• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!

[vJASS] Building a Struct

Status
Not open for further replies.
Level 13
Joined
Jul 26, 2008
Messages
1,009
So I'm trying to build a struct to represent a unit classification in my map. I want "prey" units to be reviveable and respawn at their origin point (x, y).

I figured I could make a trigger on the structs creation that would detect if the unit designated to the struct dies. If they do, it starts a countdown and at the end of that countdown, a new instance of that unit is created.

However, I'm getting the message that I can't use onDeath or reviveAnimal because they're Undefined functions.

I know it's possible to attach the struct to the timer via hashtable and then reference the values that way. But I was hoping I could have a little more versatility with structs and use them in a less rigid and roundabout way.

Is there a simple way to make this work?

Code:
struct Prey
    public unit animal
    public integer animalType
    public integer rareType
    public player originPlayer
    public real originX
    public real originY
    private rect nativeRect
    private timer deathTimer    = CreateTimer()
    private trigger deathTrigger


    private method reviveAnimal takes nothing returns nothing
        set .animal = CreateUnit(.originPlayer, .animalType, .originX, .originY, GetRandomReal(0, 360))
    endmethod

    method onDeath takes nothing returns nothing
        call TimerStart(.deathTimer, 120, false, function reviveAnimal)
        call DestroyTrigger(.deathTrigger)
    endmethod

    private method createDeathTrigger takes nothing returns nothing
        set .deathTrigger = CreateTrigger()
            call TriggerRegisterUnitEvent( .deathTrigger, .animal, EVENT_UNIT_DEATH )
        call TriggerAddAction( .deathTrigger, function onDeath)
    endmethod

    static method create takes unit animal returns Prey
     local thistype prey = thistype.allocate()
        set prey.animal = animal
        set prey.animalType = GetUnitTypeId(animal)
        set prey.originX = GetUnitX(animal)
        set prey.originY = GetUnitY(animal)
        set prey.nativeRect = gg_rct_HeroSelectionArea //Create function to determine Starting Rect
        set prey.rareType = 'A000' //Create function to determine Rare unit type based on Rect (or Animal Type)
        call prey.createDeathTrigger()
     return prey
    endmethod

endstruct

Any additional feedback outside of this is welcome, jsut be sure to preface it as separate.
 
Last edited:
JASS:
struct Prey
    public unit animal
    public integer animalType
    public integer rareType
    public player originPlayer
    public real originX
    public real originY
    private rect nativeRect
    private timer deathTimer    = CreateTimer()
    private trigger deathTrigger

    private method reviveAnimal takes nothing returns nothing
        set .animal = CreateUnit(.originPlayer, .animalType, .originX, .originY, GetRandomReal(0, 360))
    endmethod

    method onDeath takes nothing returns nothing
        call TimerStart(.deathTimer, 120, false, function reviveAnimal)
        call DestroyTrigger(.deathTrigger)
    endmethod

    private method createDeathTrigger takes nothing returns nothing
        set .deathTrigger = CreateTrigger()
        call TriggerRegisterUnitEvent( .deathTrigger, .animal, EVENT_UNIT_DEATH )
        call TriggerAddAction( .deathTrigger, function onDeath)
    endmethod

    static method create takes unit animal returns Prey
        local thistype prey = thistype.allocate()
        set prey.animal = animal
        set prey.animalType = GetUnitTypeId(animal)
        set prey.originX = GetUnitX(animal)
        set prey.originY = GetUnitY(animal)
        set prey.nativeRect = gg_rct_HeroSelectionArea //Create function to determine Starting Rect
        set prey.rareType = 'A000' //Create function to determine Rare unit type based on Rect (or Animal Type)
        call prey.createDeathTrigger()
        return prey
    endmethod

endstruct

In Prey.reviveAnimal, shouldn't the method be static? As far as I recall, in order to pass functions as parameters, they have to take no arguments. After the method is made static, another problem arises with this such that one cannot properly obtain the value of this. This is where Timer data association comes into play, and you can do it in at least two ways: associate the data of the timer to its' parent instance of the struct: set .deathTimer.data = this, or attach it to the unit's index: set .deathTimer.data = GetUnitUserData(.animal).

If doing the latter, you'll then need a Unit Indexer in order for the latter to work.

In Prev.onDeath, the same predicament falls on it just as it does on Prey.reviveAnimal. Just change it to a static method and find a way to get the instance via the handle given.

In Prey.createDeathTrigger, the result is that the compiler assumes that a function named onDeath exists, which only does inside the struct. Given that, the compiler would fail to discern that as the intended function to be called, and throws an error.
To fix that, try doing this: Prey.onDeath or thistype.onDeath

Just in case you find ordinary methods and static methods tricky, ordinary methods are invoked by instances of the class, and have this as a default keyword, whereas static methods are invoked by the class itself.
 
Level 13
Joined
Jul 26, 2008
Messages
1,009
I do have a UnitIndexer but in this case I'm expecting the Unit to be fully decayed by the time the Timer expires.

Unfortunately this
Code:
set .deathTimer.data = this
kicks back the error message: "deathTimer is not of a type that allows . syntax"

I also run into the issue where onDeath cannot access the information that's created when the struct is created.

I do understand that static and normal methods are different in that static methods are calling class data, and normal methods can call on the data instances of the class.

Since I want to access the data from the instances of the class, I want to use normal methods. But I'm forced to use static method, which feels like it defeats the purpose and I'm forced to create a workaround.
 
Status
Not open for further replies.
Top