• 🏆 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!

[Snippet] ReviveUnit

ReviveUnit

Revives a unit in a similar fashion to reviving a hero. Note it does not work on units who do not leave a corpse (e.g. exploded, does not decay etc.).

Here is the code:
JASS:
library ReviveUnit /* 2.0.0.0
***************************************************
*
*   Resurrects a unit from his corpse, retaining
*   its handle ID, facing, and position.
*
***************************************************
*
*   ReviveUnit(unit whichUnit) returns boolean
*       - Resurrects the input unit.
*
***************************************************
*
*   Configurables
*       - Remove the ! from //! after saving.
*/
    //! external ObjectMerger w3a AHre URez anam "Dummy Resurrection" aher 0 acat "" atat "" Hre1 1 1 aare 1 0 aran 1 0 acdn 1 0 amcs 1 0 atar 1 "Air,Dead,Enemy,Friend,Ground,Neutral"
    //! external ObjectMerger w3u ushd eRez unam "Dummy" uabi "Aloc,Avul" ucbs 0 ucpt 0 umdl ".mdl" usca "0.01" ushu "None" umvh 0 umvs 0 ufoo 0 umpi 100000 umpm 100000 umpr 1000
        
    globals
        private constant integer DUMMY = 'eRez'
        private constant integer RESURRECT = 'URez'
    endglobals
/*
***************************************************
*
*   Notes
*       - Does not work on units without corpses.
*       - The resurrected unit's mana is determined
*         by the field: "Mana - Initial Amount" 
*
***************************************************
*
*   Importing: Automatic
*       - Copy and paste this trigger.
*       - Save the map, close it, and reopen it
*       - Remove the exclamation ! from the object
*         merger lines above.
*
*   Importing: Manual
*       - Copy and paste this trigger.
*       - Copy and paste the dummy unit and resurrection
*         ability from the object editor.
*       - Change the configurable raw codes as necessary.
*
***************************************************/

    globals 
        private unit reviver
        private real rx
        private real ry
    endglobals
    
    function ReviveUnit takes unit u returns boolean 
        local boolean success
        if IsUnitType(u, UNIT_TYPE_HERO) == true then
            return ReviveHero(u, GetUnitX(u), GetUnitY(u), false)
        else
            call SetUnitX(reviver, GetUnitX(u))
            call SetUnitY(reviver, GetUnitY(u))
            set success = IssueImmediateOrderById(reviver, 852094)
            call SetUnitX(reviver, rx)
            call SetUnitY(reviver, ry)
        endif
        return success
    endfunction
    
    private module Init
        private static method onInit takes nothing returns nothing 
            set rx = GetRectMaxX(bj_mapInitialPlayableArea) - 1
            set ry = GetRectMaxY(bj_mapInitialPlayableArea) - 1
            set reviver = CreateUnit(Player(15), DUMMY, rx, ry, 0)
            call SetUnitPathing(reviver, false)
            call UnitAddAbility(reviver, RESURRECT)
        endmethod
    endmodule
    
    struct Revive extends array
        /* For backwards compatibility */
        static method Unit takes unit whichUnit returns boolean
            return ReviveUnit(whichUnit)
        endmethod
        
        implement Init
    endstruct
endlibrary

Here is a demo map.
 

Attachments

  • ReviveUnit.w3x
    19.2 KB · Views: 394
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
Use http://www.hiveworkshop.com/forums/jass-functions-413/snippet-worldbounds-180494/ to save yourself some handle creation.

library ReviveUnit initializer Init

ReviveUnit(KillUnit(u)) won't work in a struct onInit or module onInit.

I'm sure we've went over making a habit of using module onInits twice now ; P.

I'll take a look at the rest soon, I'm in the middle of something ;D.

edits
Ok, I'm already seeing a few blatant problems. When it comes to vjass code using custom objects, it is a convention to use lua. Most people use a single line external block script to generate an object. Recently, a slew of lua scripts have come out that makes it possible to generate objects that have a 0% chance of colliding with each other, so at this point using the single line is pure laziness and is bad* as they have a chance to collide with other scripts.

I'll link you to the UnitIndexer Installation code so that you can learn more about these scripts, but you should learn how to use them and create your own installation script.

UnitIndexer
JASS:
//If running into an error, be sure that the lua scripts have been updated
//Since the update of this library, a few of the lua scripts were secretly modified : P

//LUA_JASS_IO: hiveworkshop.com/forums/jass-functions-413/snippet-lua_jass_io-177419/
//LUA_FIND_LINE: hiveworkshop.com/forums/jass-functions-413/snippet-lua_find_line-177418/
//LUA_TRIM: hiveworkshop.com/forums/jass-functions-413/snippet-lua_trim-177439/
//LUA_OBJECT_ID: hiveworkshop.com/forums/jass-functions-413/snippet-lua_object_id-176943/
//LUA_STRING_EXPLODE: hiveworkshop.com/forums/jass-functions-413/snippet-lua_string_explode-176944/
//LUA_JASS_GLOBALS: hiveworkshop.com/forums/submissions-414/system-lua_jass_globals-185917/
//LUA_GET_VAR_OBJECT: hiveworkshop.com/forums/submissions-414/snippet-lua_get_var_object-185944/


//! externalblock extension=lua ObjectMerger $FILENAME$
    //replace FILE_NAME with the name of the map
    //! runtextmacro LUA_JASS_IO("FILE_NAME")

    //////////////////////////////////////////////////////////////////////////////////
    //! runtextmacro LUA_FIND_LINE()
    //! runtextmacro LUA_STRING_TRIM()
    //! runtextmacro LUA_GET_OBJECT_ID()
    //! runtextmacro LUA_STRING_EXPLODE()
    //! runtextmacro LUA_JASS_GLOBALS()
    //! runtextmacro LUA_GET_VAR_OBJECT()
    
    //! i local id = getvarobject("Adef", "abilities", "ABILITIES_UNIT_INDEXER")
    
    //! i createobject("Adef", id)
    //! i makechange(current, "anam", "Unit Indexing")
    //! i makechange(current, "ansf", "(Unit Indexing)")
    //! i makechange(current, "aart", "")
    //! i makechange(current, "arac", "0")
//! endexternalblock

UnitEvent
JASS:
//If running into an error, be sure that the lua scripts have been updated
//Since the update of this library, a few of the lua scripts were secretly modified : P

//LUA_JASS_IO: hiveworkshop.com/forums/jass-functions-413/snippet-lua_jass_io-177419/
//LUA_FIND_LINE: hiveworkshop.com/forums/jass-functions-413/snippet-lua_find_line-177418/
//LUA_TRIM: hiveworkshop.com/forums/jass-functions-413/snippet-lua_trim-177439/
//LUA_OBJECT_ID: hiveworkshop.com/forums/jass-functions-413/snippet-lua_object_id-176943/
//LUA_STRING_EXPLODE: hiveworkshop.com/forums/jass-functions-413/snippet-lua_string_explode-176944/
//LUA_JASS_GLOBALS: hiveworkshop.com/forums/submissions-414/system-lua_jass_globals-185917/
//LUA_GET_VAR_OBJECT: hiveworkshop.com/forums/submissions-414/snippet-lua_get_var_object-185944/

//! externalblock extension=lua ObjectMerger $FILENAME$
    //replace FILE_NAME with the name of the map
    //! runtextmacro LUA_JASS_IO("FILE_NAME")
    
    //////////////////////////////////////////////////////////////////////////////////
    //! runtextmacro LUA_FIND_LINE()
    //! runtextmacro LUA_STRING_TRIM()
    //! runtextmacro LUA_GET_OBJECT_ID()
    //! runtextmacro LUA_STRING_EXPLODE()
    //! runtextmacro LUA_JASS_GLOBALS()
    //! runtextmacro LUA_GET_VAR_OBJECT()
    
    //! i local id = getvarobject("nfr2", "units", "UNITS_UNIT_EVENT")
    
    //! i createobject("nfr2", id)
    //! i makechange(current, "unam", "Unit Event")
    //! i makechange(current, "unsf", "(Unit Event)")
    //! i makechange(current, "uico", "")
    //! i makechange(current, "uine", "0")
    //! i makechange(current, "udro", "-")
    //! i makechange(current, "usnd", "")
    //! i makechange(current, "ushb", "")
    //! i makechange(current, "umdl", "")
    //! i makechange(current, "uubs", "")
    //! i makechange(current, "ides", "")
    //! i makechange(current, "utip", "")
    //! i makechange(current, "usca", ".01")
    //! i makechange(current, "ussc", ".01")
    
    //! i local j = ((jass.globals.create(jassread())):read("ABILITIES_UNIT_INDEXER")).value:sub(2,5)
    //! i makechange(current, "uabi", "Aloc," .. j)
    //! i makechange(current, "ubdg", "0")
//! endexternalblock

These scripts are fairly new, so that is why there are lots of resources around right now that don't use them. Atm, their installation into maps (the scripts themselves) are being thrown into question on how to be accomplished, but you've seen the future of vjass coding thread, so I'm sure you already know about this.

Now on to the code

These should be installed via Lua. These names are not proper convention. Units need to be UNITS_NAME and abilities need to be ABILITIES_NAME. This comes from a combination JASS constant naming convention and grimoire.
JASS:
       private constant integer DUMMY_ID = 'dumy'
        private constant integer RESURRECTION_ID = 'ResX'

Not needed with WorldBounds

JASS:
        private real SAFE_X
        private real SAFE_Y

It'd be good to retrieve the order integer id ; P. Only takes a second to retrieve. Oh if only there was an orders script that had a list of constants with all of these ids. Oh if only.
call IssueImmediateOrder(reviver,"resurrection")

Your init is bad
->call UnitAddAbility(reviver,RESURRECTION_ID)

The unit should already have this ability on it.

Furthermore, the unit should also have locust and it should be paused when not in use. It should also have a move speed of 0 and a scaling of .01 as well as a possible invisibility abil.

Make sure that ReviveUnit targets allies and enemies ;D.

Just WorldBounds.maxX and WorldBounds.maxY
JASS:
call SetUnitX(reviver,SAFE_X)
        call SetUnitY(reviver,SAFE_Y)

Also, your resurrection should have a radius of like 0. In fact, for further stability, I would move the reviving unit to the rezzer at the edge of the map, rez, and then move it back. As it stands, you have a chance of reviving multiple units.

Not needed
private group g = CreateGroup()

function ReviveUnit takes unit whichUnit returns unit

Should be
function ReviveUnit takes unit whichUnit returns nothing

Why on earth would you return the passed in unit? That's silly, the caller already has access to it >.<.

Remove this
return FirstOfGroup(g)

Also, you should have a reviveLocation with a radius or something ;O. To accomplish this, enumerate units in the radius, store their locations, move them to the rezzer, resurrect, and then move them back. Why do all of this? So that your radius can be anything (you don't want to make a 1000 resurrection abilities with a 1000 different radii do you?).

If you were to add that above feature then I guess your group handle could be retained in the script.

Also check if the unit is of type hero, and if so, use ReviveHero on it, otherwise run your script.
 
Last edited:
Use http://www.hiveworkshop.com/forums/jass-functions-413/snippet-worldbounds-180494/ to save yourself some handle creation.

library ReviveUnit initializer Init

ReviveUnit(KillUnit(u)) won't work in a struct onInit or module onInit.

Why would you revive someone on init? lol. But okay.

These should be installed via Lua.

As for LUA, yeah I was going to generate it. However, I came across some weird things (I don't remember what they were), but I'll revisit it soon.

These names are not proper convention. Units need to be UNITS_NAME and abilities need to be ABILITIES_NAME. This comes from a combination JASS constant naming convention and grimoire.
JASS:
       private constant integer DUMMY_ID = 'dumy'
        private constant integer RESURRECTION_ID = 'ResX'

Okay. :p

Not needed with WorldBounds

Oh, I didn't see that library yet. neat.

It'd be good to retrieve the order integer id ; P. Only takes a second to retrieve. Oh if only there was an orders script that had a list of constants with all of these ids. Oh if only.

Okay.

Your init is bad
->call UnitAddAbility(reviver,RESURRECTION_ID)

The unit should already have this ability on it.

Furthermore, the unit should also have locust and it should be paused when not in use. It should also have a move speed of 0 and a scaling of .01 as well as a possible invisibility abil.

I wanted to allow the possibility of using your own dummy unit if you already have one. But I guess I can do that.

in ReviveUnit, you need to change the owner of the unit to the player as Player(15) may not be allied to the player in the map script. Alliance properties can change you know. The unit ownership can be changed back to 15 after reviving is done.

Okay.

Also, your resurrection should have a radius of like 0. In fact, for further stability, I would move the reviving unit to the rezzer at the edge of the map, rez, and then move it back. As it stands, you have a chance of reviving multiple units.

Yeah I can make a smaller radius. I made it 50 at the moment, but I guess I can make it bigger. On the spell though, it has an option of how many units to res, so I set that to 1 opposed to 6 so it will always revive 1 unit. But yeah, I'll move it out and then res and back in.

Not needed
private group g = CreateGroup()

function ReviveUnit takes unit whichUnit returns unit

Should be
function ReviveUnit takes unit whichUnit returns nothing

Why on earth would you return the passed in unit? That's silly, the caller already has access to it >.<.

Remove this
return FirstOfGroup(g)

Lol, yeah. I'll update that.

Also, you should have a reviveLocation with a radius or something ;O. To accomplish this, enumerate units in the radius, store their locations, move them to the rezzer, resurrect, and then move them back. Why do all of this? So that your radius can be anything (you don't want to make a 1000 resurrection abilities with a 1000 different radii do you?).

Yeah, that is an interesting idea. I'll implement it soon.

Also check if the unit is of type hero, and if so, use ReviveHero on it, otherwise run your script.

That should be left up to the user. But okay. :\

Ty for the feedback.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
On this note-
in ReviveUnit, you need to change the owner of the unit to the player as Player(15) may not be allied to the player in the map script. Alliance properties can change you know. The unit ownership can be changed back to 15 after reviving is done.

I changed it to this-
Make sure that ReviveUnit targets allies and enemies ;D.

The second is smerter ;P.

That should be left up to the user. But okay. :\

Reviving heroes is faster with ReviveHero, no? : P


As for LUA, yeah I was going to generate it. However, I came across some weird things (I don't remember what they were), but I'll revisit it soon.

Post any issues you find with any of the scripts so that I can fix them >: P, lol.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
->Yep, but this doesn't work for heroes

I suppose, but a user may be passing in some random unit that may or may not be a hero. Furthermore, I've seen plenty of resurrection spells in ORPGs that revive heroes ;P.

->For LUA, I don't know what to do when I get to Targets Allowed. How do I fill in values for that?
Go to Object Editor, click on your Revive Object, go to the revive list, hit CTRL + D. CTRL+D changes view to raw data. Raw data view allows you to directly see what types of values the properties take =). If you already have your targets set up, you can just sorta write it out in the lua.

Keep in mind that properties can't have space in them. If there are commas, don't add spaces! I did that with UnitEvent when I was trying to add 2 abils and was wondering why it wasn't working until I saw that it treated the spaces as part of the object ids ;P.
 
Okay, here is the current code.
JASS:
library ReviveUnit requires WorldBounds
    //***********************************************
    //       REVIVE UNIT
    //***********************************************
    //  - This library allows you to revive units in a similar fashion to heroes. 
    //  - This library retains the unit's previous handle ID 
    //  - This library retains the unit's facing
    //  - It will fail if the unit has decayed already
    
    //  Implementation:
    //    - Copy the spell named "Resurrection"
    //    - Paste it in your map
    //    - Copy this trigger and its contents, and paste it in your map
    //    - Modify RESURRECTION_ID to the rawcode of the resurrection spell in your map (press CTRL+D to view rawcode)
    //    - Modify DUMMY_ID to the rawcode of the dummy unit your are using
    
    //  Function:
    //      function ReviveUnit takes unit whichUnit returns nothing
    //          - Revives a unit who is currently a corpse and decaying
    
    //***********************************************
    

    globals
        private constant integer UNITS_DUMMY = 'dumy'
        private constant integer ABILITIES_DUMRESURRECTION = 'ResX'
        
        private unit reviver 
    endglobals
    
    private module ReviveInitialization
        private static method onInit takes nothing returns nothing
            set reviver = CreateUnit(Player(15),UNITS_DUMMY,WorldBounds.maxX,WorldBounds.maxY,0)
        endmethod
    endmodule
    
    struct Revive extends array
        static method Unit takes unit whichUnit returns nothing
            if IsUnitType(whichUnit,UNIT_TYPE_HERO) == true then
                call ReviveHero(whichUnit,GetUnitX(whichUnit),GetUnitY(whichUnit),false)
            else
                call SetUnitX(reviver,GetUnitX(whichUnit))
                call SetUnitY(reviver,GetUnitY(whichUnit))
                call IssueImmediateOrderById(reviver,852094)
                call SetUnitX(reviver,WorldBounds.maxX)
                call SetUnitY(reviver,WorldBounds.maxY)
            endif
        endmethod
        
        implement ReviveInitialization
    endstruct
endlibrary

One thing:

Moving a corpse is impossible, lol. Thus, I couldn't do that technique. :( So, I had to resort back to my old technique, which seems to work fine.

--------

As for LUA, this is what I have atm:
JASS:
//! runtextmacro GenerateAbility("true")

//! textmacro GenerateAbility takes BOOL
    //! externalblock extension=lua ObjectMerger $FILENAME$
    //! i if "$BOOL$" == "true" then
        //! i setobjecttype("abilities")
        //! i createobject("AHre","ReSX")
        //! i makechange(current,"aher","0")
        //! i makechange(current,"acat","")
        //! i makechange(current,"atat","")
        //! i makechange(current,"Hre1","1")
        //! i makechange(current,"aare","0")
        //! i makechange(current,"aran","0")
        //! i makechange(current,"acdn","0")
        //! i makechange(current,"amcs","0")
        //! i makechange(current,"atar","Air,Dead,Enemy,Friend,Ground,Neutral")
    //! i end
    //! endexternalblock
//! endtextmacro

And this is what occurs:
attachment.php


EDIT: Did I forget the levels?
 

Attachments

  • asdfjklsjf.png
    asdfjklsjf.png
    23.5 KB · Views: 1,740
Level 31
Joined
Jul 10, 2007
Messages
6,306
->Did I forget the levels?

That you did... it's annoying... lemme remember how on earth it was supposed to be done.

Also, you should be using Lua Get Var, not a random id ;P.

Level is placed before value.

//! i makechange(current,"amcs", "1", "0")

; )

This is from omtest.lua
Code:
makechange(current, "Tip", 3, "Lame Level 3 Tooltip")

This should be your script (add your makechanges)
JASS:
//If running into an error, be sure that the lua scripts have been updated
//Since the update of this library, a few of the lua scripts were secretly modified : P

//LUA_JASS_IO: hiveworkshop.com/forums/jass-functions-413/snippet-lua_jass_io-177419/
//LUA_FIND_LINE: hiveworkshop.com/forums/jass-functions-413/snippet-lua_find_line-177418/
//LUA_TRIM: hiveworkshop.com/forums/jass-functions-413/snippet-lua_trim-177439/
//LUA_OBJECT_ID: hiveworkshop.com/forums/jass-functions-413/snippet-lua_object_id-176943/
//LUA_STRING_EXPLODE: hiveworkshop.com/forums/jass-functions-413/snippet-lua_string_explode-176944/
//LUA_JASS_GLOBALS: hiveworkshop.com/forums/submissions-414/system-lua_jass_globals-185917/
//LUA_GET_VAR_OBJECT: hiveworkshop.com/forums/submissions-414/snippet-lua_get_var_object-185944/


//! externalblock extension=lua ObjectMerger $FILENAME$
    //replace FILE_NAME with the name of the map
    //! runtextmacro LUA_JASS_IO("FILE_NAME")

    //////////////////////////////////////////////////////////////////////////////////
    //! runtextmacro LUA_FIND_LINE()
    //! runtextmacro LUA_STRING_TRIM()
    //! runtextmacro LUA_GET_OBJECT_ID()
    //! runtextmacro LUA_STRING_EXPLODE()
    //! runtextmacro LUA_JASS_GLOBALS()
    //! runtextmacro LUA_GET_VAR_OBJECT()
    
    //not sure what you are naming your var
    ///ABILITIES_RESURRECTION seems a little generic ; P
    //! i local id = getvarobject("AHre", "abilities", "ABILITIES_RESURRECTION")
    
    //! i createobject("AHre", id)
    //etc
//! endexternalblock
 
->Did I forget the levels?

That you did... it's annoying... lemme remember how on earth it was supposed to be done.

Also, you should be using Lua Get Var, not a random id ;P.

Yeah, I will. I just wanted to get it working first, lol.

JASS:
//! runtextmacro GenerateAbility("true")

//! textmacro GenerateAbility takes BOOL
    //! externalblock extension=lua ObjectMerger $FILENAME$
    //! i if "$BOOL$" == "true" then
        //! i setobjecttype("abilities")
        //! i createobject("AHre","ReSX")
        //! i makechange(current,"aher", "1", "0")
        //! i makechange(current,"acat", "1", "0")
        //! i makechange(current,"atat", "1", "0")
        //! i makechange(current,"Hre1", "1", "1")
        //! i makechange(current,"aare", "1", "0")
        //! i makechange(current,"aran", "1", "0")
        //! i makechange(current,"acdn", "1", "0")
        //! i makechange(current,"amcs", "1", "0")
        //! i makechange(current,"atar", "1", "Air,Dead,Enemy,Friend,Ground,Neutral")
    //! i end
    //! endexternalblock
//! endtextmacro
Here is the error now:
attachment.php
 

Attachments

  • asdfdfgfdg.png
    asdfdfgfdg.png
    23.7 KB · Views: 1,766
Whoops. Of course.

Works fine now, I'll move it to the template thingy.

EDIT:

JASS:
//! runtextmacro GenerateAbility("false")

//! textmacro GenerateAbility takes BOOL
    //! externalblock extension=lua ObjectMerger $FILENAME$
    //! i if "$BOOL$" == "true" then
        //! i setobjecttype("abilities")
        //! i createobject("AHre","ResX")
        //! i makechange(current,"anam","DumResurrection")
        //! i makechange(current,"aher","0")
        //! i makechange(current,"acat","")
        //! i makechange(current,"atat","")
        //! i makechange(current,"Hre1","1","1")
        //! i makechange(current,"aare","1","0")
        //! i makechange(current,"aran","1","0")
        //! i makechange(current,"acdn","1","0")
        //! i makechange(current,"amcs","1","0")
        //! i makechange(current,"atar","1","Air,Dead,Enemy,Friend,Ground,Neutral")
        
        //! i setobjecttype("units")
        //! i createobject("ushd","dumy")
        //! i makechange(current,"unam","Dummy")
        //! i makechange(current,"uabi","ResX,Aloc,Avul")
        //! i makechange(current,"ucbs","0")
        //! i makechange(current,"ucpt","0")
        //! i makechange(current,"umdl","none.mdl")
        //! i makechange(current,"usca","0.01")
        //! i makechange(current,"ushu","None")
        //! i makechange(current,"umvh","0")
        //! i makechange(current,"umvs","0")
        //! i makechange(current,"ufoo","0")
        //! i makechange(current,"umpi","100000")
        //! i makechange(current,"umpm","100000")
        //! i makechange(current,"umpr","1000")
    //! i end
    //! endexternalblock
//! endtextmacro

That is including the dummy unit now. I will probably move it to the template eventually, but I am too lazy atm.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
JASS:
//If running into an error, be sure that the lua scripts have been updated
//Since the update of this library, a few of the lua scripts were secretly modified : P

//LUA_JASS_IO: hiveworkshop.com/forums/jass-functions-413/snippet-lua_jass_io-177419/
//LUA_FIND_LINE: hiveworkshop.com/forums/jass-functions-413/snippet-lua_find_line-177418/
//LUA_TRIM: hiveworkshop.com/forums/jass-functions-413/snippet-lua_trim-177439/
//LUA_OBJECT_ID: hiveworkshop.com/forums/jass-functions-413/snippet-lua_object_id-176943/
//LUA_STRING_EXPLODE: hiveworkshop.com/forums/jass-functions-413/snippet-lua_string_explode-176944/
//LUA_JASS_GLOBALS: hiveworkshop.com/forums/submissions-414/system-lua_jass_globals-185917/
//LUA_GET_VAR_OBJECT: hiveworkshop.com/forums/submissions-414/snippet-lua_get_var_object-185944/


//! externalblock extension=lua ObjectMerger $FILENAME$
    //replace FILE_NAME with the name of the map
    //! runtextmacro LUA_JASS_IO("FILE_NAME")

    //////////////////////////////////////////////////////////////////////////////////
    //! runtextmacro LUA_FIND_LINE()
    //! runtextmacro LUA_STRING_TRIM()
    //! runtextmacro LUA_GET_OBJECT_ID()
    //! runtextmacro LUA_STRING_EXPLODE()
    //! runtextmacro LUA_JASS_GLOBALS()
    //! runtextmacro LUA_GET_VAR_OBJECT()
    
    //not sure what you are naming your var
    ///ABILITIES_RESURRECTION seems a little generic ; P
    //! i local rez = getvarobject("AHre", "abilities", "ABILITIES_REVIVE_UNIT_RESURRECTION")
        //! i createobject("AHre",rez)
        //! i makechange(current,"anam","DumResurrection")
        //! i makechange(current,"aher","0")
        //! i makechange(current,"acat","")
        //! i makechange(current,"atat","")
        //! i makechange(current,"Hre1","1","1")
        //! i makechange(current,"aare","1","0")
        //! i makechange(current,"aran","1","0")
        //! i makechange(current,"acdn","1","0")
        //! i makechange(current,"amcs","1","0")
        //! i makechange(current,"atar","1","Air,Dead,Enemy,Friend,Ground,Neutral")

    //! i local dummy = getvarobject("ushd", "units", "UNITS_REVIVE_UNIT_DUMMY")
        //! i createobject("ushd",dummy)
        //! i makechange(current,"unam","Dummy")
        //! i makechange(current,"uabi","'" .. rez .. "',Aloc,Avul")
        //! i makechange(current,"ucbs","0")
        //! i makechange(current,"ucpt","0")
        //! i makechange(current,"umdl","none.mdl")
        //! i makechange(current,"usca","0.01")
        //! i makechange(current,"ushu","None")
        //! i makechange(current,"umvh","0")
        //! i makechange(current,"umvs","0")
        //! i makechange(current,"ufoo","0")
        //! i makechange(current,"umpi","100000")
        //! i makechange(current,"umpm","100000")
        //! i makechange(current,"umpr","1000")
//! endexternalblock
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Ty! Tomorrow I'll just test everything, and if it works, then I'll update the first post with everything.

Just be sure you pick 2 var names you like and make the FILE_NAME the name of your file in the test.

JASS:
//! runtextmacro LUA_JASS_IO("FILE_NAME")
//! i local rez = getvarobject("AHre", "abilities", "ABILITIES_REVIVE_UNIT_RESURRECTION")
//! i local dummy = getvarobject("ushd", "units", "UNITS_REVIVE_UNIT_DUMMY")

This script doesn't support private vars ;P

edit
Also, obv with LUA_FILE_HEADER, the above scripts should be easier to write : D.

edit
This is wrong
Moving a corpse is impossible, lol. Thus, I couldn't do that technique. :( So, I had to resort back to my old technique, which seems to work fine.

You can move corpses just fine, meaning you need to implement the stuff I mentioned to further stability >.>

Proof!
JASS:
struct tester extends array
    private static unit u2
    
    private static method run takes nothing returns nothing
        call SetUnitX(u2, WorldBounds.centerX)
        call SetUnitY(u2, WorldBounds.centerY)
    endmethod
    private static method onInit takes nothing returns nothing
        local unit u = CreateUnit(Player(0), 'hpea', WorldBounds.centerX, WorldBounds.centerY, 0)
        set u2 = CreateCorpse(Player(0), 'hfoo', WorldBounds.maxX, WorldBounds.maxY, 0)
        
        call TimerStart(CreateTimer(), 1, false, function thistype.run)
    endmethod
endstruct
 
Last edited:
edit
This is wrong


You can move corpses just fine, meaning you need to implement the stuff I mentioned to further stability >.>

Proof!
JASS:
struct tester extends array
    private static unit u2
    
    private static method run takes nothing returns nothing
        call SetUnitX(u2, WorldBounds.centerX)
        call SetUnitY(u2, WorldBounds.centerY)
    endmethod
    private static method onInit takes nothing returns nothing
        local unit u = CreateUnit(Player(0), 'hpea', WorldBounds.centerX, WorldBounds.centerY, 0)
        set u2 = CreateCorpse(Player(0), 'hfoo', WorldBounds.maxX, WorldBounds.maxY, 0)
        
        call TimerStart(CreateTimer(), 1, false, function thistype.run)
    endmethod
endstruct

Okay, yeah you are right. However, when I move it to world bounds, the corpse won't move. (or at least it doesn't seem to move) It works if I put it anywhere else though. I guess this means I'll have to have the user define a SafeX/SafeY on the map, otherwise it won't work. Or should I just stick with my current method?

EDIT: This is the code that does not work:
JASS:
library ReviveUnit requires WorldBounds
    globals
        private constant integer UNITS_DUMMY = 'dumy'
        private constant integer ABILITIES_DUMRESURRECTION = 'ResX'
        
        private unit reviver 
    endglobals
    
    private module ReviveInitialization
        private static method onInit takes nothing returns nothing
            set reviver = CreateUnit(Player(15),UNITS_DUMMY,WorldBounds.maxX,WorldBounds.maxY,0)
        endmethod
    endmodule
    
    struct Revive extends array
        static method Unit takes unit whichUnit returns nothing
            local real x = GetUnitX(whichUnit)
            local real y = GetUnitY(whichUnit)
            if IsUnitType(whichUnit,UNIT_TYPE_HERO) == true then
                call ReviveHero(whichUnit,x,y,false)
            else
                call SetUnitX(whichUnit,WorldBounds.maxX)
                call SetUnitY(whichUnit,WorldBounds.maxY)
                call IssueImmediateOrderById(reviver,852094)
                call SetUnitX(whichUnit,x)
                call SetUnitY(whichUnit,y)
            endif
        endmethod
        
        implement ReviveInitialization
    endstruct
endlibrary

However, having this instead works fine:
JASS:
set reviver = CreateUnit(Player(15),UNITS_DUMMY,0,0,0) //(0,0) instead of (maxX,maxY)
//....
call SetUnitX(whichUnit,0) //0 instead of maxX
call SetUnitY(whichUnit,0) //0 instead of maxY
 
Updated. I should really rename it to revive corpse, but whatever, I'll make fixes soon.

Then do WorldBounds-128 or something to ensure its within the max possible camera bounds.

Apparently it doesn't work for anything from GetRectMaxX(bj_mapInitialPlayableArea) and above. (same for Y)

So I set it to that minus 1. It works sometimes if I don't have the minus, but it fails occasionally so I had to add that.

Right now I need to iron out some bugs, and to do that I might have to switch to ancestral spirit. Currently this doesn't support reviving buildings, exploded units, nor decayed corpses, so yeah this is currently a ReviveCorpse(unit) instead of a revive unit.

EDIT: I'm still going to update this, but I just wanted to update the first post with the latest version.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Purge, it's impossible to revive decayed corpses because at that point the unit no longer exists. Unit decay is akin to RemoveUnit.

The same goes for exploded units and destroyed buildings.

Ancestral spirit only repairs buildings right? Once a building is destroyed, it's gone >.>.



Also your Lua generation is outdated = |... textmacros aren't used anymore except for LUA_FILE_HEADER. Check UnitIndexer, UnitEvent to see examples =).

UnitIndexer
http://www.hiveworkshop.com/forums/submissions-414/snippet-lua_get_var_object-185944/
http://www.hiveworkshop.com/forums/submissions-414/snippet-lua_file_header-186775/
JASS:
//! externalblock extension=lua ObjectMerger $FILENAME$
    //! runtextmacro LUA_FILE_HEADER()
    //! i dofile("GetVarObject")
    
    //! i local id = getvarobject("Adef", "abilities", "ABILITIES_UNIT_INDEXER", true)
    
    //! i createobject("Adef", id)
    //! i makechange(current, "anam", "Unit Indexing")
    //! i makechange(current, "ansf", "(Unit Indexing)")
    //! i makechange(current, "aart", "")
    //! i makechange(current, "arac", "0")
    
    //! i updateobjects()
//! endexternalblock

Easier no?

Also, the new convention is to include links to all scripts used within your lua script for painless installation as shown above.

For your convenience, I've updated your installation script for you.
JASS:
//! externalblock extension=lua ObjectMerger $FILENAME$
    //! runtextmacro LUA_FILE_HEADER()
    //! i dofile("GetVarObject")

    //! i local rez = getvarobject("AHre", "abilities", "ABILITIES_REVIVE_UNIT_RESURRECTION", true)
        //! i createobject("AHre",rez)
        //! i makechange(current,"anam","DumResurrection")
        //! i makechange(current,"aher","0")
        //! i makechange(current,"acat","")
        //! i makechange(current,"atat","")
        //! i makechange(current,"Hre1","1","1")
        //! i makechange(current,"aare","1","0")
        //! i makechange(current,"aran","1","0")
        //! i makechange(current,"acdn","1","0")
        //! i makechange(current,"amcs","1","0")
        //! i makechange(current,"atar","1","Air,Dead,Enemy,Friend,Ground,Neutral")

    //! i local dummy = getvarobject("ushd", "units", "UNITS_REVIVE_UNIT_DUMMY", true)
        //! i createobject("ushd",dummy)
        //! i makechange(current,"unam","Dummy")
        //! i makechange(current,"uabi","'" .. rez .. "',Aloc,Avul")
        //! i makechange(current,"ucbs","0")
        //! i makechange(current,"ucpt","0")
        //! i makechange(current,"umdl","none.mdl")
        //! i makechange(current,"usca","0.01")
        //! i makechange(current,"ushu","None")
        //! i makechange(current,"umvh","0")
        //! i makechange(current,"umvs","0")
        //! i makechange(current,"ufoo","0")
        //! i makechange(current,"umpi","100000")
        //! i makechange(current,"umpm","100000")
        //! i makechange(current,"umpr","1000")

        //! i updateobjects()
//! endexternalblock

Be sure to update that in your first post asap =).
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Thanks, I forgot that changes were made, I haven't been looking at the posts enough. ;D

It's better though right?

Also in the demo map, it'd probably be coolest if you had a row of units. When you select a unit, it creates a corpse of that unit at a designated location (auto start an ability so the user can click where). When you hit escape, it auto starts an ability so you can select a corpse to revive (enum to find the corpse).

From here, you can use http://www.hiveworkshop.com/forums/jass-functions-413/string-parser-170574/ to enhance it further.

You can literally do this in chat (spaces required)
JASS:
set u = CreateUnit //pass in parameters or do below
                          //create for calling player
//select a unit for selection type
//select a point to create unit at

call KillUnit(u) //kill your unit
call ReviveUnit(u) //revive it
 
Lol updated again. I had to resort back to my old technique of moving the dummy to the unit, instead of all the units to the dummy. It requires WorldBounds again.

The reason why is because of creeps. (arghh) When I move them to the dummy and then revive them, and then move them back, it works fine. But if I say attack them and then run, they will run back to the dummy. (After they are revived, that kind of "changes" their start position to wherever they were revived) So they run back and that is their new home. Thus, I had to change it again. :ogre_icwydt:

EDIT: Nvm, not creeps. Units in general. If you attack them and then run away, they'll run back to the position of the reviver.
 
Found a problem ;D

private constant integer UNITS_REVIVE_UNIT_DUMMY = 'dumy'


That would create a null unit, unless you just happen to have a unit using the 'dumy' id. You should fix as that'll shadow the correct UNITS_REVIVE_UNIT_DUMMY variable.

Whoops, fixed.

Also fixed a LUA error. I changed this:
JASS:
        //! i makechange(current,"uabi","'" .. rez .. "',Aloc,Avul")
To this:
JASS:
        //! i makechange(current,"uabi","" .. rez .. ",Aloc,Avul")

Because otherwise it wouldn't add the ability to the unit. (It would look for 'A!! rawcode)
 
//! i makechange(current,"uabi","" .. rez .. ",Aloc,Avul") is still wrong. Notice your "" ; P

It should be current,"uabi", rez .. ",Aloc,Avul"

You can try that if you want but it doesn't seem to work. (the one I posted works fine though) The data for abilities is inclusive of rez, so it would be " A , B , C " and then the " .. var .. " is just to read it. ;P
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Delete this line and it will be good to go.

private constant integer UNITS_REVIVE_UNIT_DUMMY = 'u!!!'


Remember that the id is dynamic, so it could be anything. Just because it happens to be 'u!!!' in your map doesn't mean that it'll be the same in another map.

Furthermore, the variable is automatically imported into the map >.>. All this line does is overshadow the variable that contains the right value.
 
Delete this line and it will be good to go.

private constant integer UNITS_REVIVE_UNIT_DUMMY = 'u!!!'


Remember that the id is dynamic, so it could be anything. Just because it happens to be 'u!!!' in your map doesn't mean that it'll be the same in another map.

Furthermore, the variable is automatically imported into the map >.>. All this line does is overshadow the variable that contains the right value.

Whoops. I must've had that left over from before. Removed. Thanks. :D
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
It has to do with the lua links above it. When JASS or variables are generated (as is the case here), the stuff has to be installed for the map. Purge should probably not be using the lua scripts in the demo map, but rather just have some arbitrary id and a pre-gen'd object. The demo map should be able to be run immediately w/o having to install stuff.

Here that Purge? : P
 
Lol, sorry. I ignore updating the demo map at times. I saved with the header in it and I was too lazy to remove it. :p I'll update it in a little bit.

EDIT: Okay, I updated it. It is still the boring old test map though. :p However, now once all the units are alive, it will kill them all again. So spam ESC to your heart's delight. :D
 
What do you think of changing the script to this:

JASS:
library ReviveUnit initializer Init
    //***********************************************
    //       REVIVE UNIT
    //***********************************************
    //  - This library allows you to revive units in a similar fashion to heroes.
    //  - This library retains the unit's previous handle ID
    //  - This library retains the unit's facing
    //  - It will fail if the unit has decayed already
    //  - It will fail if the unit has exploded
    //  - It will fail on ethereals. (essentially anything that doesn't leave a corpse)
    //  - It will fail on buildings
    
    //  Automatic Generation:
    //      - Save your map and restart it, then uncomment the object merger line below.
    //  Manual Implementation:
    //    - Copy the spell named "Resurrection"
    //    - Paste it in your map
    //    - Copy this trigger and its contents, and paste it in your map
    //    - Modify UNITS_REVIVE_UNIT_DUMMY to the rawcode of the dummy unit your are using
    
    //  Function:
    //      Revive.Unit(whichUnit)
    //          - Revives some dead corpse. Returns whether or not the unit was revived.
    
    //***********************************************    

    globals
        // Configuration
        private constant integer UNITS_REVIVE_UNIT_DUMMY            = 'e000' // any dummy (preferably xebasic's)
        private constant integer ABILITIES_REVIVE_UNIT_RESURRECTION = 'URez'
        
        //! external ObjectMerger w3a AHre URez anam "Dummy Resurrection" ansf "(ReviveUnit)" acat "" arac 0 atat "" amcs 1 0 acdn 1 0 aher 0 Hre1 1 1 aare 1 0 aran 1 0 atar 1 "Air, Dead, Enemy, Friend, Ground, Neutral"
            
        // Don't edit below this line
        private unit reviver 
        private real rx
        private real ry
    endglobals
    
    struct Revive extends array
    
        static method Hero takes unit whichHero returns boolean
            return ReviveHero(whichHero, GetUnitX(whichHero), GetUnitY(whichHero), false)
        endmethod
        
        static method Unit takes unit whichUnit returns boolean
            local real x = GetUnitX(whichUnit)
            local real y = GetUnitY(whichUnit)
            local boolean bb = true
            if IsUnitType(whichUnit,UNIT_TYPE_HERO) == true then
                call ReviveHero(whichUnit,x,y,false)
            else
                call SetUnitX(whichUnit,rx)
                call SetUnitY(whichUnit,ry)
                set bb = IssueImmediateOrderById(reviver,852094)
                call SetUnitX(whichUnit,x)
                call SetUnitY(whichUnit,y)
            endif
            return bb
        endmethod
        
    endstruct
    
    function ReviveUnit takes unit whichUnit returns boolean
        return Revive.Unit(whichUnit) // unfortunately doesn't inline
    endfunction
    
    private function Init takes nothing returns nothing
        set rx = GetRectMaxX(bj_mapInitialPlayableArea)-1
        set ry = GetRectMaxY(bj_mapInitialPlayableArea)-1
        set reviver = CreateUnit(Player(15),UNITS_REVIVE_UNIT_DUMMY,rx,ry,0)
        call UnitAddAbility(reviver, ABILITIES_REVIVE_UNIT_RESURRECTION)
    endfunction

endlibrary
and if not, you might want to at least utilize the object merger line
 
Updated to 2.0.0.0. The API was changed. Now it just has a function API call ReviveUnit(unit). A struct API doesn't make much sense since it isn't really an object.

As for the method: now the dummy moves to the unit's position, and then back. Pro: now the unit won't fire enter/leave region events (the dummy still will, but that is easier to filter out), and he'll maintain the same position when resurrected. Con: there is a chance that the wrong unit will be resurrected iff (1) there are > 1 units on the same exact coordinates (2) they both have no pathing. The chances of that are very small, so I figure it isn't worth even addressing. I'd rather prevent firing external events due to the system.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
I see! Back to the roots where IsUnitType(u, UNIT_TYPE_HERO) was IsUnitType(u, UNIT_TYPE_HERO) == true.

Dalvengyr submitted a system with the same functionality in the spell section 2 weeks ago. I guess he wasn't aware of the JASS section back then.
I'm going to pm him and discuss what we're gonna do with his submission.

I required more savety checks before moving the reviver and asked him to add:
  • IsUnitType(toRevie, UNIT_TYPE_DEAD) --> Is the unit you attempt to revive actually dead (debug only)
  • GetUnitTypeId(toRevive) != 0 --> Does this corpse actually rot somewhere or is it removed. Does filter out invalid units. (debug only)
Those checks are not important, because it doesn't minimize the chance of reviving the wrong unit. (The chance of reviving the wrong unit is close to zero.)
I'm already waiting for his wave of anger towards me :/.

The dummy doesn't need 'Avul' since you already use 'Aloc', but it's not a big deal.
 
I see! Back to the roots where IsUnitType(u, UNIT_TYPE_HERO) was IsUnitType(u, UNIT_TYPE_HERO) == true.

haha yeah. I don't know whether that bug still exists or not. Rather than looking it up, I just decided to keep it as == true. Laziness on my part. :p

BPower said:
Those checks are not important, because it doesn't minimize the chance of reviving the wrong unit. (The chance of reviving the wrong unit is close to zero.)
I'm already waiting for his wave of anger towards me :/.

The dummy doesn't need 'Avul' since you already use 'Aloc', but it's not a big deal.

I suppose I could add extra checks to it. I'll think about it--maybe it could be useful for error reporting. But it is so pretty in its current state. ;-;

And yeah, I suppose the dummy doesn't need 'Avul'. But I like invulnerability. It makes my dummies sleep well at night.
 
I could, but I don't really want backwards compatibility. I just don't like having it named Revive.Unit. It is (1) pascal case, which doesn't follow my normal convention for struct methods (2) it doesn't make sense for "Revive" to be an object. It is kind of abusing OOP syntax for no good reason.

Maybe I should add it but just not include it in the documentation, so that people won't use it. I still don't like it being there. :p Do you think I should add it anyway?
 
Top