Lambdas and function types - ItsDeltin/Overwatch-Script-To-Workshop GitHub Wiki
Lambdas and function types
Function Types
Methods and lambdas in OSTW can be stored inside variables and passed as parameters using function types. Function types can be declared like so:
(parameter_list) => return_type
If your function type has only one parameter, the parentheses are optional.
The types of the function parameters are defined on the left side of the =>, and the return type is defined on the right. To assign a function type in code to a method, declare the name of the method group. If there are multiple methods with the same name, the method chosen is matched with the parameters and return type of the function type.
void A() {} // 1
void A(String text) {} // 2
String => void func = A; // 2 is chosen
Function types can be encased in parentheses for an array of functions.
(() => void)[] actionList;
Examples
// In variable declaration. No parameters and no return value.
globalvar () => void functionVariable;
rule: 'Test'
{
// The workshop method 'DestroyAllDummyBots' assigned to functionVariable.
functionVariable = DestroyAllDummyBots;
// Destroys all dummy bots!
functionVariable();
}
The example below will disable a random button for the event player.
// An array of the workshop actions that enables or disables buttons.
((Player, Boolean) => void)[] buttonToggles = [
SetPrimaryFireEnabled,
SetSecondaryFireEnabled,
SetJumpEnabled,
SetMeleeEnabled,
SetCrouchEnabled,
SetReloadEnabled,
SetAbility1Enabled,
SetAbility2Enabled,
SetUltimateAbilityEnabled
];
// Disable a random button for the event player
buttonToggles.Random().Invoke(EventPlayer(), false);
Undo/redo system I used in a new pathmap editor I was working on.
Boolean CanUndo: historyPage > 0;
Boolean CanRedo: historyPage < historyItems.Length;
globalvar Number historyPage; // The current point in history.
globalvar HistoryCatalog[] historyItems = []; // The undo list.
// Executes an action that can be undone and redone.
void Document(in HistoryCatalog catalogItem)
{
// If we went back in time and something is documented, the future states are now stale so we can remove them.
while (historyItems.Length > historyPage)
historyItems.ModRemoveByIndex(historyPage);
// Execute the action.
catalogItem.Set();
// Add the action to the history of actions.
historyItems += [catalogItem];
historyPage++;
}
// Represents a point in history
struct HistoryCatalog
{
public () => void Set; // The action required to enter this state.
public () => void Revert; // The logical inverse of 'Set' to backtrack out of this state.
}
void Undo()
{
historyPage--;
historyItems[historyPage].Revert();
}
void Redo()
{
historyItems[historyPage].Set();
historyPage++;
}
Constant function types
Constant function types are function types that cannot be changed after they have been assigned. They are created by denoting a function type with the const
keyword like so:
const () => void myConstantFunction;
Constant function types can use constant workshop types such as EffectRev
, Location
, HealthType
, etc as parameters. Constant function types are cheaper to call than normal function types. However, constant function types cannot be reassigned once they have been changed.
Example
The Create HUD Text
and Create Progress Bar HUD Text
workshop actions both take a parameter called "Location". Location values are normally constant and cannot be supplied with a variable. However, the code below allows us to store the location as the type StoreableVariable
which can be converted to the constant Location
workshop type.
enum StoreableLocation
{
Left,
Right,
Top
}
void CastLocation(in StoreableLocation variable, const Location => void cast)
{
switch (variable)
{
case StoreableLocation.Left: cast(Location.Left); break;
case StoreableLocation.Right: cast(Location.Right); break;
case StoreableLocation.Top: cast(Location.Top); break;
}
}
...
// Randomly choose between the left and right hud location.
StoreableLocation location = [StoreableLocation.Left, StoreableLocation.Right].Random();
// Create the hud text
CastLocation(location, constLocation => {
// Create the HUD text.
CreateHudText(Text: 'Hello!', Location: constLocation);
// Create the progress bar.
CreateProgressBarHudText(Text: 'Progress: ', Value: 0, Location: constLocation);
});
Lambdas
You can use lambdas to create anonymous functions. You can use lambdas in any code that requires a function type. Lambda expressions can be created like so:
(parameter_list) => expression or statement
Lambda parameters
The parameters of the lambda are defined inside the parentheses. If your lambda requires zero parameters, use empty parentheses.
WaitAsync(duration: 3, action: () =>
{
SmallMessage(AllPlayers(), "3 seconds have passed!");
});
If your lambda has only one parameter, parentheses are optional.
String => void message = text => BigMessage(AllPlayers(), text);
If your lambda has multiple parameters, seperate them with commas.
(Number, Number) => Number op = (x, y) => x % y;
In cases where the parameter types of the lambda cannot be inferred, you can provide their types. In this case, even if there is just one parameter you must use parentheses.
(String text) => BigMessage(AllPlayers(), text);
Variable capturing
If a variable is accessed inside a lambda, the value of the variable is saved. The values of these saved variables cannot be changed after the lambda expression declaration. This is because the lifetime of a variable ends immediately once it goes out of scope.
Number x = 5;
() => void action = () => {
// x cannot be changed here.
// y will equal 5, even though x's value is changed before the lambda is executed.
Number y = x;
};
x = 6;
action();
Examples
String => void anonymousMethod = text => {
SmallMessage(AllPlayers(), text);
};
anonymousMethod('Hello everyone!');
(() => void)[] actionList = [
() => {
SmallMessage(AllPlayers(), 'Hi!');
},
DeclareMatchDraw,
PauseMatchTime
];
foreach (() => void action in actionList)
action();