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

[vJASS] [System] Physical Damage Detection

Level 19
Joined
Jul 14, 2011
Messages
875
The object editor data is the exact same as it was before I recoded it.

Changing the attack/damage types to normal didnt make a difference.

Pretty sure the 'ranged' boolean is whether the attack can miss if the target is on a higher cliff level than the attacker. Thats what Ive read, atleast.

Also, I need to deal the exact amount of damage, not reduced by armor at all because PDDS.amount returns the damage after armor has been applied.
Doing UnitDamageTarget(source, target, damage, false, false, null, null, null) deals the exact amount to the target. Its just that it doesnt take it as PHYSICAL anymore, and thus the event fires again.

E:I check the damage type the exact same way in both places (if PDDS.damageType == PHYSICAL then).

Our of curiosity, what does the animation damage point have to do with this? E2: Oo, no no. I am using a custom projectile and damaging when it lands, not just X seconds after his animation starts.
 
Level 19
Joined
Jul 14, 2011
Messages
875
The delay is dynamic. But that doesnt matter at all, because the damage event shouldnt be firing a second time in the first place.

What is happening now, is that I send the projectile and when it lands, the event fires again and it tries to send another one. That repeats untill the unit runs out of projectiles, which is determined after after the event tells the projectile to launch.

E: To explain it better: I save the damage dealt, send out a projectile and deal the damage when it lands, which is basically delaying.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
I implemented something nice in my system which wont cause this problem, however to do that means rewriting the system you use.

Maybe lfh knows the best way to do it in his.
I mean, he designed it and he probably know this kind of problem already.
 
Level 19
Joined
Jul 14, 2011
Messages
875
The interesting thing is that in both the old backup and the current version of the map, the only difference in the triggers is the one which contains my system, and in both there is exactly one UnitDamageTarget, one damage event and the same exact conditions in it. One treats it as physical, the other does not(treats it as spell).

E:Never mind. My config values werent set properly for some reason, I may have tried to update it at some point and forgot to set it up.
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
After more thinking on this, why is it so important to detect the instant the unit's life changes? You have custom get/set unit life functions. If you add to those functions the same behavior that you'd normally execute when the 0 second timer expires (provided it is after the Damage events run), there's no chance of errors I can think of. Unless someone wants to fill me in otherwise.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007

Agreed, but there is a problem with this you oversee:

A unit with 5,000,000 hp which event is set on 4,999,999.9375 (0.0625 lower) makes the event run when damaged by 1 hp (after being reduced by armor etc).

that only works if you hardcode that value. But we can't use hardcoded values, we have to calculate them. Try using 5,000,000 - 0.0625 as an argument. Same happens with damage of 1. The health is reduced, but the event is not fired.

Never use hardcoded values to test such things, operations like +-*/ etc affect accuracy.

Doing UnitDamageTarget(source, target, damage, false, false, null, null, null) deals the exact amount to the target. Its just that it doesnt take it as PHYSICAL anymore, and thus the event fires again.

Of course its not PHYSICAL anymore, because you use null as attacktype. null == ATTACK_TYPE_NORMAL == SPELL damage. You can also refer to this table, which is a nice summary of the attacktype/damagetype combinations in Wc3.

Bribe said:
After more thinking on this, why is it so important to detect the instant the unit's life changes? You have custom get/set unit life functions. If you add to those functions the same behavior that you'd normally execute when the 0 second timer expires (provided it is after the Damage events run), there's no chance of errors I can think of. Unless someone wants to fill me in otherwise.

Three things:

  • GUI users don't like custom script and system functions. Its especially annoying for them if they want to integrate the system into a map that is already quite big and they have to replace all occurrences of GUI get/set life with custom scripts. Thats cumbersome and error prone. In general it would be good to not have any Ex functions (for vJass users too).
  • It avoids health value flickering which can't be avoided otherwise. We can only avoid health bar flickering using timers (with a proportional streched health bar), but there is no way to avoid health value flickering using timers. Only unit state events can solve this.
  • Real after damage events: Would instantly allow UnitDamageTargetEx functionality (queuing damage in the order it was applied) without the use of an extra function. Users would just apply the damage in the after damage event. Also no priority management for simple things like damage display (just display the final damage) would be needed, because display would just happen in an after damage event.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
Ah yes I see the problem.
If damage is just large enough to change the health but the damage - 0.0625 wouldnt change the health... (or change the health to exactly the same value).

Its a shame that EQUAL TO and NOT EQUAL TO dont work...
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
More bugs with this:

- IF there is a recursive UnitDamageTarget, the recursive event will not fire (you don't set the variable to 0 before running the event - only afterward).

- If a unit dies, you kick them out of the system. Heroes and units who were ressurrected are not valid until 60 seconds have passed.

Also, why inline UnitHasItemOfTypeBJ? You don't null the item so it's pointless.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
- IF there is a recursive UnitDamageTarget, the recursive event will not fire (you don't set the variable to 0 before running the event - only afterward).
I have to disagree here... you have to set the value to (any value EXCEPT the event) and then to the event.
So if you set it to 1 and then to 0, 0 will be the event, so you will make your triggers run when the variable becomes equal to 0.
If you set it to 0 and then to 1, 1 will be the event, bla bla bla.
It doesnt matter but I prefer to have 0 as the event and 1 or rather -1 as the reset to make it work recursive.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
No, in a recursive situation the variable will already be 1.00 and setting it again to 1 doesn't work.

Not if I use 0 as the event...
Ofcourse his example shows that you can use 1 as the event which means that UnitDamageTarget() will not run the event (regardless of that they are supposed to run a custom function), but if you change that 1 to 0, then you are fine.

Set EVENT = 1 //<<<this is a value that makes the event able to run
Set EVENT = 0 //<<<this is the event

No problems if I use:
Game - EVENT becomes equal to 0.00
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Clearly needs a disclaimer and a revised example, then. The layman will not notice the error in the script and copy the example.

Edit: it's clearly an oversight as he didn't cache any of the variables before running the event, so recursion will always mess with this script. UnitDamageTargetEx should never be a requirement - what if I want that damage to fire before the running damage but also run all the damage events? It's an unnecessary handicap.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
Im against caching variables because that would force you to edit the code of the system when you want to add your own variables (map maker perspective)
Im more in for indexing which would make a simple integer lead to every single variable that you need and cache only that integer.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
- IF there is a recursive UnitDamageTarget, the recursive event will not fire (you don't set the variable to 0 before running the event - only afterward).

Yes you are right, I think the user should be able to decide if he doesn't want to queue the damage but apply it directly. Until now nobody requested this, but I think its good to have it available.

- If a unit dies, you kick them out of the system. Heroes and units who were ressurrected are not valid until 60 seconds have passed.

Nice find, thats a nasty bug! Added on my todo list.
 
Level 18
Joined
Nov 21, 2012
Messages
835
Unfortunatelly it didnt work in my map. Made 1 test on line and noticed that 2 spells heals target , not damaging. Im really sad, after about a week of changing map and implementing dds. :psick:
I use Gui version 1.3.0.0
there is no abilities used, based on ACdr , ANdr
there is no abilities used, based on Afod , ACfd , ACf3 , ANfd , AIfz
/Afod is used for computer players for redirect spells, deals 0,01dmg/ and there was no computers in test I made on line
there is no abilities based on Elune and Runed Braces used in map /on items or on units/
magic reduction is triggered

also removed all calls:
GetUnitLifePercent
GetUnitStatePercent
GetUnitStateSwap
SetUnitLifeBJ
SetUnitLifePercentBJ
SetUnitState [there are but only mana references]
GetUnitState [there are but only mana references]

and replaced by
GetUnitLife
GetUnitMaxLife
SetUnitLife

To be honest only Weep's dds works w/o problems, but it doesnt offer much features. Still thats only one it worked, had Bribe's and also was problem with healing sometimes
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
I realised my comment was bullshit because Ex didnt fire after even before or did it?

But if UnitDamageTarget does the same thing, whats the point of having Ex now?

@Zibithe

Go to the locust swarm ability and invert its damage return portion from (default) 0.75 to -0.75.
LifeDrain does not work with this system, as the caster doesn't get healed. So if you want to use LifeDrain in your map, you should use a triggered version of this spell.
Finger of Death should also be triggered, as units don't explode when killed by this spell.

Maybe one of these are bugging? Also full names would be nice, Im too lazy to heat up editor :D
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
also removed all calls:
GetUnitLifePercent
GetUnitStatePercent
GetUnitStateSwap
SetUnitLifeBJ
SetUnitLifePercentBJ
SetUnitState [there are but only mana references]
GetUnitState [there are but only mana references]

and replaced by
GetUnitLife
GetUnitMaxLife
SetUnitLife

To be honest only Weep's dds works w/o problems, but it doesnt offer much features. Still thats only one it worked, had Bribe's and also was problem with healing sometimes

DamageEngine 3.3's only weirdness from what I can tell is that Mana Shield doesn't work yet with spells (but all DDS that use spell damage reduction have this problem). I'll make a triggered fix for it in a similar way I did Life Drain.

I realised my comment was bullshit because Ex didnt fire after even before or did it?

But if UnitDamageTarget does the same thing, whats the point of having an Ex now?

It is useful for queueing an attack that fires after a 0 second timer. lfh says it can mess with the bounty depending on who dies first in a MAD situation. DE3 doesn't let you queue damage, but if you want to achieve the same effect of dealing damage after the first damage expired then apply the damage from an AfterDamageEvent Equal to 1.00 trigger.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
The first point of having UnitDamageTargetEx is that it is used in a lot of maps now, so you cannot just remove the function.

Also when you run UnitDamageTarget while being in the OnDamage event, you will deal the new damage before the first one (where the OnDamage event comes from).
With UnitDamageTargetEx, you will apply it after the first damage.

I dont really see any problems regarding either methods but for safety usage, I should recommend UnitDamageTargetEx. (Regardless of how good or bad it is coded cause I have actually no idea how the code in there looks like :D)
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
But if UnitDamageTarget does the same thing, whats the point of having Ex now?

Its for queuing and applying damage in the order it happened.

Bribe said:
DamageEngine 3.3's only weirdness from what I can tell is that Mana Shield doesn't work yet with spells (but all DDS that use spell damage reduction have this problem).

What do you mean? Manashield works fine in PDDS without any triggers.

ZiBitheWand3r3r said:
Unfortunatelly it didnt work in my map. Made 1 test on line and noticed that 2 spells heals target , not damaging. Im really sad, after about a week of changing map and implementing dds.

Well, you will have to give some more information. Maybe you can create a minimal working example? But without any code or further information I can only guess too.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
What do you mean? Manashield works fine in PDDS without any triggers.

If you want it to only react to the original damage, then it's fine. But I wanted it to work off of modified damage so no mana was reduced in the event of a block.

I didn't test it with spell damage, but wouldn't it not subtract mana at all for that type?
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
If you want it to only react to the original damage, then it's fine. But I wanted it to work off of modified damage so no mana was reduced in the event of a block.

I don't understand what you mean exactly... Units that have mana shield (and have sufficient mana) don't take damage at all. So there is no damage event in the first place?
There might be a zero damage event, but those are unreliable anyway (casting slow on a unit also triggers a zero damage event, sometimes even entering an aura).

I didn't test it with spell damage, but wouldn't it not subtract mana at all for that type?

Just tested it (again) and everything works fine in PDDS. At least I haven't found a scenario where its not working.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
That is the problem.
Lets say that I have an ability that increases my basic attack damage by 100 X Armor.
Now this one has to be triggered and we can do that by using a DDS.
However, when a unit is protected by Mana Shield, it wont take that damage because the event did not run.

Yes, but thats just how things work and Mana Shield isn't an exception here.

Also thats not related to the bracers trick but will happen with any DDS that allows damage modification. With your argument I can also say that ...

  • ... setting any armor type in the armor table to zero will cause this "problem"
  • ... Illusion attacks have this "problem"
  • ... Evasion has this "problem"
  • ... Anti-Magic Shell has this "problem"
  • ... Anti-Magic Potion has this "problem"
  • ... Spell Shield has this "problem"
  • ... Harden Skin has this "problem"
  • ... and so on

Blizzard only gives us access to the reduced damage, thats just how it is. I don't think it would be a good idea to hard-code all the problems mentioned above into a DDS just because a user might want to modify their damage. This applies for Mana Shield too IMO.

If you really want to modify the mana-damage of Mana Shield based on your own logic, just recode the spell. Then you have full control and with a DDS that allows damage modification thats really straightforward anyways.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
The difference with all those which you mentioned above is that they haven't removed a resource from the unit and are completely duration-based. Mana is removed from the unit before the mana shield reduces the damage to 0 and triggers the 0 damage event. If the user has any desire to amplify the damage from 0 to something else, they can, but the mana lost is extremely difficult to accurately trace. This is also problematic to use just one event for all damage processing, because you need to be able to have a modification event run first so that the next event has the final damage amount to work with, and in between those events is where mana shield is applied.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
I'm with edo on that. Most of the problematic cases for dds have been listed for ages (Finger of Death, Drain of Life) and now Mana Shield. Neither of them is very complicated and if you want to be that accurate in your map, then you probably have more than enough knowledge anyway to code their substitutes efficiently.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
The difference with all those which you mentioned above is that they haven't removed a resource from the unit and are completely duration-based.

Disagree ;)

An Anti magic Shell for example also has a certain amount of "hitpoints", which extend a units resources (namely life) by some value.

If you now set all damage to zero and attack a unit which has Anti Magic Shell, the shell will still get destroyed due to the damage being dealt before the modification happens.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
Yes, but thats just how things work and Mana Shield isn't an exception here.
It is how it works but not how it should work... no blame on the people making DDS stuff but blaming Blizzard for how WC3 is made.
And you know that WC3 damage engine is not perfect.

With your argument I can also say that ...
  • ... setting any armor type in the armor table to zero will cause this "problem"
  • ... Illusion attacks have this "problem"
  • ... Evasion has this "problem"
  • ... Anti-Magic Shell has this "problem"
  • ... Anti-Magic Potion has this "problem"
  • ... Spell Shield has this "problem"
  • ... Harden Skin has this "problem"
  • ... and so on
Yes there are problems with some abilities that will make them bug out, but that doesnt mean that it is not a problem because we cant fix them.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Can someone please help me - I have tried many combinations in Object Editor for values trying to nullify its effect, but even the Anti Magic Shield that's supposed to absorb damage is actually spell IMMUNE instead of subtracting from the health. I can't even cast banish on it.

Is it something in the Gameplay Constants that needs to change?
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Isn't 'Aam2' hardcoded as Spell Shield without Crown Control immunity while 'Aams' shields wearer from every single magic effect?

Actually, I had been testing AMS with Blizzard and Flame Strike. I had the shield damage at 0 when I tried something else and accidentally found out that the unit was spell immune. So lowering the shield to 0 is not the solution. I tried messing with the spell reduction on it, but that was never hardcoded by Blizzard (like Defend's deflect).

The only way to make it work is to use a custom ability (in this case, I used Frost Armor manual-cast). I attach the value 300 onto the unit when it's targeted with that ability, then reduce it with spell damage until I manually remove the buff, the buff is dispelled or it expires. Does anyone know if Spell Steal will act as a re-cast of that ability, or is there no way to handle it?
 
excuse my ignorance, but all is needed for a DDS sys that detects the difference between spells and physical damage is a wrapper damage function. One function deals damage with DDS on and the other with it off.

Doing this, if you're willing to make all of your spells entirely composed of Channel Base spell and JASS you can have complete control of when DDS will fire.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
I hear Mr.Pockets00000's point.
But I have a question... the actual use of a DDS is to detect damage, whatever is done with it can be wrapped under the words "Damage Engine".
I see that you want to have a quite nice Damage Engine, but how far do you need a Damage Detection System?

For example, will you be willingly to only deal spell damage via triggers?
In that case, you will only need it to detect basic attack damage points.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
He means "be like Wietlol" :p

The best approach (afaik) is to not let units use their regular basic attacks any more and trigger that behavior instead.

There is a sort of workaround but it is not 100% safe.
You can check if the first attack index is ranged or melee (according to their weapon type).
But if you fire an arrow, then morph into a melee unit, that arrow will be detected as melee.
Depending on what you want to use it for, this will do, but it will not work for everything.
 
Top