• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece!🔗 Click here to enter!

Neutral Units Respawn

Status
Not open for further replies.
Level 13
Joined
Sep 14, 2012
Messages
437
  • NeutralRespawn
    • Events
      • Unit - A unit Dies
    • Conditions
    • Actions
      • If(All conditions are True)then do (Then Actions)else do(Else Actions)
        • If - Conditions
          • (Unit type of (Triggering unit)) Equal to Satyr(1)
        • Then - Actions
          • Wait 15.00 seconds
          • Unit - Create 1 Satyr(1) for Neutral Hostile at (Center of Satyr1 <gen>)facing 360 degrees
        • Else - Actions
      • If(All conditions are True)then do (Then Actions)else do(Else Actions)
        • If - Conditions
          • (Unit type of (Triggering unit)) Equal to Satyr(2)
        • Then - Actions
          • Wait 15.00 seconds
          • Unit - Create 1 Satyr(2) for Neutral Hostile at (Center of Satyr2 <gen>)facing 360 degrees
        • Else - Actions
Here's what I'm looking for. When a neutral unit dies, it respawns at the same starting place when game started. I tryed it like this:

  • NeutralRespawn
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Owner of (Triggering unit)) Equal to Neutral Hostile
    • Actions
      • Wait 15 seconds
      • Unit - Create 1 (Unit type of (Triggering unit) for Neutral Hostile at (Position of (Triggering unit)) faceing 360 degrees
But the netural creep will spawn at the last place it died, and I don't want that. The first trigger will take me a lot of copys' of the unit. So far I created 15 different units(same model, same damage, same armor, same hp, everything the same) just so they spawn at the place where they started. There is a another similar concept. Instead of copying the same unit over and over, I crate 1 type and then I use variables. For example:
  • Map Initialization
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set Satyr[0]=Satyr 001 <gen>
      • Set Satyr[1]=Satyr 002 <gen>
      • Set SatyrPosition[0]=(Position of Satyr 001 <gen>)
      • Set SatyrPosition[1]=(Position of Satyr 002 <gen>)
  • NeutralRespawn
    • Events
      • Unit - A unit Dies
    • Conditions
    • Actions
      • If(All conditions are True)then do (Then Actions)else do(Else Actions)
        • If - Conditions
          • (Triggering unit) Equal to Satyr[0]
        • Then - Actions
          • Wait 15.00 seconds
          • Unit - Create 1 Satyr for Neutral Hostile at (Center of SatyrPosition[0] <gen>)facing 360 degrees
          • Set Satyr[0]=Last Created unit
        • Else - Actions
      • If(All conditions are True)then do (Then Actions)else do(Else Actions)
        • If - Conditions
          • (Triggering unit) Equal to Satyr[1]
        • Then - Actions
          • Wait 15.00 seconds
          • Unit - Create 1 Satyr for Neutral Hostile at (Center of SatyrPosition[1] <gen>)facing 360 degrees
          • Set Satyr[0]=Last Created unit
        • Else - Actions
But This will take a loot of setting up and there are chances(50% chance) that i mess up and mix up the positions or unit types.
If there is a way to make this easier than please help.
 
Last edited:
Level 7
Joined
Mar 10, 2013
Messages
366
I'm not sure what the problem with creating a new unit but, what's the current you're facing anyway?
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
Iterate through all neutral units on map initialization and store their type, position and facing inside 3 parallel arrays in the form of a list. Use a hashtable to map the unit to the index it uses in the arrays. When a neutral unit dies, lookup its index using the hashtable, remove its mapping from the hashtable (to prevent a leak) and then add the index to a respawn list as well as the respawn timeout.

The respawn list is similar to how most MUI abilities are done. It is an unordered collection of scheduled respawns that every second you iterate through and decrement the countdown by 1. When the countdown reaches 0 you create a new unit for the spawn index, remembering to map it in the hashtable, and then destroy that scheduled respawn instance. Destroying scheduled respawn instances is done by replacing the destroyed instance with the last instance, as is common in MUI abilities. New instances are added to the end of the scheduled respawn collection, again common in MUI abilites.

Wait, aka TriggerSleepAction, cannot be used for respawn systems because it does follow game time accurately.
 
Level 7
Joined
Mar 10, 2013
Messages
366
Iterate through all neutral units on map initialization and store their type, position and facing inside 3 parallel arrays in the form of a list. Use a hashtable to map the unit to the index it uses in the arrays. When a neutral unit dies, lookup its index using the hashtable, remove its mapping from the hashtable (to prevent a leak) and then add the index to a respawn list as well as the respawn timeout.

The respawn list is similar to how most MUI abilities are done. It is an unordered collection of scheduled respawns that every second you iterate through and decrement the countdown by 1. When the countdown reaches 0 you create a new unit for the spawn index, remembering to map it in the hashtable, and then destroy that scheduled respawn instance. Destroying scheduled respawn instances is done by replacing the destroyed instance with the last instance, as is common in MUI abilities. New instances are added to the end of the scheduled respawn collection, again common in MUI abilites.

Wait, aka TriggerSleepAction, cannot be used for respawn systems because it does follow game time accurately.
Is it so bad to use 3 globals arrays intead of a hashtable?

@Hotwer Because, I'm basically creating the same unit over and over, place 1 of each type, and then when unit dies, it just creates the same unit type, dus, preventing the "spawn at where the unit was killed bug"

@Dr Super Good I don't know how to use hashtable man, I never got the use of it.
Well, for you to care about it, @Dr Super Good pointed the only way you can do it dinamically. The only other way is doing statically, as you pointed out, but that will take you tremenduous amount of time, and as you pointed out, you can get it wrong.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
Is it so bad to use 3 globals arrays intead of a hashtable?
The hashtable is for the unit to index mapping, otherwise one would need to perform a linear search and need another array to hold the actual unit. Alternativly the entire system could be powered from a single hashtable but the code may be more complicated and slower.
 
Level 7
Joined
Mar 10, 2013
Messages
366
The hashtable is for the unit to index mapping, otherwise one would need to perform a linear search and need another array to hold the actual unit. Alternativly the entire system could be powered from a single hashtable but the code may be more complicated and slower.
I see. He would use the hashtable to use the unit id as the indexing for it's informations and use it to retieve it's information on the "Die Event" trigger.
 
you need Unit Indexer (use Bribe's UnitEvent) and dummy unit
feel free to ask if got questions
JASS:
    // requires Unit Indexer and dummy unit
globals
    //-------------------------------------------------------------
    //configure following 3 lines:
    constant boolean        SET_ACQUIRE_RANGE = true
    constant real               ACQUIRE_RANGE = 220.00
    constant real               RESPAWN_TIME = 30.00 //seconds
    //-------------------------------------------------------------
    
    constant integer     DUMMY = 'n000'
    //---
    unit array          g_hostileU
    integer array     g_hostileId
    real array          g_hostileX
    real array          g_hostileY
    real array          g_hostileFace
    real array          g_hostileRepawnTime
    real array          g_hostileLife
    integer              g_hostileTotal = 0
    
    group                g_hostileGroup
    timer                 spellTimer
    real array          spellDuration
    integer array     spellHostileUnitNr
endglobals
//===============================================
//-------------------------------------------------------------------------------
//----find unique number for each hostile unit ----------------------------
//-------------------------------------------------------------------------------
function Hostile_GetUnitNumber takes unit u returns integer
    local integer i = 0
    loop //find in array unit u, its number will be "i"
        exitwhen (i > g_hostileTotal) or (u == g_hostileU[i])
        set i=i+1
    endloop
    if i>g_hostileTotal then
        return -1
    endif
    return i
endfunction
//================================================
function Hostile_LoopEnum takes nothing returns nothing
    local unit d = GetEnumUnit()
    local integer id = GetUnitUserData(d)
    local integer i = spellHostileUnitNr[id]
    if spellDuration[id] == 4.00 then
        call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Orc\\Reincarnation\\ReincarnationTarget.mdl", g_hostileX[i], g_hostileY[i]))
    elseif spellDuration[id] == 3.00 then
        set g_hostileU[i] = CreateUnit(Player(12), g_hostileId[i], g_hostileX[i], g_hostileY[i], g_hostileFace[i])
        static if SET_ACQUIRE_RANGE then
            call SetUnitAcquireRange(g_hostileU[i], ACQUIRE_RANGE)
        endif
    endif
    //---
    set spellDuration[id] = spellDuration[id] - 1.00
    if spellDuration[id] <= 0.00  then // Clean up any data attached to this spell
        call GroupRemoveUnit(g_hostileGroup, d)
        call RemoveUnit(d)        
        if FirstOfGroup(g_hostileGroup) == null then
            call PauseTimer(spellTimer)
        endif
    endif
    set d=null
endfunction
//-------------------------------------------------------------------------------
function Hostile_Loop takes nothing returns nothing
    call ForGroup(g_hostileGroup, function Hostile_LoopEnum)
endfunction
//-------------------------------------------------------------------------------
function Hostile_OnDeath takes nothing returns boolean // EVENT_PLAYER_UNIT_DEATH
    local integer i = Hostile_GetUnitNumber(GetDyingUnit())
    local integer id
    if i == -1 then
        return false
    endif
    set bj_lastCreatedUnit = CreateUnit(Player(15), DUMMY, g_hostileX[i], g_hostileY[i], 0.00)
    set id = GetUnitUserData(bj_lastCreatedUnit)
    set spellHostileUnitNr[id] = i
    set spellDuration[id] = g_hostileRepawnTime[i]
    //---
    if FirstOfGroup(g_hostileGroup) == null then
        call TimerStart(spellTimer, 1.00, true, function Hostile_Loop)
    endif
    call GroupAddUnit(g_hostileGroup, bj_lastCreatedUnit)
    return false
endfunction
//===============================================
//===============================================
function Hostile_CountPreplaced takes nothing returns nothing
    //Count preplaced Hostile units
    local unit u = null
    local integer i=0
    local group ug = CreateGroup()
    call GroupEnumUnitsInRect(ug, bj_mapInitialPlayableArea, null)
    loop
        set u = FirstOfGroup(ug) 
        exitwhen u == null
        if GetOwningPlayer(u) == Player(12) and (not IsUnitType(u, UNIT_TYPE_STRUCTURE)) then
            set g_hostileU[i] = u
            set g_hostileId[i] = GetUnitTypeId(u)
            set g_hostileX[i] = GetUnitX(u)
            set g_hostileY[i] = GetUnitY(u)
            set g_hostileFace[i] = GetUnitFacing(u)
            set g_hostileRepawnTime[i] = RESPAWN_TIME // you can use point value of unit-type to diffrentiate respawn time
            static if SET_ACQUIRE_RANGE then
                call SetUnitAcquireRange(u, ACQUIRE_RANGE)
            endif
            set i=i+1
        endif
        call GroupRemoveUnit(ug, u)
    endloop
    call GroupClear(ug)
    
    set g_hostileTotal = i
    set g_hostileGroup = CreateGroup()
    set spellTimer = CreateTimer()    
    call DestroyGroup(ug)
    set ug=null
    set u=null
endfunction
//===================================================================
function InitTrig_HostileRespawn takes nothing returns nothing
    local trigger t = CreateTrigger()
    set gg_trg_HostileRespawn = CreateTrigger(  )
    call TriggerRegisterTimerEvent(gg_trg_HostileRespawn, 0.00, false) //at 0sec of the game
    call TriggerAddAction( gg_trg_HostileRespawn, function Hostile_CountPreplaced)
    //---
    call TriggerRegisterPlayerUnitEvent(t, Player(12), EVENT_PLAYER_UNIT_DEATH, null)
    call TriggerAddCondition(t, Condition(function Hostile_OnDeath))
    set t=null   
endfunction
 

Attachments

  • CreepsRespawn.w3x
    32.8 KB · Views: 28
Level 19
Joined
Jul 2, 2011
Messages
2,162
Just use the spawn ability. The one the spiders have that when they die they produce two smaller versions of themselves. Only difference here is you will give the same unit type version and add a delay to the spawn ability.

You could use a trig for the rest... or maybe ....

Nah I give up jass is better
 
Level 7
Joined
Mar 10, 2013
Messages
366
Just use the spawn ability. The one the spiders have that when they die they produce two smaller versions of themselves. Only difference here is you will give the same unit type version and add a delay to the spawn ability.

You could use a trig for the rest... or maybe ....

Nah I give up jass is better
That system would really be funny, haha.
 
Level 19
Joined
Jul 2, 2011
Messages
2,162
That system would really be funny, haha.
I actually used a goblin factory for my map because you can set a rally point with a gf, but I see this thread has a slightly different preference.

Goblin factories would still work though as long as you create an invisible building. Also you will need to make the life span of creatures relatively short so that the re-spawn frequently. Items will be tough but I think you already don't have any at this point
 
Level 7
Joined
Mar 10, 2013
Messages
366
I actually used a goblin factory for my map because you can set a rally point with a gf, but I see this thread has a slightly different preference.

Goblin factories would still work though as long as you create an invisible building. Also you will need to make the life span of creatures relatively short so that the re-spawn frequently. Items will be tough but I think you already don't have any at this point
Wouldn't it cause 'unit flickering' while one unit is beign replaced by another?
 
Status
Not open for further replies.
Top