Tips text alignment is done via ad-hoc padding, if languages are added it would be better to rework.
Temp variables (GTemp, PTemp, GTempArray*...) are used for short lived, disposable variables within their context (player or global).
We currently do not check for Sombra hack status effect when executing certain faux abilities as it's too troublesome given we need to detect only the initial phase of it (silenced - when it disables abilities) and it's not straightforward to do. See 4568175704f6bb8ed586de94cc738ab0b38ea247.
Round boundaries
Avoid default Is Game In Progress as it turns true only several seconds after round actually starts, prefer Global.IsRoundActive.
Avoid default Is Between Rounds as it turns false far too early in the start of the round, sometimes even when player is still indicated to have previous round hero.
Playerbase data and moving players
Be acutely aware of the fact that dummy bots count towards playerbase data, so whichever rules use Number Of Players,All Players, etc. have to filter out bots or ensure it's not an issue.
When using Move Player to Team the playerbase data does not update for the remainder of the rule execution unless a long wait (e.g. a second) is executed and even then, the timing of when the data gets updated is not deterministic.
It seems to be preferable to put player in the spectator first and then immediately move to the team as direct Move Player to Team is riddled with buggy side effects (link, link, link, link), I also encountered players being stuck in queue when moved.
Moving players to spectators is done via providing empty array as a team argument to Move Player to Team. This is an undocumented hack.
General findings
The general Ultimate Generation setting multiplies with specific ones (combat/passive). So when you set passive generation to say 200% and general to 200%, your passive will result in 400%.
Match time is not editable in Elimination, using Set Match Time or Pause / Unpause simply resets it.
There can only be one instance of a unique global rule running at a time (same rule wont execute if conditions went false->true while it is still running), so there typically is no need to worry about reentrancy.
For event rules it also somewhat applies but uniqueness depends also on event subject and type.
All HUDs of a dead player is replaced with HUD of teammate that dead player is spectating through. However HUD shown to local player will NOT be visible to dead team spectators.
Ultimates wont start generating for a few seconds in the start of match (when Is Game In Progress is still false). This is an issue for characters that don't start with ult ready.
If player is saved to a variable (or array element), on team switch that variable will still refer to the same valid player (however all player sub-variables will reset). On match leave or if moved to spectators and back into game the variable will no longer refer to same player - it'll refer to some residual dead identifier with all sub-variables reset.
No player object or any player variables are preserved during the Player Left Match event.
On player death, all effects and texts created inside rules in the context of that player are automatically removed, so there is no need to manually clean those on their leave.
Keyword continue is somewhat broken, if you put it under an if block it will not skip to the start of the loop but to the start of the if block essentially turning it into an endless loop crashing the game. Use Skip If with Continue if needed instead (e.g. Skip If(condition, 1); Continue;).
Small Message can be quite unreliable as its mechanics are vague, especially with string evaluation (it will only eval at the end of rule and not always with freshest values). Be careful using dynamic strings with it. For debugging prefer Log To Inspector.
Do not store arrays inside arrays anywhere at all, support for multidimensional arrays is very limited and a source of bugs and inconsistencies.
Implementation details
Temp
variables (GTemp, PTemp, GTempArray*...) are used for short lived, disposable variables within their context (player or global).Round boundaries
Is Game In Progress
as it turns true only several seconds after round actually starts, preferGlobal.IsRoundActive
.Is Between Rounds
as it turns false far too early in the start of the round, sometimes even when player is still indicated to have previous round hero.Playerbase data and moving players
Number Of Players
,All Players
, etc. have to filter out bots or ensure it's not an issue.Move Player to Team
the playerbase data does not update for the remainder of the rule execution unless a long wait (e.g. a second) is executed and even then, the timing of when the data gets updated is not deterministic.Move Player to Team
is riddled with buggy side effects (link, link, link, link), I also encountered players being stuck in queue when moved.Move Player to Team
. This is an undocumented hack.General findings
Set Match Time
or Pause / Unpause simply resets it.local player
will NOT be visible to dead team spectators.Is Game In Progress
is still false). This is an issue for characters that don't start with ult ready.Player Left Match
event.continue
is somewhat broken, if you put it under anif
block it will not skip to the start of the loop but to the start of theif
block essentially turning it into an endless loop crashing the game. UseSkip If
withContinue
if needed instead (e.g.Skip If(condition, 1); Continue;
).Small Message
can be quite unreliable as its mechanics are vague, especially with string evaluation (it will only eval at the end of rule and not always with freshest values). Be careful using dynamic strings with it. For debugging preferLog To Inspector
.