Inline blocks

In mid-July 2023, the Master Chief Collection was updated to backport some Halo 4 scripting features to Halo: Reach. One of these is the begin action. This is a low-level optimization that allows triggers to be compiled slightly more efficiently.

trigger general
   action for_each player
      temporary number is_survivor false
      temporary number is_zombie   false

      action begin
         condition if current_player.is_zombie == 1
         action set is_zombie = true
      end
      action begin
         condition if current_player.is_zombie == 0
         action set is_survivor = true
      end
   end
end

ReachVariantTool uses the term inlined triggers for this feature, in reference to how it works under the hood.

Ordinarily, blocks of code are compiled into "trigger" data structures in the Megalo data format, and an "action" is compiled into the script code to "call" these triggers and execute their contents. (In fact, ReachVariantTool implements user-defined functions by abusing this system and compiling a trigger that gets called from multiple places.) However, there's a limit on how many triggers a gametype can contain.

What this new feature does is take some of the data that triggers normally contain (specifically, the data that says, "this part of the code belongs to me; it is inside me"), and it writes that data directly into the action itself. This means that the block of code doesn't become a "real" trigger that contributes to a gametype's overall trigger limit; the block of code is inlined directly into the very same action that executes it.

In order to inline a block in ReachVariantTool, prefix it with an inline specifier:

inline: do
   -- ...
end

You can only inline do, if, altif, and alt blocks, and you cannot inline a block that is an event handler. This is because for blocks and event handler blocks require extra information that's only stored in real triggers, not inlined ones.

Functions cannot be marked as inline at this time. It would theoretically be possible to compile function calls as inline triggers, without creating a full trigger for the function's body, provided the function doesn't need any functionality that requires full trigger behavior (i.e. the function doesn't have a for-loop as its entire body); however, this is not implemented.