Introduction
This system was originally requested by Peacehagen for his map Rise of the Corruptor ORPG.
He recommended that I upload it because it would help people, which I hope it does!
I added some new features to it and made it as user-friendly as possible.
Features
- Respawn all dead creeps every X seconds, or individual creeps X seconds after they die.
- Specify which players to respawn creeps for.
- Functions which allow the following:
Respawn all dead creeps immediately.
Respawn all dead creeps owned by a specific player immediately.
Pause and resume the system.
Reset and restart the system.
Count how many creeps there are in total, alive and dead.
- Can create an effect on respawning units.
- Can choose to respawn heroes or not.
- Written in vJASS, can be used in GUI.
Requirements
- JASS NewGen Pack [LINK]
- Latest JASSHelper [LINK]
- TimerUtils by Vexorian (included in demo map)
library RespawnSystem initializer OnInit requires TimerUtils
//**************************************************\\//*** START OF CONFIGURABLES ***\\//**************************************************\\globals// Delay between unit dying and respawning:privateconstantreal RESPAWN_DELAY =30.0// Respawn all dead units at once? If set to false, units will respawn individually.privateconstantboolean RESPAWN_TOGETHER =true// Show a countdown window to all players:privateconstantboolean SHOW_TIMER_WINDOW =false// Countdown window text (only applicable if SHOW_TIMER_WINDOW = true):privateconstantstring TIMER_WINDOW_TEXT ="Creeps respawn in:"// Respawn heroes:privateconstantboolean RESPAWN_HEROES =false// Effect created on respawning units (set to "" to have no effect):privateconstantstring RESPAWN_EFFECT ="Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl"// Attachment point of effect on unit:privateconstantstring EFFECT_ATTACHMENT ="origin"endglobalsprivatefunction CheckOwner takesnothingreturnsbooleanlocalinteger playerId =GetPlayerId(GetOwningPlayer(GetFilterUnit()))if/*
//------------------------------------------------------\\
// Add the players that the system respawns creeps for: \\
// Remember to subtract 1 from GUI player indexes! \\
*/ playerId ==10or/* // Player 11 in GUI. \*
*/ playerId ==11or/* // Player 12 in GUI. \*
*/ playerId ==12/* // Neutral Hostile in GUI. \*
//------------------------------------------------------\\
*/thenreturntrueendifreturnfalseendfunction//**************************************************\\//*** END OF CONFIGURABLES ***\\//**************************************************\\globalsprivategroup deadCreeps =CreateGroup()privategroup creeps =CreateGroup()privategroup enumG =CreateGroup()privatehashtable ht =InitHashtable()privatetimer respawnTimer
privatetimerdialog timerWindow
privateinteger tempInt =0endglobalsprivatefunction Increment takesnothingreturnsnothingset tempInt = tempInt +1endfunctionprivatefunction EnumerateGroup takesgroup g returnsintegerset tempInt =0callForGroup(g,function Increment)return tempInt
endfunction//**************************************************\\//*** GetTotalCreeps ***\\//**************************************************\\function GetTotalCreeps takesnothingreturnsintegerreturn EnumerateGroup(creeps)+ EnumerateGroup(deadCreeps)endfunction//**************************************************\\//*** GetAliveCreeps ***\\//**************************************************\\function GetDeadCreeps takesnothingreturnsintegerreturn EnumerateGroup(deadCreeps)endfunction//**************************************************\\//*** GetDeadCreeps ***\\//**************************************************\\function GetAliveCreeps takesnothingreturnsintegerreturn EnumerateGroup(creeps)endfunction//**************************************************\\privatefunction RespawnCreepX takesinteger handleId returnsnothinglocalreal x =LoadReal(ht, handleId,StringHash("x"))localreal y =LoadReal(ht, handleId,StringHash("y"))localreal angle =LoadReal(ht, handleId,StringHash("facing"))localinteger owner =LoadInteger(ht, handleId,StringHash("owner"))localinteger unitType =LoadInteger(ht, handleId,StringHash("type"))localunit creep
set creep =CreateUnit(Player(owner), unitType, x, y, angle)callFlushChildHashtable(ht, handleId)callDestroyEffect(AddSpecialEffectTarget(RESPAWN_EFFECT, creep, EFFECT_ATTACHMENT))set handleId =GetHandleId(creep)callSaveReal(ht, handleId,StringHash("x"),GetUnitX(creep))callSaveReal(ht, handleId,StringHash("y"),GetUnitY(creep))callSaveReal(ht, handleId,StringHash("facing"),GetUnitFacing(creep))callSaveInteger(ht, handleId,StringHash("owner"),GetPlayerId(GetOwningPlayer(creep)))callSaveInteger(ht, handleId,StringHash("type"),GetUnitTypeId(creep))callGroupRemoveUnit(deadCreeps, creep)callGroupAddUnit(creeps, creep)set creep =nullendfunction//**************************************************\\//*** ResumeRespawnSystem ***\\//**************************************************\\function ResumeRespawnSystem takesnothingreturnsnothingstaticif RESPAWN_TOGETHER thencallResumeTimer(respawnTimer)elsecallBJDebugMsg("|cffff0000Respawn System|r: Cannot use ResumeRespawnSystem when RESPAWN_TOGETHER = false.")endifendfunction//**************************************************\\//*** PauseRespawnSystem ***\\//**************************************************\\function PauseRespawnSystem takesreal duration returnsnothingstaticif RESPAWN_TOGETHER thenif duration <0thencallPauseTimer(respawnTimer)elseif duration >0thencallPauseTimer(respawnTimer)callTimerStart(NewTimer(), duration,false,function ResumeRespawnSystem)endifelsecallBJDebugMsg("|cffff0000Respawn System|r: Cannot use PauseRespawnSystem when RESPAWN_TOGETHER = false.")endifendfunction//**************************************************\\//*** RespawnAllCreepsForPlayer ***\\//**************************************************\\function RespawnAllCreepsForPlayer takesplayer whichPlayer returnsnothinglocalunit temp
set enumG = deadCreeps
loopset temp =FirstOfGroup(enumG)exitwhen temp ==nullifGetOwningPlayer(temp)== whichPlayer thencall RespawnCreepX(GetHandleId(temp))endifcallGroupRemoveUnit(enumG, temp)endloopendfunctionprivatefunction GroupEnumeration takesnothingreturnsnothingcall RespawnCreepX(GetHandleId(GetEnumUnit()))endfunction//**************************************************\\//*** RespawnAllCreeps ***\\//**************************************************\\function RespawnAllCreeps takesnothingreturnsnothingcallForGroup(deadCreeps,function GroupEnumeration)endfunction//**************************************************\\//*** ResetRespawnSystem ***\\//**************************************************\\function ResetRespawnSystem takesnothingreturnsnothingstaticif RESPAWN_TOGETHER thencallTimerStart(respawnTimer, RESPAWN_DELAY,true,function RespawnAllCreeps)callPauseTimer(respawnTimer)elsecallBJDebugMsg("|cffff0000Respawn System|r: Cannot use ResetRespawnSystem when RESPAWN_TOGETHER = false.")endifendfunction//**************************************************\\//*** RestartRespawnSystem ***\\//**************************************************\\function RestartRespawnSystem takesnothingreturnsnothingstaticif RESPAWN_TOGETHER thencallTimerStart(respawnTimer, RESPAWN_DELAY,true,function RespawnAllCreeps)elsecallBJDebugMsg("|cffff0000Respawn System|r: Cannot use RestartRespawnSystem when RESPAWN_TOGETHER = false.")endifendfunction//**************************************************\\privatefunction TimerExpiration takesnothingreturnsnothingcall RespawnCreepX(GetTimerData(GetExpiredTimer()))call ReleaseTimer(GetExpiredTimer())endfunctionprivatefunction CreepDeath takesnothingreturnsbooleanlocalunit u =GetTriggerUnit()ifIsUnitInGroup(u, creeps)thencallGroupRemoveUnit(creeps, u)callGroupAddUnit(deadCreeps, u)staticifnot RESPAWN_TOGETHER thencallTimerStart(NewTimerEx(GetHandleId(u)), RESPAWN_DELAY,false,function TimerExpiration)endifendifset u =nullreturnfalseendfunctionprivatefunction GroupCreeps takesnothingreturnsnothinglocalunit temp
localinteger handleId
callGroupEnumUnitsInRect(enumG,bj_mapInitialPlayableArea,Condition(function CheckOwner))loopset temp =FirstOfGroup(enumG)exitwhen temp ==nullifnotIsUnitType(temp,UNIT_TYPE_DEAD)thenset handleId =GetHandleId(temp)callSaveReal(ht, handleId,StringHash("x"),GetUnitX(temp))callSaveReal(ht, handleId,StringHash("y"),GetUnitY(temp))callSaveReal(ht, handleId,StringHash("facing"),GetUnitFacing(temp))callSaveInteger(ht, handleId,StringHash("owner"),GetPlayerId(GetOwningPlayer(temp)))callSaveInteger(ht, handleId,StringHash("type"),GetUnitTypeId(temp))callGroupAddUnit(creeps, temp)endifcallGroupRemoveUnit(enumG, temp)endloopendfunctionprivatefunction CreateDialog takesnothingreturnsnothingset timerWindow =CreateTimerDialog(respawnTimer)callTimerDialogSetTitle(timerWindow, TIMER_WINDOW_TEXT)callTimerDialogDisplay(timerWindow,true)endfunctionprivatefunction OnInit takesnothingreturnsnothinglocaltrigger t =CreateTrigger()callTriggerAddCondition(t,Condition(function CreepDeath))callTriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_DEATH)set t =nullcall GroupCreeps()staticif RESPAWN_TOGETHER thenset respawnTimer =CreateTimer()callTimerStart(respawnTimer, RESPAWN_DELAY,true,function RespawnAllCreeps)staticif SHOW_TIMER_WINDOW thencallTimerStart(NewTimer(),0.01,false,function CreateDialog)endifendifendfunctionendlibrary
Changelogs
v1.0b (33 June 2012)
- Improved creep counting as per KnnO's suggestion.
- Added map name, description and author for demo map.
v1.0 (22 June 2012)
- Initial release.
Credits
- Peacehagen for requesting the system and encouraging me to upload it.
- Vexorian for TimerUtils.
Contact
If you find any bugs in the system or if something is unclear in the documentation, please let me know!
- Email
- Private Message
Rating - 5.00 (1 vote)
(Hover and click)
Moderator Comments
Not Rated
12:09, 17th Jul 2012
Magtheridon96:
Comments
Instead of using the ForGroup function to figure out the number of units, you can keep track of the number of units dead and alive by yourself using a couple of integers.
ResumeTimer -> TimerStart because it's faster :P
Instead of using those StringHash functions, you can use constant integers, or as the others suggested, keys.
CheckOwner can be shortened to 2 lines. You just need to return the conditions of the if statement. (
return playerId ==10or playerId ==11or playerId ==12
)
__________________ Mr_Bean's Spell Workshop - Looking for people to help with GUI & vJASS requests. - Need help importing your request? Try this guide I wrote!
It's written in vJASS, but you can obviously use GUI actions (custom scripts).
__________________ Mr_Bean's Spell Workshop - Looking for people to help with GUI & vJASS requests. - Need help importing your request? Try this guide I wrote!
I recommend this system, very easy to use (and i have 0 jass knowledge) and works perfectly. All other i have tried have had an issue that some units did not respawn but this solved it :)
function EnumerateGroup takesgroup g returnsinteger callForGroup(g,function Inc)
retun count endfunction
But I am not sure If you are using it that way because it is faster or something...are you? or because you don't want an extra function and an extra variable? IDK
Update:
Uploaded version 1.0b:
- Fixed creep counting as per KnnO's suggestion.
- Added map name, description and author for the demp map.
@KnnO: Thanks man! I guess I'm just too used to using FirstOfGroup loops in spells. Much appreciated.
__________________ Mr_Bean's Spell Workshop - Looking for people to help with GUI & vJASS requests. - Need help importing your request? Try this guide I wrote!
@Mr_Bean987, First of all nice API you got there :) Alright lets get down to business. Instead of using hashtables, i suggest you use a struct and store the handle id of the unit on its respective timer when it dies. If you still insist on using hashtables, then i suggest you use the variable type
Jass:
key
and make it constant; this is rather than using stringhash.
Can you please give me an example of how I should use
key
...
If I were to use structs, would I create a new instance for each creep? Is this more efficient than hashtables?
__________________ Mr_Bean's Spell Workshop - Looking for people to help with GUI & vJASS requests. - Need help importing your request? Try this guide I wrote!
/* ======================
Respawn System - v1.1
======================
Coded by: Mr_Bean (mrbean987789@gmail.com)
Introduction:
-------------
This system was originally requested by Peacehagen for his map Rise of the Corruptor ORPG.
He recommended that I upload it because it would help people, which I hope it does!
I added some new features to the system and made it as user-friendly as possible.
This system only works for units that are on the map as soon as the game starts.
Feel free to contact me if something is not clear, or if you find bugs.
Installation:
-------------
> Copy this trigger.
> Copy the "TimerUtils" trigger (if you don't have it already).
> Configure the "Configurables" section in this trigger as desired.
Available Functions:
--------------------
> RespawnAllCreeps()
- Immediately respawns all dead creeps.
- Does not affect countdown timer.
> RespawnAllCreepsForPlayer(player whichPlayer)
- Immediately respawns all dead creeps for a specified player.
- Does not affect countdown timer.
> PauseRespawnSystem(real howLong)
- If all creeps respawn together, you can use this to pause the system.
- The parameter is how long it is paused for. Use any negative number to pause it forever (until you resume again). Using 0 means no pause.
- Can only use if RESPAWN_TOGETHER = true.
> ResumeRespawnSystem()
- This will resume the system.
- Only works if you used PauseRespawnSystem with a negative number (like PauseRespawnSystem(-1)).
- Can only use if RESPAWN_TOGETHER = true.
> ResetRespawnSystem()
- This will pause the system and reset the countdown.
- Needs to be unpaused with ResumeRespawnSystem().
- Can only use if RESPAWN_TOGETHER = true.
> RestartRespawnSystem()
- This will reset the respawn countdown.
- Will not pause the system.
- Can only use if RESPAWN_TOGETHER = true.
> GetAliveCreeps()
- Returns how many creeps are alive.
> GetDeadCreeps()
- Returns how many creeps are dead.
> GetTotalCreeps()
- Returns how many creeps there are in total.
Contact:
--------
> [email]mrbean987789@gmail.com[/email]
> Mr_Bean987 on the HiveWorkshop.com
// Delay between unit dying and respawning: privateconstantreal RESPAWN_DELAY =30.0 // Respawn all dead units at once? If set to false, units will respawn individually. privateconstantboolean RESPAWN_TOGETHER =false // Show a countdown window to all players: privateconstantboolean SHOW_TIMER_WINDOW =false // Countdown window text (only applicable if SHOW_TIMER_WINDOW = true): privateconstantstring TIMER_WINDOW_TEXT ="Creeps respawn in:" // Respawn heroes: privateconstantboolean RESPAWN_HEROES =false // Effect created on respawning units (set to "" to have no effect): privateconstantstring RESPAWN_EFFECT ="Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl" // Attachment point of effect on unit: privateconstantstring EFFECT_ATTACHMENT ="origin"
//------------------------------------------------------\\
// Add the players that the system respawns creeps for: \\
// Remember to subtract 1 from GUI player indexes! \\
*/ playerId ==10or/* // Player 11 in GUI. \*
*/ playerId ==11or/* // Player 12 in GUI. \*
*/ playerId ==12/* // Neutral Hostile in GUI. \*
//------------------------------------------------------\\
*/then returntrue endif returnfalse endfunction
//**************************************************\\ //*** END OF CONFIGURABLES ***\\ //**************************************************\\
function ResumeRespawnSystem takesnothingreturnsnothing staticif RESPAWN_TOGETHER then callResumeTimer(respawnTimer) else callBJDebugMsg("|cffff0000Respawn System|r: Cannot use ResumeRespawnSystem when RESPAWN_TOGETHER = false.") endif endfunction
privatefunction CreateDialog takesnothingreturnsnothing set timerWindow =CreateTimerDialog(respawnTimer) callTimerDialogSetTitle(timerWindow, TIMER_WINDOW_TEXT) callTimerDialogDisplay(timerWindow,true) endfunction
privatefunction OnInit takesnothingreturnsnothing localtrigger t =CreateTrigger() callTriggerAddCondition(t,Condition(function CreepDeath)) callTriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_DEATH) set t =null
call GroupCreeps()
staticif RESPAWN_TOGETHER then
set respawnTimer =CreateTimer() callTimerStart(respawnTimer, RESPAWN_DELAY,true,function RespawnAllCreeps)
staticif SHOW_TIMER_WINDOW then callTimerStart(NewTimer(),0.01,false,function CreateDialog) endif
endif
endfunction
endlibrary
There is no need for struct, btw, I must suggest that you make timer library optional, so you can use this system even without it.
I say this because I myself code in that way to minimize number of external libraries I use.
For example Table library is really awesome but using it in your map only because of 1 spell is ridiculous, where it can be replaced with indexing or single hash, but when you speak about 10 spells 1 table will certainly become more powerful than 10 hashtables.
But then how can I respawn a specific creep when it dies without attaching its handle id to a timer?
__________________ Mr_Bean's Spell Workshop - Looking for people to help with GUI & vJASS requests. - Need help importing your request? Try this guide I wrote!