Methods, Macros and Subroutines - GrandeurHammers/Overwatch-Script-To-Workshop GitHub Wiki

(Oh my!)

Methods and macros can be defined at the rule level or inside classes.

Both methods and macros can take parameters and return a value. Methods can have a block, macros cannot. Macros do not generate any workshop actions, so unlike methods they can be used in conditions.

See defining parameters for more information about defining parameters.

Methods

define name()
{
    return expr;
}

// With parameters
define name(define param, TypeName typeParam)
{
    return expr;
}

// With return type
TypeName name()
{
    return expr;
}

// With accessor (class/struct only)
public define name()
{
    return expr;
}

// Recursive
recursive define name()
{
    return expr;
}

// Void
void name()
{
}

If there are multiple return statements in a method, the return result will internally be stored as a variable.

If there is just one return statements in a method, the method will directly return the expression. If the returned expression has potentially high server load usage, depending on how the method is used it may be a good idea to store the expression in a variable before returning.

define returnedValue = // ...high server-load expression
return definedValue;

Macros

Macros do not create any actions. This allows macros to be used in conditions and reevaluation. Macros cannot be recursive.

define name(): expr;

// With parameters
define name(define param, TypeName typeParam): expr;

// Variable
define name: expr;

define Normal(define start, define end): RayCastHitNormal(start, end, null, null, true);

Parameters

Parameters can have workshop enum types (HudTextRev, Effect, etc.). Parameters with these types cannot be set to, but they can be used in method, macros, or constructors that use them.

By default, non-constant-type parameters have a variable assigned to them. Adding the ref attribute will make calling the parameter directly use the provided expression. The ref attribute cannot be used in subroutines.

void MakeHelpText(Icon icon, ref define text)
{
    CreateHudText(
        VisibleTo: AllPlayers(),
        Header   : IconString(icon),
        Text     : text,
        TextColor: Color.SkyBlue
    );
}

Recursion

Methods with the recursive attribute can be called more than once in a stack.

Recursive subroutine

Subroutines do not require the recursive attribute in order to call itself, but variable stacks will not be handled, potentially causing problems with parameters and variables defined in the subroutine. Add the recursive attribute to your subroutine in order to handle the variable stacks.

Inline recursive

'inline-recursive' are recursive functions that are not stored in subroutines. The function continuation is handled directly in the action-set. This assigns an additional variable to store data used to continue execution at the correct spot in the action-set. If you are worried about element count, consider making the function a subroutine.

Variable stack

Recursive functions store the parameter values as a stack, so it isn't a good idea to have recursive function's parameters in the extended collection. This additionally applies to variables defined inside the recursive function.

Recursive virtual

Virtual, recursive functions assigns an additional variable in order to store the object stack data. This applies to both inline-recursive and subroutine-recursive.

Recursion Example

// This will output the following when a player presses interact:
// forward 0
// forward 1
// forward 2
// forward 3
// forward 4
// forward 5
// forward 6
// forward 7
// forward 8
// forward 9
// forward 10
// back 10
// back 9
// back 8
// back 7
// back 6
// back 5
// back 4
// back 3
// back 2
// back 1
// back 0

rule: "Recursion!"
Event.OngoingPlayer
if (IsButtonHeld(EventPlayer(), Button.Interact))
{
    CountUpThenDown(0);
}

recursive void CountUpThenDown(define num)
{
    SmallMessage(AllPlayers(), <"forward <0>", num>);
    MinWait();

    if (num < 10)
    {
        CountUpThenDown(num + 1);
    }

    SmallMessage(AllPlayers(), <"back <0>", num>);
    MinWait();
}

Subroutines

Typically, functions are inserted into the action-set of the rule that called it. Subroutines only have one instance, meaning no matter how many times the subroutine is called it will only be written into the output once.

Subroutines in OSTW supports parameters and returning values.

Pros:

  • Only one instance of the function will exist, meaning less elements used in most cases.
  • Recursive subroutines do not need a continue-stack, resulting in one less variable used in the output.

Cons:

  • The ref attribute does not work with parameters.
  • Constant types such as Effect, EffectRev, HudTextRev, or lambdas do not work with parameters.
  • Potential conflicts if the subroutine is called from multiple places at the same time.
    This won't be an issue if you don't have any waits in your subroutine.

To make a subroutine, simply add a string to the end of the function. The string will be the name of the subroutine's rule.

void Subroutine() "My subroutine!"
{
}

The parameters and variables defined in subroutines will be global by default. To change it to be player variables, add the playervar keyword before the subroutine rule name.

void Subroutine() playervar "My Subroutine!"
{
}

Subroutines can be called asynchronously.

async MySubroutine(); // If the subroutine is already executing in the current global or player context, it will be restarted.
async! MySubroutine(); // Adding ! will do nothing if it is already executing.
⚠️ **GitHub.com Fallback** ⚠️