• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] how do I check when a struct instance is empty?

Status
Not open for further replies.
Level 14
Joined
Apr 20, 2009
Messages
1,543
I haven't been working with vJass for a while and I may have forgotten a thing or two...

Currently I'm trying to get my struct instances to work with a unit indexer.
I've done the following:

JASS:
struct myStruct
    unit u
    player owningPlayer
    integer unitType
    real posX
    real posY
    real face

    static integer array structIndex

    static method create takes unit v returns thistype
        local thistype this = thistype.allocate()
        set structIndex[GetUnitId(v)] = this
        set .u = v
        set .unitType = GetUnitTypeId(v)
        set .posX = GetUnitX(v)
        set .posY = GetUnitY(v)
        set .face = GetUnitFacing(v)
        set .owningPlayer = GetOwningPlayer(v)
        return this
    endmethod

    static method operator [] takes unit v returns thistype
        return structIndex[GetUnitId(v)]
    endmethod

Now what I am trying to do is the following:
itterate through all struct instances (or at least return the instance with the right unit id) to find out if the instance contains the same unit id for a triggering unit.

I'm not sure if I'm doing this correctly but this is what I've got so far:
JASS:
private function catchAddedUnitsActions takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local integer creepTypeIndex = checkUnitType(u)
        local respawnUnit thisUnit = respawnUnit[u]
        call BJDebugMsg(I2S(thisUnit))
        if thisUnit == 0 then
            if creepTypeIndex != 0 then
                set thisUnit = respawnUnit.create(u, creepTypeIndex)
            endif
        endif
        return FALSE
endfunction

I want to make sure that when there is no struct instance with the same unit id, it will create a new struct instance for me.

Is this the right way to go about it? By checking if the returned struct instance is 0?

Because for some reason my respawn system will only respawn the unit once and doesn't work after that.
The function catchAddedUnitsActions will run whenever a new unit gets added to the map so... I figured I'm doing it wrong.
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
Show the respawn trigger. At the moment it should be fine the way you're doing it.

Should I just paste all the code?

EDIT:

JASS:
library creepRespawn initializer init requires CreepConfig, UnitIndexer, TimerUtilsEx
    
    struct respawnUnit
        unit u
        player owningPlayer
        integer index
        integer unitType
        real posX
        real posY
        real face
        timer respawnTimer
        timer deathTimer
        static integer array structIndex
        
        method destroy takes nothing returns nothing
            set .u = null
            set .owningPlayer = null
            set .respawnTimer = null
            set .deathTimer = null
            call .deallocate()
        endmethod

        private static method actualRespawn takes nothing returns nothing
            local timer t = GetExpiredTimer()
            local thistype this = GetTimerData(t)
            call CreateUnit(.owningPlayer, .unitType, .posX, .posY, .face)
            call ReleaseTimer(.respawnTimer)
            call .destroy()
        endmethod
        
        private static method kill takes nothing returns nothing
            local timer t = GetExpiredTimer()
            local thistype this = GetTimerData(t)
            if udg_CreepRespawnCurrentPosition[.index] then
                set .posX = GetUnitX(.u)
                set .posY = GetUnitY(.u)
            endif
            call RemoveUnit(.u)
            call TimerStart(.respawnTimer, udg_CreepRespawnTime[.index], false, function thistype.actualRespawn)
            call SetTimerData(.respawnTimer, this)
            call ReleaseTimer(.deathTimer)
        endmethod
        
        method respawn takes nothing returns nothing
            call TimerStart(.deathTimer, udg_CreepRemovalTime[.index], false, function thistype.kill)
            call SetTimerData(.deathTimer, this)
        endmethod

        static method create takes unit v, integer creepTypeIndex returns thistype
            local thistype this = thistype.allocate()
            set structIndex[GetUnitId(v)] = this
            set .u = v
            set .unitType = GetUnitTypeId(v)
            set .index = creepTypeIndex
            set .posX = GetUnitX(v)
            set .posY = GetUnitY(v)
            set .face = GetUnitFacing(v)
            set .respawnTimer = NewTimer()
            set .deathTimer = NewTimer()
            set .owningPlayer = GetOwningPlayer(v)
            return this
        endmethod
        
        static method operator [] takes unit v returns thistype
            return structIndex[GetUnitId(v)]
        endmethod
    endstruct
    
    //check if the owning player matches with the Creep Respawn Configuration
    private function checkOwningPlayer takes unit u, integer index returns boolean
        if GetOwningPlayer(u) == udg_CreepOwner[index] then
            return TRUE
        endif
        return FALSE
    endfunction
    
    //check if the unit type is inside the Creep Respawn Configuration and returns the index
    private function checkUnitType takes unit u returns integer
        local integer i = 1
        loop
            exitwhen i > udg_lastIndex
            if GetUnitTypeId(u) == udg_CreepType[i] then
                if checkOwningPlayer(u, i) then
                    return i
                endif
            endif
            set i = i + 1
        endloop
        return 0
    endfunction
    
    //respawns the unit
    private function respawnTheUnit takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local integer creepTypeIndex = checkUnitType(u)
        local respawnUnit thisUnit = respawnUnit[u]
        call thisUnit.respawn()
        return FALSE
    endfunction
    
    //catches all dying units
    private function catchKilledUnits takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i
        set i = 0
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_DEATH, null)
            set i = i + 1
            exitwhen i == bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerAddCondition(t, Condition(function respawnTheUnit))
    endfunction
    
    //catches all preplaced units on the map, checks if they are in the Creep Respawn Configuration and creates a struct instance for each one
    private function catchMapUnits takes nothing returns nothing
        local group g = CreateGroup()
        local unit u
        local integer creepTypeIndex
        local respawnUnit newUnit
        call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, null)
        loop
            set u = FirstOfGroup(g)
            exitwhen u == null
            set creepTypeIndex = checkUnitType(u)
            if creepTypeIndex != 0 then
                set newUnit = respawnUnit.create(u, creepTypeIndex)
            endif
            call GroupRemoveUnit(g, u)
        endloop
        call DestroyGroup(g)
        set g = null
    endfunction
    
    //trigger actions for catchAddedUnits
    private function catchAddedUnitsActions takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local integer creepTypeIndex = checkUnitType(u)
        local respawnUnit thisUnit = respawnUnit[u]
        call BJDebugMsg(I2S(thisUnit))
        if thisUnit == 0 then
            if creepTypeIndex != 0 then
                set thisUnit = respawnUnit.create(u, creepTypeIndex)
            endif
        endif
        return FALSE
    endfunction
    
    //catches all units created throughout the game, checks if they are in the Creep Respawn Configuration and creates a struct instance for each one
    private function catchAddedUnits takes nothing returns nothing
        local trigger t = CreateTrigger()
        local region r = CreateRegion()
        call RegionAddRect(r, bj_mapInitialPlayableArea)
        call TriggerRegisterEnterRegion(t, r, null)
        call TriggerAddCondition(t, Condition(function catchAddedUnitsActions))
        set t = null
        set r = null
    endfunction
    
    private function init takes nothing returns nothing
        call catchMapUnits()
        call catchAddedUnits()
        call catchKilledUnits()
    endfunction
    
endlibrary
  • Creep Respawn Configuration
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Visibility - Disable fog of war
      • Visibility - Disable black mask
      • -------- Don't touch the custom script, it makes sure that these global variables can be used properly by the system --------
      • Custom script: //! runtextmacro SPAWNVARS()
      • Custom script: endfunction
      • Custom script: library CreepConfig initializer init
      • Custom script: private function init takes nothing returns nothing
      • Custom script: //! textmacro SPAWNVARS
      • -------- Add, change, do anything with these variables as you like --------
      • Set CreepType[1] = Chicken
      • Set CreepRespawnTime[1] = 3.00
      • Set CreepRemovalTime[1] = 0.30
      • Set CreepOwner[1] = Neutral Hostile
      • Set CreepRespawnCurrentPosition[1] = False
      • Set CreepType[2] = Frog
      • Set CreepRespawnTime[2] = 2.00
      • Set CreepRemovalTime[2] = 0.40
      • Set CreepOwner[2] = Neutral Hostile
      • Set CreepRespawnCurrentPosition[2] = True
      • Set CreepType[3] = Rabbit
      • Set CreepRespawnTime[3] = 4.00
      • Set CreepRemovalTime[3] = 0.20
      • Set CreepOwner[3] = Neutral Hostile
      • Set CreepRespawnCurrentPosition[3] = False
      • Set CreepType[4] = Raccoon
      • Set CreepRespawnTime[4] = 2.00
      • Set CreepRemovalTime[4] = 0.30
      • Set CreepOwner[4] = Neutral Hostile
      • Set CreepRespawnCurrentPosition[4] = True
      • Set CreepType[5] = Stag
      • Set CreepRespawnTime[5] = 7.00
      • Set CreepRemovalTime[5] = 0.60
      • Set CreepOwner[5] = Neutral Hostile
      • Set CreepRespawnCurrentPosition[5] = False
      • Set lastIndex = 5
      • Custom script: //! endtextmacro
      • Custom script: //! runtextmacro SPAWNVARS()
      • Custom script: endfunction
      • Custom script: endlibrary
      • Custom script: function doesNothing takes nothing returns nothing
Also, is it suitable material for submission? Or is it too basic :p?
If so, I would like to call it: EasySpawn
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
private function catchAddedUnits takes nothing returns nothing could also use UnitIndexer and run onIndexEvent. (Depends which UnitIndexer you are using I guess). Nestharus's Indexer has a module called UnitIndexStruct


local integer creepTypeIndex is not even used.
JASS:
    private function respawnTheUnit takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local integer creepTypeIndex = checkUnitType(u)
        local respawnUnit thisUnit = respawnUnit[u]
        call thisUnit.respawn()
        return FALSE
    endfunction

You could save a real RespawnTime instead of a timer RespawnTimer.
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
private function catchAddedUnits takes nothing returns nothing could also use UnitIndexer and run onIndexEvent. (Depends which UnitIndexer you are using I guess). Nestharus's Indexer has a module called UnitIndexStruct


local integer creepTypeIndex is not even used.
JASS:
    private function respawnTheUnit takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local integer creepTypeIndex = checkUnitType(u)
        local respawnUnit thisUnit = respawnUnit[u]
        call thisUnit.respawn()
        return FALSE
    endfunction

You could save a real RespawnTime instead of a timer RespawnTimer.

Great tips again! :D

Although, why use a loop with reals to simulate a timer when you can create a timer through timerutils?

Thank you for the tips though, I would rep you again if I had the chance.
Yeah I am using UnitIndexer, and I forgot about onIndexEvent.

I'm using Nestharus's UnitIndexer v4.0.2.8 it uses:
JASS:
function RegisterUnitIndexEvent takes boolexpr codeToRegister, Event unitIndexEvent returns nothing
function TriggerRegisterUnitIndexEvent takes trigger triggerToRegister, Event unitIndexEvent returns nothing
and yeah that second one was a stupid mistake. My bad..

Nonetheless this doesn't solve the problem I described in my first message. :(

The thing is, the event does register and work. I'm seeing the debug messages correctly.
But somehow I think I missed something with the struct instances. That's my real problem currently.
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
What's the difference and when do I use FALSE then?
It doesn't seem to do anything, is it a coding standard of sorts?
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
It's a constant boolean variable, false on the other hand, is a boolean value.

Here's its declaration in common.j
JASS:
//===================================================
// Game Constants
//===================================================

// pfff
constant boolean FALSE = false
constant boolean TRUE = true

I don't think you really should use it anywhere.
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
Thanks, I'll keep that in mind.

EDIT: I think my current problem is that I need to create a list of sorts.
My real question is, how do I accomplish this with structs?

JASS:
local unit u1 = CreateUnit(Player(0), 'hfoo', 0, 0, 0)
local unit u2 = CreateUnit(Player(0), 'hfoo', 0, 0 ,0)
local unit u3 = CreateUnit(Player(0), 'hfoo', 0, 0 ,0)
local unit u4 = CreateUnit(Player(0), 'hfoo', 0, 0 ,0)
integer unitId1 = GetUnitId(u1)
integer unitId2 = GetUnitId(u2)
integer unitId3 = GetUnitId(u3)
integer unitId4 = GetUnitId(u4)

integer array a
integer aCount
integer i
integer i2
 
//create a new instance that sets unitId inside the instance of the struct, aka create method with counting index
set aCount = aCount + 1
set a[aCount] = unitId1 //struct instance with integer unitId
set aCount = aCount + 1
set a[aCount] = unitId2
set aCount = aCount + 1
set a[aCount] = unitId3
set aCount = aCount + 1
set a[aCount] = unitId4

loop
    exitwhen i > aCount
    set i = i + 1
    if GetUnitId(u) == a[i] then
        set a[i] = 0 //destroy the correct instance
        set i2 = i //set current
        loop
            exitwhen i2 > aCount
            set a[i2+1] = a[i2] //set next = current
            set i2 = i2 + 1 //set current = current + 1
        endloop
    endif
endloop
set aCount = aCount - 1 //decrease struct index since all are now shifted
 
Last edited:
Status
Not open for further replies.
Top