• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

RespawnSystem v1.1 [Zinc]

  • Like
Reactions: Almia

Foreword

Code

Demo

Credits

Changelogs

Bugs


- This is my first ever system written in Zinc, I just learned this day :p
- Respawns the same unit(s) at the same point and facing angle with customable effects and delay.
- Heroes will be revived instead of recreated.


JASS:
//! zinc
library RespawnSystem requires Table, TimerUtils, optional RegisterPlayerUnitEvent /* v1.1
*************************************************************************************
*
*   by mckill2009
*   - My first ever system written in Zinc.
*
*************************************************************************************
*
*   Respawns the same unit(s) at the same point and facing angle with customable effects and delay.
*
*************************************************************************************
*
*   Required Libraries:
*       Table by Bribe (www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084)
*       TimerUtils by Vexorian (www.wc3c.net/showthread.php?t=101322)
*       
*   Optional Library:
*       RegisterPlayerUnitEvent by Magtheridon96 (http://www.hiveworkshop.com/forums/jass-resources-412/snippet-registerplayerunitevent-203338/)
*
*************************************************************************************
*
*   Installation:
*       Just copy all the required libraries and this script to your map and follow the 
*       API callings or refer to the DEMO trigger.
*
*************************************************************************************
*
*   API:
*       public static method register(unit u)
*           - call RespawnSystem.register(UNIT)
*           - Sets the unit to respawn in simple manner
*
*       public static method registerEx(unit u, real delay, string sfx, player pl)
*           - call RespawnSystem.registerEx(UNIT, custom delay, custom effect, owner player)
*           - Respawns with configurables
*
*       public static method remove(unit u)
*           - call RespawnSystem.remove(UNIT)
*           - Unit will not be respawned again
*
*************************************************************************************/
{
    constant real DEFAULT_DELAY = 5;
    constant string DEFAULT_SFX = "";
    Table chk;
    
public struct RespawnSystem
{
    unit u;
    real x;
    real y;
    real f;
    real del;
    string sfx;
    player pl;
    integer id;
   
    static method respawnNow()
    {
        timer t = GetExpiredTimer();
        thistype this = GetTimerData(t);
        thistype new = thistype.allocate();
        unit nonHero;
        if (IsUnitType(this.u, UNIT_TYPE_HERO)) {
            ReviveHero(this.u, this.x, this.y, true);        
            chk[GetHandleId(this.u)] = new;            
        } else {
            nonHero = CreateUnit(this.pl, this.id, this.x, this.y, this.f);
            if (this.sfx != "") 
                {DestroyEffect(AddSpecialEffectTarget(this.sfx, u, "origin"));}
            chk[GetHandleId(nonHero)] = new;
            nonHero = null;
        }
        new.x = this.x;
        new.y = this.y;
        new.f = this.f;
        new.del = this.del;
        new.sfx = this.sfx;
        new.pl = this.pl; 
        this.pl = null;
        this.u = null;
        ReleaseTimer(t);
        chk.remove(id);
        this.deallocate();
        t = null;
    }
    
    static method death()->boolean
    {
        thistype this;
        unit u = GetTriggerUnit();
        if (chk.has(GetHandleId(u))) {
            this = chk[GetHandleId(u)];
            this.id = GetUnitTypeId(u);
            this.u = u;
            TimerStart(NewTimerEx(this), this.del, false, function thistype.respawnNow);
        }
        u = null;
        return false;
    }
 
    static method onInit()
    {
        static if (LIBRARY_RegisterPlayerUnitEvent) {
            RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.death);
        } else {
            trigger t = CreateTrigger();
            TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_DEATH);
            TriggerAddCondition(t,function thistype.death);
            t = null;
        }
        chk = Table.create();
    }
   
    /*****************************************************************
    *   API:
    ******************************************************************/
  
    public static method register(unit u)
    {
        thistype this = thistype.allocate();
        chk[GetHandleId(u)] = this;
        this.id = GetUnitTypeId(u);
        this.x = GetUnitX(u);
        this.y = GetUnitY(u);
        this.f = GetUnitFacing(u);
        this.del = DEFAULT_DELAY;
        this.sfx = DEFAULT_SFX;
        this.pl = GetOwningPlayer(u);   
    }
   
    public static method registerEx(unit u, real delay, string sfx, player pl)
    {
        thistype this = thistype.allocate();
        chk[GetHandleId(u)] = this;
        this.x = GetUnitX(u);
        this.y = GetUnitY(u);
        this.f = GetUnitFacing(u);
        this.del = delay;
        this.sfx = sfx;
        this.pl = GetOwningPlayer(u);
        if (pl==null) {
            this.pl = GetOwningPlayer(u);
        }            
    }
 
    public static method remove(unit u)
        {chk.remove(GetHandleId(u));}
}
}    
//! endzinc

  • DEMO
    • Events
      • Time - Elapsed game time is 1.00 seconds
    • Conditions
    • Actions
      • Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
        • Loop - Actions
          • Custom script: local integer random = GetRandomInt(1, 2)
          • Custom script: if random==1 then
          • -------- =====Respawns in simple fashion===== --------
          • Custom script: call RespawnSystem.register(GetEnumUnit())
          • Custom script: else
          • -------- =====Respawns with configuration===== --------
          • Custom script: call RespawnSystem.registerEx(GetEnumUnit(), GetRandomReal(5, 8), "Objects\\Spawnmodels\\NightElf\\EntBirthTarget\\EntBirthTarget.mdl", GetOwningPlayer(GetEnumUnit()))
          • Custom script: endif
      • Trigger - Turn on Loop <gen>
  • Loop
    • Events
      • Time - Every 2.00 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in (Random 1 units from (Units in (Playable map area) matching (((Matching unit) is alive) Equal to True))) and do (Actions)
        • Loop - Actions
          • Unit - Kill (Picked unit)

Required Libraries:
Table by Bribe
TimerUtils vy Vexorian

Optional Library:
RegisterPlayerUnitEvent by Magtheridon96

v1.1
- TableArray removed an focused on indexing
- Added revive for heroes

-



Keywords:
zinc, mckill2009, respawn, unit, id, system, vjass, gui, effect, effects, sfx, dota
Contents

RespawnSystem (Map)

Reviews
18:45, 19th Aug 2013 PurgeandFire: Changes made. Approved.

Moderator

M

Moderator

18:45, 19th Aug 2013
PurgeandFire: Changes made. Approved.
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
Even though it may seem obvious, you should still mention that your system is for respawning non-hero units. (It doesn't have ideal behavior for heroes since it creates new units instead of reviving them.)

You should document what FIXED_DELAY and FIXED_SFX do.

Opinion
DEFAULT seems like a better name choice than FIXED.

I'd suggest saving information in a struct instead of abusing TableArray; it's easier to understand and maintain the code rather than having to remember arbitrary values like 4 being the index for a special effect.

Your coding style is rather unappealing. :\
Specifically, doing things like
JASS:
if (rs[4].string[id] != "") {DestroyEffect(AddSpecialEffectTarget(rs[4].string[id], u, "origin"));}
JASS:
// Having different indentation for this can also be misleading.
            if (pl==null) {rs[5].player[uID] = GetOwningPlayer(u);}
            else {rs[5].player[uID] = pl;}
and
JASS:
    public static method remove(unit u)
        {chk.remove(GetHandleId(u));}
Squishing braces like that can be confusing.
The opening library brace and the two ending braces from the struct and library makes the code look confusing.
 
forgot to filter out the non-hero thing as this suppose to create only non-hero units...
I'd suggest saving information in a struct instead of abusing TableArray
it'll still need Table for that since I can only save the 'this' to the handle of the dying unit and then pass to the next unit...and it will be limited to 8192, but then again who uses 8192 anyway :D...
Your coding style is rather unappealing. :\
sorry for that, its my first time to use zinc, but I think that it's OK to reduce lines...
 
- Indentation needs work (needs to be consistent and readable)
- Default does actually make a better label here than Fixed because it expresses the intent and purpose of the global constants
- Can we agree to always use one style of indentation in one library?

The accepted styles of indentation here are as follows:

  • K&R
    Code:
    if (x) {
        y();
    } else {
        z();
    }
  • Allman
    Code:
    if (x)
    {
        y();
    }
    else
    {
        z();
    }
  • Stroustrup
    Code:
    if (x) {
        y();
    }
    else {
        z();
    }

GNU style, Whitesmiths style, Pico style and pretty much any other style you can think of, yeah... don't use them. Your colleagues will hate you.
 
You don't need 6 or so tables/instances. You only need 1 for this.

JASS:
struct X
    static Table instance = 0
    real x
    real y
    integer id 
    // ... other data

    static method create takes unit u returns thistype 
         local thistype this = thistype.allocate()
         set this.x = GetUnitX(u)
         set this.y = GetUnitY(u) // etc... 
         //... other saving
         set instance[GetUnitTypeId(u)] = this // only need to save this
         return this 
    endmethod

    // move this to module init, though
    private static method onInit takes nothing returns nothing 
         set instance = Table.create()
    endmethod
endstruct

Then when you load it, you just load the instance via:
JASS:
local thistype this = instance[GetUnitTypeId(GetTriggerUnit())]
Right now, your method works, but it is reading quite a few things from a hashtable. Reading it from the arrays will save a lot of time on both lookup and saving. Of course, this means you are limited to 8192 creeps, but that is an issue that can be ignored for most maps.

By the way, you should save under the unit's type ID. Saving under the handle ID means that you have to save the data all over again each time the unit dies. However, if you save it under the unit's type ID, you only need to save it once (since the next unit rezz'd will have the same type ID).

If you make those changes, it will be approvable.
 
Level 16
Joined
Aug 7, 2009
Messages
1,406
@PurgeAndFire:

He could actually do it without having to use Table at all. All you need is a unit indexer (that almost every mapper has - although the same goes to Table as well) and an integer array. It should be faster - not that it'd make that big of a difference for such resource, though I usually stick to that solution.
 
Top