HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

My unkillability ( =/= invulnerability) system doesnt work 100%, why?!

05-06-2009, 01:10 PM#1
Dj0z
I basically made a system unallowing heroes to be killed by non-hero units.
It would leave them down to 1 hp but any damage dealt to them would be pro-actively prevented.

When a hero would deal any damage to the almost dead hero, though, a trigger called Death Scene would fire and make a small cutscene where the killer hero finishes the agonizing one.


However when i finished it (it actually works), i noticed that sometimes (quite randomly), it would let a random hero (usually the first time it is supposed to fire) die without doing its anti-death job. No Death Scene would occur, it would be just like the system never existed.

I already found one part of the solution: this system cannot handle damage higher than the hero's hp. That because the hero cannot be healed higher than his max hp, then when the damage is applied he is instakilled anyways.
Still, sometimes, a very low damage from a random unit/hero kills a hero while it should not.


If you guys have any idea why it doesnt work, or if you could provide a workaround, i would be grateful. Credit would be given ingame of course.
Here is the system:

Initialization: indexing the anti-death triggers:
Trigger:
HeroSpecialDeath Init
Collapse Evénements
Map initialization
Conditions
Collapse Actions
Set HeroSpecialDeathTrigX[1] = HeroSpecialDeath 1 <gen>
Set HeroSpecialDeathTrigX[2] = HeroSpecialDeath 2 <gen>
Set HeroSpecialDeathTrigX[3] = HeroSpecialDeath 3 <gen>
Set HeroSpecialDeathTrigX[4] = HeroSpecialDeath 4 <gen>
Set HeroSpecialDeathTrigX[5] = HeroSpecialDeath 5 <gen>
Set HeroSpecialDeathTrigX[6] = HeroSpecialDeath 6 <gen>
Set HeroSpecialDeathTrigX[7] = HeroSpecialDeath 7 <gen>
Set HeroSpecialDeathTrigX[8] = HeroSpecialDeath 8 <gen>
Set HeroSpecialDeathTrigX[9] = HeroSpecialDeath 9 <gen>
Set HeroSpecialDeathTrigX[10] = HeroSpecialDeath 10 <gen>
Set HeroSpecialDeathTrigX[11] = HeroSpecialDeath 11 <gen>

Setting up the system: assigning each hero to a trigger:
Trigger:
HeroSpecialDeath Setup
Collapse Evénements
Unité - A unit enters (Playable map area)
Collapse Conditions
Collapse ((Triggering unit) is an illusion) Différent de (!=) TRUE
Collapse Multiple ConditionsOr - Any (Conditions) are true
Collapse Conditions
(Unit-type of (Triggering unit)) Egal Ã* (==) Defender - Master builder
(Unit-type of (Triggering unit)) Egal Ã* (==) COLOSSUS - unevolved (weakest)
(Unit-type of (Triggering unit)) Egal Ã* (==) COLOSSUS - Infernal
(Unit-type of (Triggering unit)) Egal Ã* (==) COLOSSUS - Arctic
(Unit-type of (Triggering unit)) Egal Ã* (==) COLOSSUS - Stygian
(Unit-type of (Triggering unit)) Egal Ã* (==) COLOSSUS - Flesh Abomination
(Unit-type of (Triggering unit)) Egal Ã* (==) COLOSSUS - Crystal
Collapse Actions
Collapse Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse Si - Conditions
HeroSpecialDeath_HeroX[HeroNumber] Egal Ã* (==) Pas d'unité
Collapse Alors - Actions
Set HeroSpecialDeath_HeroX[HeroNumber] = (Triggering unit)
Déclencheur - Add to HeroSpecialDeathTrigX[HeroNumber] the event (Unité - (Triggering unit) Subit des dégâts)
Partie - Display to Groupe joueur - Joueur 12 (Marron) the text: (String(HeroNumber))
Partie - Display to Groupe joueur - Joueur 12 (Marron) the text: ((Name of (Triggering unit)) + INVUL)
Set HeroNumber = (HeroNumber + 1)
Sinon - Actions

One of the to-be-indexed antideath triggers (they are all copy-pastes):
Trigger:
HeroSpecialDeath 4
Evénements
Collapse Conditions
(Vie of (Triggering unit)) Inférieur ou égal Ã* (<=) (Damage taken)
Collapse Actions
Collapse Unité - Set life of (Triggering unit) to (1.00 + (Damage taken))
Collapse Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse Si - Conditions
Collapse ((Damage source) is an illusion) Différent de (!=) TRUE
Collapse Multiple ConditionsOr - Any (Conditions) are true
Collapse Conditions
(Unit-type of (Damage source)) Egal Ã* (==) Defender - Master builder
(Unit-type of (Damage source)) Egal Ã* (==) COLOSSUS - unevolved (weakest)
(Unit-type of (Damage source)) Egal Ã* (==) COLOSSUS - Infernal
(Unit-type of (Damage source)) Egal Ã* (==) COLOSSUS - Arctic
(Unit-type of (Damage source)) Egal Ã* (==) COLOSSUS - Stygian
(Unit-type of (Damage source)) Egal Ã* (==) COLOSSUS - Flesh Abomination
(Unit-type of (Damage source)) Egal Ã* (==) COLOSSUS - Crystal
(Death scene <gen> is on) Egal Ã* (==) TRUE
DeathSceneKiller Egal Ã* (==) Pas d'unité
DeathSceneVictim Egal Ã* (==) Pas d'unité
Collapse Alors - Actions
Set DeathSceneKiller = (Damage source)
Set DeathSceneVictim = (Triggering unit)
Déclencheur - Run Death scene <gen> (checking conditions)
Sinon - Actions
Partie - Display to Groupe joueur - Joueur 12 (Marron) for 1.00 seconds the text: ((Name of (Triggering unit)) + healed!)

The Death Scene trigger, supposed to be the only way a hero can die:
(there is no event because it is fired straight from the antideath triggers, using 2 globals.)
Trigger:
Death scene forWC3C
Evénements
Conditions
Collapse Actions
Déclencheur - Turn off (This trigger)
Set DeathScenePointVictim = (Position of DeathSceneVictim)
Set DeathScenePointKiller = (Position of DeathSceneKiller)
Set DeathSceneAngleVictimToKiller = (Angle from DeathScenePointVictim to DeathScenePointKiller)
Cinématique - Turn cinematic mode On for (All players)
Déclencheur - Run SOUND VOL RESET <gen> (ignoring conditions)
-------- BELOW, the scene --------
Unité - Make DeathSceneKiller Invulnérable
Unité - Pause DeathSceneKiller
Unité - Pause DeathSceneVictim
Collapse Wait 2.00 game-time seconds
Collapse Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse Si - Conditions
(Distance between DeathScenePointKiller and DeathScenePointVictim) Supérieur Ã* (>) 350.00
Collapse Alors - Actions
Set TempPoint = (DeathScenePointVictim offset by 350.00 towards DeathSceneAngleVictimToKiller degrees)
Unité - Move DeathSceneKiller instantly to TempPoint
Sinon - Actions
Unité - Make DeathSceneKiller face DeathSceneVictim over 1.50 seconds
Unité - Make DeathSceneVictim face DeathSceneKiller over 1.50 seconds
Wait 2.00 game-time seconds
Collapse Groupe joueur - Pick every player in (All players) and do (Actions)
Collapse Boucle - Actions
Caméra - Lock camera target for (Picked player) to DeathSceneVictim, offset by (0.00, 0.00) using Rotation par défaut
Set CineTempAngle = (DeathSceneAngleVictimToKiller + (Random real number between 25.00 and 45.00))
Collapse Wait 1.20 game-time seconds
Collapse Do Multiple ActionsFor each (Integer TempInteger) from 1 to HeroNumber, do (Actions)
Collapse Boucle - Actions
Collapse Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse Si - Conditions
HeroSpecialDeath_HeroX[TempInteger] Egal Ã* (==) DeathSceneVictim
Collapse Alors - Actions
Déclencheur - Turn off HeroSpecialDeathTrigX[TempInteger]
Partie - Display to Groupe joueur - Joueur 12 (Marron) the text: (String(TempInteger))
Partie - Display to Groupe joueur - Joueur 12 (Marron) the text: DEACTIVATED
Sinon - Actions
Unité - Cause DeathSceneKiller to damage DeathSceneVictim, dealing 99999.00 damage of attack type Chaos and damage type Universel
Collapse Wait 1.00 game-time seconds
Collapse Do Multiple ActionsFor each (Integer TempInteger) from 1 to HeroNumber, do (Actions)
Collapse Boucle - Actions
Collapse Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse Si - Conditions
HeroSpecialDeath_HeroX[TempInteger] Egal Ã* (==) DeathSceneVictim
Collapse Alors - Actions
Déclencheur - Turn on HeroSpecialDeathTrigX[TempInteger]
Partie - Display to Groupe joueur - Joueur 12 (Marron) the text: (String(TempInteger))
Partie - Display to Groupe joueur - Joueur 12 (Marron) the text: REACTIVATED
Sinon - Actions
Wait 1.00 game-time seconds
-------- RESET -- END OF THE SCENE --- --------
Unité - Make DeathSceneKiller Vulnérable
Cinématique - Turn cinematic mode Off for (All players)
Déclencheur - Run SOUND VOL RESET <gen> (ignoring conditions)
Déclencheur - Run RestoreCamAllPlayers <gen> (ignoring conditions)
Wait 8.00 game-time seconds
-------- RESET -- - RESET --- --------
Set DeathSceneKiller = Pas d'unité
Set DeathSceneVictim = Pas d'unité
Déclencheur - Turn on (This trigger)
05-06-2009, 01:41 PM#2
Captain Griffen
Use GUI tags.

Change condition on damaged trigger to be life < damage taken + 1; should fix it. If a unit's health goes below 0.405, then it dies - it doesn't have to go to zero.
05-06-2009, 01:46 PM#3
Dj0z
Thx for the quick feedback, testing this solution rightaway.
i will learn to use GUI tags, too.

By the way could this system be responsible for a sudden increase in lag? (from one version of the map without it, to one with it?)

EDIT: Actually, is this system efficient or could it be improved in any way (no talking about jassing it, there)?
05-06-2009, 05:56 PM#4
grim001
You will probably get more feedback after you convert it to GUI tags, I don't want to read it with those screenshots.
05-06-2009, 09:03 PM#5
Dj0z
Omg... i just tried using GUI tags, the only way i found is to manually right click every single line and "copy as text" then paste it here between both tags...

This is such a Pain >.< it's gonna take me half an hour to paste the amount of lines i have in those triggers :/ i'm sure there must be another way, could you guys please teach me?
05-06-2009, 09:16 PM#6
Opossum
Just right click on the trigger title and select copy as text. That will copy the whole trigger.
05-06-2009, 09:18 PM#7
Alevice
Quote:
Originally Posted by Dj0z
Omg... i just tried using GUI tags, the only way i found is to manually right click every single line and "copy as text" then paste it here between both tags...

This is such a Pain >.< it's gonna take me half an hour to paste the amount of lines i have in those triggers :/ i'm sure there must be another way, could you guys please teach me?
right click the trigger name in the event/cond/actions window. it copies the whole trigger into text.
05-06-2009, 09:35 PM#8
Dj0z
Okay thanks for the GUI tags tuto guys, i have fixed the display now, and added the roles of each trigger.
So, any idea?
05-06-2009, 10:36 PM#9
grim001
Well the only part of those triggers relevant to your question seems to be the part where you increase the unit's life if they would have died from the damage taken. These are two possible problems (other than the one you noticed about units dying in one hit):

1.) You should follow Griffen's advice and consider the fact that units die if their HP goes below 0.405, not below 0. So your condition needs to be "if unit life - 0.405 >= damage" (this is probably your main problem)

2.) If two units damage the same unit at exactly the same time (more common than you might think if you have lots of units on the map), and the sum of their damage is enough to kill the damaged unit in one hit, this method won't save it from dying

Let me ask you this, are you completely allergic to using custom script calls or libraries?
05-06-2009, 10:51 PM#10
Dj0z
First of all: i've tried Griffen's system, and in the last test i ran, with thousands of instances of the antideath triggers firing, none of the heroes died to a non-hero unit!!

I found some other bugs though, so ill fix them and retest to see if it's Really actually working.


@grim: Actually I just don't have any clue about libraries, but I have nothing against custom scripts. I have made a couple jass spells/mechanisms in this map aswell btw.

Why would i use a custom script in this trigger btw? could it improve anything? I don't think it leaks, i mean.

EDIT: Also, any idea if there is a fix for this case: "the hero is dealt damage higher than his max hp." ?
I thought about making him invulnerable and running a timer expiring in 0.00 or 0.01 seconds that removes the invul, any better idea?
05-06-2009, 10:58 PM#11
Captain Griffen
Add an ability giving it a load more HP, then have a 0. second timer and then remove it.
05-06-2009, 11:18 PM#12
grim001
If it were that simple, Griffen, DamageMod wouldn't need to exist.

Dj0z, you're trying to do something that is actually quite complicated to pull off correctly. If you just add some max life to the unit it will probably work "most of the time," but you'll still get the random errors, especially if two units attack at the exact same time.

Anyway there is no point in explaining to you how to reinvent the wheel, this is exactly what I created DamageMod for. I would suggest you use it. It will just take a very simple custom script call to modify the incoming damage by the correct amount to leave the damaged unit with 1 HP.
05-06-2009, 11:23 PM#13
ToukoAozaki
Quote:
Originally Posted by grim001
Dj0z, you're trying to do something that is actually quite complicated to pull off correctly. If you just add some max life to the unit it will probably work "most of the time," but you'll still get the random errors, especially if two units attack at the exact same time.

There is no such thing possible as "attacking at the exact same time." Simply that cannot happen. All in-game events are processed sequentially.
However, involvement of timer can cause an issue. In that particular case, insufficient logic may cause some trouble since execution order is not guaranteed. While attacks cannot be at the exact same time, but they can happen in a single frame.

Added: As the event fires before actual damage is applied, I think there still is possibility of conflict. I think you can solve that by saving the amount of adjusted life to a unit, comparing it with unit's current life, and accumulate it if necessary. Whether there is possible conflict and needs to be solved can only be determined by further testing (means I'm not sure that may happen).
05-06-2009, 11:24 PM#14
grim001
Quote:
Originally Posted by ToukoAozaki
There is no such thing possible as "attacking at the exact same time." Simply that cannot happen.

You're wrong. There's a minimum granularity to the attack intervals in WC3. Test it yourself.
05-07-2009, 02:36 AM#15
Bobo_The_Kodo
Ye, grim is correct

Is how "EvasionMod" works