• 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.

Reviving unit via trigger

Level 29
Joined
Sep 26, 2009
Messages
2,595
resurrect retains original unit's handleId, so I think it is effectively a revival rather than replacement.
Wouldn't it risk failure if two corpses are on top of each other?
It may be worth trying to pick all corpses nearby, hide them except for the corpse you are interested in, revive that single corpse and then unhide other corpses.
 
Level 12
Joined
Nov 13, 2010
Messages
277
i was thinking that you can detect the unit`s death and store its properties and then revive the unit ad the same location

it can be something like

Code:
Event:
- Unit - A unit dies

Conditions:
- (Unit-type of (Triggering unit)) is not a Hero

Actions:
- Set Temp_Loc = (Position of (Triggering unit))
- Set Temp_UnitType = (Unit-type of (Triggering unit))
- Set Temp_Owner = (Owner of (Triggering unit))

- Wait x seconds

- Unit - Replace (Triggering unit) with a Temp_UnitType using The new unit’s default life and mana
- Custom script: call RemoveLocation(udg_Temp_Loc)
 
Last edited:
ReplaceUnit is actually CreateUnit behind the scene based on this doc: https://lep.duckdns.org/jassbot/doc/ReplaceUnitBJ

I think the closest I can consider at the moment would be @Pyrogasm and @Nichilus suggestions combined. Still open for ideas on how to handle the issue.

The goal is to have a resurrection-esque ability executed via triggers, since CreateUnit does not retain data from AddUnitAbility and MakeUnitAbilPermanent combo.
 
Level 12
Joined
Nov 13, 2010
Messages
277
we can hide unit instead of killing and creating a new one

Code:
Event:
- Unit - A unit dies

Conditions:
- (Unit-type of (Triggering unit)) is not a Hero

Actions:
- Set Temp_Unit = (Triggering unit)
- Set Temp_Loc = (Position of (Triggering unit))
- Set Temp_HP = (Life of (Triggering unit))
- Set Temp_MP = (Mana of (Triggering unit))

- Unit - Hide (Triggering unit)
- Unit - Pause (Triggering unit)
- Wait x seconds

step 2

Actions:
- Unit - Unpause (Temp_Unit)
- Unit - Move (Temp_Unit) instantly to Temp_Loc
- Unit - Set life of (Temp_Unit) to Temp_HP
- Unit - Set mana of (Temp_Unit) to Temp_MP
- Unit - Unhide (Temp_Unit)

(and optional we can add a Effect)
- Special Effect - Create resurrection effect at Temp_Loc
- Custom script: call RemoveLocation(udg_Temp_Loc)

it can also be made with Unit - Revive (x Unit) at x with x% life and x% mana
 
Last edited:

Rheiko

Spell Reviewer
Level 26
Joined
Aug 27, 2013
Messages
4,214
I believe Reincarnation and Animate Dead work similarly. Resurrection is still your best option. I don't think there's any other way.

we can hide unit instead of killing and creating a new one

Code:
Event:
- Unit - A unit dies

Conditions:
- (Unit-type of (Triggering unit)) is not a Hero

Actions:
- Set Temp_Unit = (Triggering unit)
- Set Temp_Loc = (Position of (Triggering unit))
- Set Temp_HP = (Life of (Triggering unit))
- Set Temp_MP = (Mana of (Triggering unit))

- Unit - Hide (Triggering unit)
- Unit - Pause (Triggering unit)
- Wait x seconds

step 2

Actions:
- Unit - Unpause (Temp_Unit)
- Unit - Move (Temp_Unit) instantly to Temp_Loc
- Unit - Set life of (Temp_Unit) to Temp_HP
- Unit - Set mana of (Temp_Unit) to Temp_MP
- Unit - Unhide (Temp_Unit)

(and optional we can add a Effect)
- Special Effect - Create resurrection effect at Temp_Loc
- Custom script: call RemoveLocation(udg_Temp_Loc)
Unfortunately, this does not revive the unit either. You could try to prevent the unit from dying (fake its death) but then again, it does not actually revive the unit.
 
Level 12
Joined
Nov 13, 2010
Messages
277
I believe Reincarnation and Animate Dead work similarly. Resurrection is still your best option. I don't think there's any other way.


Unfortunately, this does not revive the unit either. You could try to prevent the unit from dying (fake its death) but then again, it does not actually revive the unit.
is it the same with Unit - Revive (x Unit) at x with x% life and x% mana then ? of so then iam out of iders

because if it does work we can do,
Code:
Event:
- Unit - A unit dies

Conditions:
- (Unit-type of (Triggering unit)) is not a Hero

Actions:
- Set Temp_Unit = (Triggering unit)
- Set Temp_Loc = (Position of (Triggering unit))
- Set Temp_HP = (Life of (Triggering unit))
- Set Temp_MP = (Mana of (Triggering unit))

- Unit - Remove (Triggering unit) from the game 
- Wait x seconds

Step 2
Actions:
- Unit - Revive (Temp_Unit) at Temp_Loc with Temp_HP% life and Temp_MP% mana
- Special Effect - Create resurrection effect at Temp_Loc
- Custom script: call RemoveLocation(udg_Temp_Loc)

but if also dont work then iam out of iders
 
Last edited:
is it the same with Unit - Revive (x Unit) at x with x% life and x% mana then ? of so then iam out of iders

because if it does work we can do,
Code:
Event:
- Unit - A unit dies

Conditions:
- (Unit-type of (Triggering unit)) is not a Hero

Actions:
- Set Temp_Unit = (Triggering unit)
- Set Temp_Loc = (Position of (Triggering unit))
- Set Temp_HP = (Life of (Triggering unit))
- Set Temp_MP = (Mana of (Triggering unit))

- Unit - Remove (Triggering unit) from the game
- Wait x seconds

Step 2
Actions:
- Unit - Revive (Temp_Unit) at Temp_Loc with Temp_HP% life and Temp_MP% mana
- Special Effect - Create resurrection effect at Temp_Loc
- Custom script: call RemoveLocation(udg_Temp_Loc)

but if also dont work then iam out of iders
There's no Unit - Revive action in GUI, and no JASS nor LUA native for it either. Removing unit also permanently removes said unit and all of the relevant data of said unit from the game.

To give an idea of why I specifically need a revival, in the following test map, I give Footman a Critical Strike ability via trigger and then kill him using Kill Unit. When you use Resurrection, you notice said Critical Strike ability remains. Replace Critical Strike with all possible abilities to be added to that unit, which is not logical to deal with using CreateUnit.

The core issue is that I want the unit to retain all information, from abilities to trigger data referencing to said unit, to persist after revival. Why not hero? Because this is for a spell that will be utilized in a map where there are non-heroes and this spell is meant as a form of resurrection ability with target point for non-heroes (target unit is not viable with dead unit, last I remembered).
I believe Reincarnation and Animate Dead work similarly. Resurrection is still your best option. I don't think there's any other way.
Based on the responses here, I have to concur. There's no mean of mimicking resurrection directly via triggers. I also investigate Spell System, but apparently it uses the real resurrection ability for one of the spells which I thought might have a solution to my issue. I might need to check if it is possible to add an ability to a dead unit and then give it reincarnation to self-resurrect as an alternative.
 

Attachments

  • SpellTestMap131Base.w3x
    21.6 KB · Views: 2

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
Regarding the Resurrection solution, you could set it's Targets Allowed to require an unused Classification and Add/Remove that to the Corpses as needed. That might be better than Hiding a corpse since that would likely interrupt the Order of something like Cannibalize or Raise Dead.

Edit, some other ideas:

1) Fake the entire Death system in your map. Detect lethal damage -> Hide "dead" unit -> Create a Special Effect that mimics the "dead" unit and it's death animation -> Create a corpse at it's position if necessary (you could even link the corpse to the "dead" unit). Fully restore and unhide the "dead" unit when it "revives".

2) Use a Unit Indexer that doesn't recycle unused Custom Values (or does so in a very controlled manner). Use that Custom Value as the key for all of your data tracking needs. Now whenever you want to transfer data from a Dead unit to a New unit you simply pass over the Custom Value.

Then for tracking the Abilities, you can use:
A Hashtable that stores each Unit-Type and all of their important "custom" information, like starting Abilities.
A set of custom "Add" and "Remove" Ability functions which track the unit's abilities in another Hashtable (one for individual units as opposed to unit-types).

That way when it comes time to Revive something you can instead create a new unit, transfer the dead unit's custom value over to it, map the new unit to a central Unit Array (ie: UDexUnits in Bribe's unit indexer), and transfer the dead unit's abilities over as well. Regarding issues, at the moment all I can think of would be Unit Groups. It's possible to avoid them entirely, if need be (arrays that use custom values come to mind).

Obviously these are more "design your entire map around it" solutions and not very practical.
 
Last edited:
so the goal is to simulate resurrection ability via triggers without removing or recreating the unit ?
To simplify, yes. The reason is that resurrection (and by extension animate dead) retains all unit data as shown in my example test map.

For everyone involved, I want to inform that I am open to all patch solutions, up to the current Reforged patch. Maybe someone found some obscure thing in the recent patches that I am not aware of, so I'll just drop this info.

Regarding the Resurrection solution, you could set it's Targets Allowed to require an unused Classification and Add/Remove that to the Corpses as needed. That might be better than Hiding a corpse since that would likely interrupt the Order of something like Cannibalize or Raise Dead.
Well, depending on the map, Suicidal classification comes first in mind since only sapper uses them. It's hard for a generic use-case to pick one classification that can be our valid target for Resurrection.

---

Also, I just tested and apparently it is possible to add abilities to a corpse. I am just dropping this info in case anyone finds it useful. It helps me get some ideas on filtering the corpses I want to revive from a cluster of corpses, though still hard to deal with the resurrect aspect.

I think it would be nice if there's a pre-resurrect event that detects before the unit is fully resurrected to detect if it matches our criteria... One solution I can think of without playing with classification (which basically limits that classification out) is to revive the units and then kill the units not matching criteria right after with KillUnit... might bloat scores though...

EDIT:

Dropping the spell description I plan to work that is related to this question.
Target an area and raises the shadow of corpses within the area. Always succeed on level 1/2/3 units. Higher level units have 10/20/30% chance for success, with up to 3 attempts per corpse. Created shadows are permanent. When a shadow dies, drain mana equals to 30/20/10% of maximum health of killed shadow to revive them next to the caster, but permanently died if caster doesn't have mana to revive them. Cannot be used on workers and heroes.
Shadow here means the exact copy of the unit with all of their previous state intact. Revive is that exact shadow being revived again (I can work with the relocation, though now I have another question on that...)
 
Regarding the Resurrection solution, you could set it's Targets Allowed to require an unused Classification and Add/Remove that to the Corpses as needed. That might be better than Hiding a corpse since that would likely interrupt the Order of something like Cannibalize or Raise Dead.

Edit, some other ideas:

1) Fake the entire Death system in your map. Detect lethal damage -> Hide "dead" unit -> Create a Special Effect that mimics the "dead" unit and it's death animation -> Create a corpse at it's position if necessary (you could even link the corpse to the "dead" unit).

2) Use a Unit Indexer that doesn't recycle unused Custom Values (or does so in a very controlled manner). Use that Custom Value as the key for all of your data tracking needs. Now whenever you want to transfer data from a Dead unit to a New unit you simply pass over the Custom Value.

Then for tracking the Abilities, you can use:
A Hashtable that stores each Unit-Type and all of their important "custom" information, like starting Abilities.
A set of custom "Add" and "Remove" Ability functions which track the unit's abilities in another Hashtable (one for individual units as opposed to unit-types).

That way when it comes time to Revive something you can instead create a new unit, transfer the reviving unit's custom value over to it, map the new unit to a central Unit Array (ie: UDexUnits in Bribe's unit indexer), and transfer the reviving unit's abilities over as well. Regarding issues, at the moment all I can think of would be Unit Groups. It's possible to avoid them entirely, if need be (arrays that use custom values come to mind).

Obviously these are more "design your entire map around it" solutions and not very practical.
Had to double post so notifications come your way.

I think this approach would be something that I think suitable for a per map basis as you mentioned. It is not suitable when working for a generic situation where it should be as flexible as possible. I like the idea of an entire fake death system though. This discussion makes me think more about the entire death system than I ever did :D
 
Level 12
Joined
Nov 13, 2010
Messages
277
i try to make a spell for your map but did not work peahps iam to sleppy to make right xd but i give up for now but you can try a look.

then funny think is that it dos make the Special Effect where the unit die but dit not spawn it back
 

Attachments

  • SpellTestMap131Base.w3x
    25 KB · Views: 2

Rheiko

Spell Reviewer
Level 26
Joined
Aug 27, 2013
Messages
4,214
Wouldn't it risk failure if two corpses are on top of each other?
I wanted to suggest this earlier

But after a few testing, when the unit's corpses are stacked on top of each other in the same coordinates, it does fail.
In my test, I tried killing some units and then move them to (0,0) using SetUnitX/Y resulting in their corpses getting on top of each other.
I waited for 2 seconds (I have tried PolledWait, TSA, and Timer) and then call ReviveUnit. The results were odd, first attempt I got 5 out of 8 resurrected, second attempt I got 4 out of 5 resurrected. I have no idea why.

So I made a little bit of adjustment to the code. Instead of moving the dummy to the target, I move the target to the dummy and move them back to their original position. Of course, this comes with a con: the unit will fire enter/leave region events if there's any. There's also another problem with this:
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.
But I solved it thanks to this post: How To Stop Neutral Units From Returning To Spawn Point

After the adjustment I made, in my testing, it just cannot fail. You can probably consider this option. Feel free to give a try, I attached both the original (slightly modified for testing purpose, you can download the "original" original from the link I provided earlier instead) and the adjusted demo map in this post.
 

Attachments

  • ReviveUnit.w3x
    20.3 KB · Views: 0
  • [Snippet] - ReviveUnit adjusted.w3x
    20.2 KB · Views: 2
Last edited:
I am curious if the data for Game Cache does hold for multiplayer, because my memory recall they don't function in multiplayer hence the necessity of Save/Load Systems. It would be a great alternative, albeit there might be hidden drawbacks that needs to be tested in entirety, to the ReviveUnit that @Rheiko provided in the post prior.

For now, I'll go with the ReviveUnit that Rheiko has provided since it should solve the issue I have at the moment and this can be considered solved for my needs, though it might be worth exploring on the matter of reviving unit further if anyone wants to. Thanks everyone for the help!
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
I am curious if the data for Game Cache does hold for multiplayer, because my memory recall they don't function in multiplayer hence the necessity of Save/Load Systems. It would be a great alternative, albeit there might be hidden drawbacks that needs to be tested in entirety, to the ReviveUnit that @Rheiko provided in the post prior.

For now, I'll go with the ReviveUnit that Rheiko has provided since it should solve the issue I have at the moment and this can be considered solved for my needs, though it might be worth exploring on the matter of reviving unit further if anyone wants to. Thanks everyone for the help!
You probably want to comment out the highlighted section of the code, or at least wrap it in an ITE that checks that the unit is actually owned by a Neutral player:
vJASS:
    function ReviveUnit takes unit u returns boolean
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local player p = GetOwningPlayer(u)
        local boolean success
     
        if IsUnitType(u, UNIT_TYPE_HERO) == true then
            return ReviveHero(u, x, y, false)
        else
            call SetUnitX(u, rx)
            call SetUnitY(u, ry)
            set success = IssueImmediateOrderById(reviver, 852094)
            call SetUnitX(u, x)
            call SetUnitY(u, y)

            // >>> ISSUES HERE <<<
            //  Prevent units to run back towards the resurrection spot
            call SetUnitOwner(u, Player(0), false)
            call SetUnitCreepGuard(u, false)
            call RemoveGuardPosition(u)
            call SetUnitOwner(u, p, true)
            ///////////////////////
        endif
     
        return success
    endfunction
^ This does nothing on non-Neutral units and will likely cause unwanted side effects. In your map's case it may be entirely unwanted. Also, the function leaks a Player (p needs to be nulled).

Lastly, the Revived units stack on top of one another, I suggest Ordering them to Stop as well:
vJASS:
    function ReviveUnit takes unit u returns boolean
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local boolean success
   
        if IsUnitType(u, UNIT_TYPE_HERO) == true then
            return ReviveHero(u, x, y, false)
        else
            call SetUnitX(u, rx)
            call SetUnitY(u, ry)
            set success = IssueImmediateOrderById(reviver, 852094)
            call SetUnitX(u, x)
            call SetUnitY(u, y)
            call IssueImmediateOrder(u, "stop") // Replace with Integer id
        endif

        return success
    endfunction
Unsure if the Order comes too early, may need to issue it 1 frame later or in response to an Event.
 
Last edited:

Rheiko

Spell Reviewer
Level 26
Joined
Aug 27, 2013
Messages
4,214
^ This does nothing on non-Neutral units and will likely cause unwanted side effects. In your map's case it may be entirely unwanted. Also, the function leaks a Player (p needs to be nulled).
It does work for both neutral units and non-Neutral units. At least it does in the version I was testing it (1.27 and 1.31). However, I can't say for sure how it behaves in newer patches. Comment out that code and try to kill neutral units / non-Neutral units, wait for it to get resurrected, then attack it and run to the edge of the map, it will follow you but after a while, it will return to top right corner (location where it got resurrected) instead of to the center (location before it got resurrected). This will not happen with that code around.

Lastly, the Revived units stack on top of one another, I suggest Ordering them to Stop as well:
Already tried it. Didn't help with the issue.

I will probably just revise it into something like this:
vJASS:
function ReviveUnit takes unit u returns boolean
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local boolean success
        local player p
       
        if IsUnitType(u, UNIT_TYPE_HERO) == true then
            return ReviveHero(u, x, y, false)
        else           
            set p = GetOwningPlayer(u)

            call SetUnitX(u, rx)
            call SetUnitY(u, ry)
            set success = IssueImmediateOrderById(reviver, 852094)
            call SetUnitX(u, x)
            call SetUnitY(u, y)
            call IssueImmediateOrder(u, "stop")
                       
            //  Prevent units to run back towards the resurrection spot
            call SetUnitOwner(u, Player(0), false)
            call SetUnitCreepGuard(u, false)
            call RemoveGuardPosition(u)
            call SetUnitOwner(u, p, true)

            set p = null
        endif
       
        return success
    endfunction
Not sure if the inclusion of call IssueImmediateOrder(u, "stop") matters at all but we can try to be safe, I guess.

Edit:
Wait, CMIIW, doesn't reference leak only happen when an agent is destroyed and local variable is still referencing it? Player never gets destroyed though. Or does it?
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
I see what you mean about the Resurrection "guard position" stuff, I was thinking it was for Creeps returning to camp.

Regardless, is the Player switch necessary? That's the concerning function to me, since I think it can fire an Event like "A unit changes ownership". Also, it still seems optional to me, maybe create a global boolean to control the behavior -> If Reset_Guard_Pos == True then do that stuff.

As far as I understand, "p" leaks as long as it's referencing a Player object -> GetOwningPlayer(). You're actually dealing with two things here, the player object which cannot be destroyed (for good reason), and the player variable that references said object (handle). I'm not too sure though, this thread has conflicting answers on the matter: [JASS] - set whichPlayer = null

For temporary objects like Locations (Points) you would do this:
vJASS:
local location loc = Location(0, 0)
 // ^ That creates two things, a location variable (handle) and the actual location object which contains the coordinates
call RemoveLocation( loc )
 // ^ That destroys the location object, but "loc" is still referencing it
set loc = null
 // ^ That removes the final reference and helps it become garbage collected

For the "Stop" order, I'm assuming the Unit isn't actually alive yet, so you'd have to delay it by a frame. If there's an Event that can catch the Unit being resurrected that would solve everything nicely (maybe it's considered a summon for the summon event?).
 
Last edited:

Rheiko

Spell Reviewer
Level 26
Joined
Aug 27, 2013
Messages
4,214
Anyway, is the Player switch necessary? That's the concerning function to me, since it can fire an Event like "A unit changes ownership". Also, it still seems like an optional thing to me, maybe create a global boolean to control the behavior -> If Reset_Guard_Pos == True then do that stuff.
Yeah, the player switch is necessary. I guess that's another downside to it. Surely, it can be optional but regardless what you choose, both have issues. If you want to reset guard of the resurrected unit, it can fire "A unit changes ownership" event but if you don't, the resurrected unit will go to the corner of the map.

I'll just leave the code here, Daffa or anyone that needs it can just choose whichever they see fits.
vJASS:
function ReviveUnit takes unit u, boolean resetGuardPos returns boolean
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local boolean success
        local player p
       
        if IsUnitType(u, UNIT_TYPE_HERO) == true then
            return ReviveHero(u, x, y, false)
        else           
            set p = GetOwningPlayer(u)

            call SetUnitX(u, rx)
            call SetUnitY(u, ry)
            set success = IssueImmediateOrderById(reviver, 852094)
            call SetUnitX(u, x)
            call SetUnitY(u, y)
            call IssueImmediateOrder(u, "stop")
                       
            //  Prevent units to run back towards the resurrection spot
            if resetGuardPos == true then
                call SetUnitOwner(u, Player(0), false)
                call SetUnitCreepGuard(u, false)
                call RemoveGuardPosition(u)
                call SetUnitOwner(u, p, true)
            endif

            set p = null
        endif
       
        return success
    endfunction
call ReviveUnit(unit whichUnit, boolean resetGuardPos)
 

Attachments

  • [Snippet] - ReviveUnit adjusted.w3x
    20.5 KB · Views: 2
Top