adapap / OWScript

Python-like scripting language which transpiles into Overwatch Workshop script rulesets.
MIT License
37 stars 2 forks source link

Player of a pvar doesn't always update on subsequent uses of the variable with a different player #19

Closed netux closed 5 years ago

netux commented 5 years ago

Problem

Declaring a pvar who's "target" is, for example, Event Player sets the "target" of the variable to that indefinitely, even if we try to use pvar variable@new_target

Examples

Rule "Link two players through their pvar other_player"
    Event
        On Each Player
        All
        All
    Conditions
        Is Button Held(Event Player, Primary Fire)
    Actions
        pvar other_player = Player Closest To Reticle(Event Player, Team(All))
        if other_player != Null:
            other_player@pvar other_player = Event Player

On that script, we set the pvar of Event Player to the closest player to the reticle of that player, then we try setting the same pvar on the other player (now stored in other_player) to the Event Player, effectively "linking" them.

Currently, OWScript traspiles that last line to:

Set Player Variable At Index(Event Player, A, 0, Event Player);

instead of

Set Player Variable At Index(Value In Array(Player Variable(Event Player, A), 0), A, 0, Event Player);

Another, real world, example would be the following

Rule "Set player lives to 3"
    Event
        On Each Player
        All
        All

    Actions
        pvar lives_left = 3

Rule "When player dies, remove a life"
    Event
        Player Died
        All
        All

    Actions
        pvar lives_left -= 1

Rule "When only one player is left alive, declare them as winners"
    Event
        On Global

    Conditions
        Is Game In Progress == True
        Number of Players(All Teams) > 1
        Count Of(Filter(Everyone, pvar lives_left@Cur Elem > 0)) == 1

    Actions
        Declare Player Victory
            First Of(Filter(Everyone, pvar lives_left@Cur Elem > 0))

The first two rules transpile correctly, but the last rule ...

   // ...
   Conditions {
      Compare(Is Game In Progress, ==, True) == True;
      Compare(Number Of Players(All Teams), >, 1) == True;
      Compare(Count Of(Filtered Array(All Players(Team(All)), Compare(Value In Array(Player Variable(Event Player, A), 0), >, 0))), ==, 1) == True;
   }
   Actions {
      Declare Player Victory(First Of(Filtered Array(All Players(Team(All)), Compare(Value In Array(Player Variable(Event Player, A), 0), >, 0))));
   }
   // ...

... uses Event Player instead of Current Array Element

Side note

This script causes an infinite loop:

Rule "Blow up Python's stack"
    Event
        On Each Player
        All
        All
    Actions
        pvar lol@pvar lol = True
adapap commented 5 years ago

This is actually a subset of a larger issue. Once a type is defined for a variable, there is no way to change it as the variable is found in the scope table without checking if the type has changed. This way, you cannot recast a const type into a pvar type. I guess my question would be should we allow this behavior if changing targets for player variables?

netux commented 5 years ago

I haven't looked much into the codebase. Can't there be an exception for constants? as in, constants being a completely different type with separated code from gvars and pvars.

netux commented 5 years ago

🎉 Almost! you_tried

The pvar target now updates correctly, but only when you use the @. If, for example, you have

pvar test = 1
pvar test@Cur Elem = 2
pvar test = 3

the third line actually works like pvar hello@Cur Elem = 3, not pvar hello@Event Player = 3

netux commented 5 years ago

Just tested again and it seems to be working fine 👍