[vJASS] [System] Physical Damage Detection

Level 5
Joined
May 24, 2016
Messages
127
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.
Pity to know. But anyway, thx.
 
Level 3
Joined
Dec 8, 2013
Messages
52
I am sorry, but what means AddDamageHandler? I wish I knew vjass..
P.s new problem here. I made trigger lifesteal, but it does not work.
Tried two ways:
call SetUnitLife(PDDS.source,GetUnitLife(PDDS.source) + PDDS.amount * 0.65)
call SetWidgetLife(PDDS.source,GetWidgetLife(PDDS.source) + PDDS.amount * 0.65 )
 
Last edited:
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.

So this allows for legacy spells, ie firebolt, to be used in such a system without recoding?
 
Firebolt currently doesnt need recoding.
So I dont really get your point.
It would if you use the old way of DDS where you simply turn a boolean off for spell damage psuedocode:

JASS:
//the following code prevents spell damage from triggering dds
set dds_enable = false
call UnitDamageTarget(spellCaster, spellTarget, 100.00, true, true, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_FIRE, WEAPON_TYPE_WHOKNOWS)
set dds_enable = true

this is the way you'd have to do it with a simple dds. Thus, to detect firebolt as being physical damage or not you'd have to recode.

edit: or more clearly

JASS:
set dds_physical_damage = false
call UnitDamageTarget(spellCaster, spellTarget, 100.00, true, true, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_FIRE, WEAPON_TYPE_WHOKNOWS)
set dds_physical_damage = true
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
In which case: "For example, will you be willingly to only deal spell damage via triggers?"
So all spells have to be recoded... and no, there is no simple way of doing that.
And I dont see anyone (except Bribe) to make all spells of WC3 by triggers.
 
Level 21
Joined
Mar 27, 2012
Messages
3,233
Tbh it wouldn't be all that complicated. The main problem imo with it is that it's going to be less efficient. A phoenix fire on my machine can create 8700 tracking projectiles before it lags. With a coded system that only does tracking projectiles I can at best get 300. The difference in efficiency is so monstrous that in many cases it simply wouldn't be worth it.
 
In which case: "For example, will you be willingly to only deal spell damage via triggers?"
So all spells have to be recoded... and no, there is no simple way of doing that.
And I dont see anyone (except Bribe) to make all spells of WC3 by triggers.
Which is why bribe is a God amongst us.

In other news, anyone want to make a Jass based language based on C# as a model with backwards compatibility with native JASS? I think that wurst was making a good point about vJASS although sadly lacking the backwards compatibility and some issues where not all the funtionality was there. I think we could really do something amazing using C# as a model. Ik i could do it all on my own, but it'd take years and would pale in comparison to the might of a community based project.

Edit: Sorry if this is too ambitious... i started having these thoughts when i looked at vjass libraries and realize like "really, i can't have 2 funcs same name between libraries?" wouldnt it be better to have a c# namespace model? Then utilize the method from wurst to allow for cyclic calls and give the freedom of vjass along with a precompiler directive allowing you to insert native jass calls.... I could see so much power in such a system alowing old vjass but allowing for newer cleaner code lacking the fugly jass CALL and SET nonsense....

Not to mention, we could completely abandon jass's vba tendencies that are so prevalent....
 
Last edited:
Level 13
Joined
Nov 7, 2014
Messages
570
OT:
@Mr.Pockets00000
i started having these thoughts when i looked at vjass libraries and realize like "really, i can't have 2 funcs same name between libraries?"

JASS:
library LibA initializer init

private function init takes nothing returns nothing
    call BJDebugMsg("LibA.init called")
endfunction

public function print_something takes nothing returns nothing
    call BJDebugMsg("LibA.print_something called")
endfunction

function global_namespace_function takes nothing returns nothing
    call BJDebugMsg("global_namespace_function (defined in LibA) called")
endfunction

endlibrary

library LibB initializer init

private function init takes nothing returns nothing
    call BJDebugMsg("LibB.init called")
endfunction

public function print_something takes nothing returns nothing
    call BJDebugMsg("LibB.print_something called")
endfunction

// error: Function redeclared: global_namespace_function
// function global_namespace_function takes nothing returns nothing
//     call BJDebugMsg("global_namespace_function defined in LibB")
// endfunction

endlibrary

//! inject main
    //! dovjassinit

    call LibA_print_something()
    call LibB_print_something()
    call global_namespace_function()

    // =>
    // LibA.init called
    // LibB.init called
    // LibA.print_something called
    // LibB.print_something called
    // global_namespace_function (defined in LibA) called

//! endinject

PS: libraries and scope visibility is of course described in the vJass manual
 
OT:
@Mr.Pockets00000

PS: libraries and scope visibility is of course described in the vJass manual

Oh i think ik the problem. I've been using an older vjass *facepalms*

Man VJASS has improved since i've touched, I actually went back to normal JASS a while back bc of annoyances I had with it.

Also I dislike the clunkyness of vJASS, like how to be efficient you can't use initializer keyword and you have to use inject in main. I hate call ExecuteFunc and would rather have a trigger if they're doing it to avoid op limits. bc atleast trigger won't get screwed by low-level jass optimizer.

I also generally don't like JASS or VJASS syntax finding it too close to VBA. Should utilize a C-style syntax as it is cleaner and only verbose where necessary. I guess this is more of a personal prefernce but does anyone really enjoy saying "call funcx"

there's also the issue of nulling locals, that should be handled automatically then utilize globals to return.

If I were to build my own to-jass language i'd surely include a precompiler directive such as:

#JASS call funca()

thus allowing you to combine old JASS with the new language easilly.

Edit: also the lack of type safety in VJASS. should make use of "as" keyword for from type a to type b
 
Last edited:
Level 5
Joined
May 24, 2016
Messages
127
I really tried to consider every detail looking_for_help's using guide, but this system doesnt really work right with UnitDamageTargetEx. I mean, for some reasons, when a hero autoattacks a unit with a buff that gives bonus magic damage, somehow target gets less damage that it could get just by getting autoattack. WTF?
 
Level 37
Joined
Sep 26, 2009
Messages
8,447
I really tried to consider every detail looking_for_help's using guide, but this system doesnt really work right with UnitDamageTargetEx. I mean, for some reasons, when a hero autoattacks a unit with a buff that gives bonus magic damage, somehow target gets less damage that it could get just by getting autoattack. WTF?
Sounds like there is an error in your code somewhere. What you describe is not an issue of this system.
 
Level 5
Joined
May 24, 2016
Messages
127
Sounds like there is an error in your code somewhere. What you describe is not an issue of this system.
Im sorry to confuse you right now, but I feel myself too tired to make a specific thread about my issues.
I could discuss with you more about my problem, but currently I cant convert 16x16 icons(.png) into blp without losing transparency. By the way do you know how to do that? Ofc I tried to google before questioning you.
 
Level 37
Joined
Sep 26, 2009
Messages
8,447
Im sorry to confuse you right now, but I feel myself too tired to make a specific thread about my issues.
I could discuss with you more about my problem, but currently I cant convert 16x16 icons(.png) into blp without losing transparency. By the way do you know how to do that? Ofc I tried to google before questioning you.
Custom models/icons aren't my thing. I recommend posting separately in the World Editor Help Zone.
 
Level 5
Joined
May 24, 2016
Messages
127
Custom models/icons aren't my thing. I recommend posting separately in the World Editor Help Zone.
Okay. Let me explain a bit.
The only thing I implemented in this system if that I gave to every unit spell book with range and melee buff
So I can check attack type by
Code:
if GetUnitAbilityLevel(PDDS.target,'B002') > 0 then // MELEE
But okay lets forget about damage function. I noticed if I try to detect this attack under buff, it's not 100% change event will work.
WTF? I checked every condition that went before my spell, and the only thing I see is that I cast slow on attacking and attacked unit. That's it.
Code:
if PDDS.amount > 0 and not IsUnitType(PDDS.target,UNIT_TYPE_STRUCTURE) /*
*/ then
//CAUSES SLOW 
//BEFORE 3.2 - CAUSES SLOW FOR BOTH SOURCE AND TARGET UNIT 
//AFTER 3.2 - CAUSES SLOW ONLY FOR TARGET
set d = CreateUnit(GetOwningPlayer(PDDS.source),dummy,GetUnitX(PDDS.target),GetUnitY(PDDS.target),0)
call UnitApplyTimedLife( d,'BTLF' , 0.1 )
call UnitAddAbility(d,'A00E')
call IssueTargetOrder(d,"slow",PDDS.target)

call UnitAddAbility(PDDS.source,'Aasl')
call GroupAddUnit(AttackingGroup,PDDS.source)
call SaveReal(Hash,GetHandleId(PDDS.source),StringHash("Attacking"),4.)
/*
set d = CreateUnit(GetOwningPlayer(PDDS.target),dummy,GetUnitX(PDDS.source),GetUnitY(PDDS.source),0)
call UnitApplyTimedLife( d,'BTLF' , 0.1 )
call UnitAddAbility(d,'A00E')
call IssueTargetOrder(d,"slow",PDDS.source) */

endif
 
Last edited:
Level 5
Joined
May 24, 2016
Messages
127
The original SPELL ATTACK event
Code:
if GetUnitAbilityLevel(PDDS.source,'B007') > 0 then // ZEAL STUN + DAMAGE

call GroupRemoveUnit(Zeal_Casters,PDDS.source)
call UnitRemoveAbility(PDDS.source,'A00J')
call UnitRemoveAbility(PDDS.source,'A00K')
call UnitRemoveAbility(PDDS.source,'B007')
call DestroyEffect(LoadEffectHandle(Hash,GetHandleId(PDDS.source),StringHash("Zeal_e")))
call RemoveSavedHandle(Hash,GetHandleId(PDDS.source),StringHash("Zeal_e"))
call RemoveSavedReal(Hash,GetHandleId(PDDS.source),StringHash("Zeal_time"))

set d = CreateUnit(GetOwningPlayer(PDDS.source),dummy,GetUnitX(PDDS.target),GetUnitY(PDDS.target),0)
call UnitApplyTimedLife( d,'BTLF' , 0.1 )
call UnitAddAbility(d,'A22Q')
call SetUnitAbilityLevel(d,'A22Q',GetUnitAbilityLevel(PDDS.source,'A00I'))
call IssueTargetOrder(d,"creepthunderbolt",PDDS.target)
call KillUnit(CreateUnit(GetOwningPlayer(PDDS.source),'e00J',GetUnitX(PDDS.target),GetUnitY(PDDS.target),0))
//call DestroyEffect(AddSpecialEffect("Singularity I Red.mdx",GetUnitX(PDDS.target),GetUnitY(PDDS.target)))

call PlaySoundOnUnit( gg_snd_Incinerate1, 100, PDDS.target )
call SetSoundDistanceCutoff( bj_lastPlayedSound, 950.00 )
//call AddEffectTimeToUnit("Flameshock.mdx",PDDS.target,"chest",2.5)
call UnitDamageTargetEx(PDDS.source, PDDS.target, 120 + (GetUnitAbilityLevel(PDDS.source,'A00I') * 20), true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null)

endif
 
Level 22
Joined
Feb 27, 2007
Messages
3,784
Instead of checking for the buff that the auras bestow to the units, you can just check for the abilities themselves. The abilities to flag the units don't even need to confer buffs unless you actually want ranged/melee to be shown on the buff UI.
 
Level 21
Joined
Mar 27, 2012
Messages
3,233
Found a bug and tracked down why exactly it happens.
I had an ambush trigger where some units are hidden at the start of the game, then unhidden later.
The issue is, depending on the timing, those units might not run the damage event at all.

This issue comes from the way the reset function works.
vJASS:
    private function ClearMemory_Actions takes nothing returns nothing
        local group g = CreateGroup()
        local code c = function DamageEngine
      
        // Reset the damage event
        call GroupEnumUnitsInRect(g, GetWorldBounds(), null)
        call ResetTrigger(damageEvent)
        call DestroyTrigger(damageEvent)
        set damageEvent = null
      
        // Rebuild it then
        set damageEvent = CreateTrigger()
        call TriggerAddCondition(damageEvent, Filter(c))
        call ForGroup(g, function RestoreTriggers)
      
        // Clean things up
        call DestroyGroup(g)
        set g = null
        set c = null
    endfunction
GrounEnumUnits functions don't pick up hidden units. Therefore, if a unit happens to be hidden when this runs, any damage it takes will not go through the system.
The solution would be to actually have a list of units in the system and check this list whenever you reset the trigger. Check if the units have been removed. (GetUnitypeId(u) == 0, iirc)
Simply using an enum breaks in rare and hard to track down cases, like mine that I spent 2 hours on, only to find in 1 hour that the bug isn't mine and in the next that it's yours.
Kindly, Xonok. Fix your shit :D
 
Level 37
Joined
Sep 26, 2009
Messages
8,447
Found a bug and tracked down why exactly it happens.
I had an ambush trigger where some units are hidden at the start of the game, then unhidden later.
The issue is, depending on the timing, those units might not run the damage event at all.

This issue comes from the way the reset function works.
vJASS:
    private function ClearMemory_Actions takes nothing returns nothing
        local group g = CreateGroup()
        local code c = function DamageEngine
     
        // Reset the damage event
        call GroupEnumUnitsInRect(g, GetWorldBounds(), null)
        call ResetTrigger(damageEvent)
        call DestroyTrigger(damageEvent)
        set damageEvent = null
     
        // Rebuild it then
        set damageEvent = CreateTrigger()
        call TriggerAddCondition(damageEvent, Filter(c))
        call ForGroup(g, function RestoreTriggers)
     
        // Clean things up
        call DestroyGroup(g)
        set g = null
        set c = null
    endfunction
GrounEnumUnits functions don't pick up hidden units. Therefore, if a unit happens to be hidden when this runs, any damage it takes will not go through the system.
The solution would be to actually have a list of units in the system and check this list whenever you reset the trigger. Check if the units have been removed. (GetUnitypeId(u) == 0, iirc)
Simply using an enum breaks in rare and hard to track down cases, like mine that I spent 2 hours on, only to find in 1 hour that the bug isn't mine and in the next that it's yours.
Kindly, Xonok. Fix your shit :D

If you are on an older Wc3 version, I would recommend using damage engine 3.8 or 3A. If you're current, you can use the current Damage Engine.

All 3 above versions have compatibility plugins for PDD.
 
Level 21
Joined
Mar 27, 2012
Messages
3,233
At this point I'll just write my own, actually. It'll be fun.
I've come to think of wc3 as practice for real programming, so very little ends up mattering except self-improvement.
Thanks though. I'm sure your DDS works well, just like your GUI unit indexer that I've still not stopped using despite only doing vJASS nowadays.
 
Level 37
Joined
Sep 26, 2009
Messages
8,447
At this point I'll just write my own, actually. It'll be fun.
I've come to think of wc3 as practice for real programming, so very little ends up mattering except self-improvement.
Thanks though. I'm sure your DDS works well, just like your GUI unit indexer that I've still not stopped using despite only doing vJASS nowadays.

Writing your own version of existing systems is a great way to practice. Many of the vJass people I used to compete with moved onto becoming real programmers. That's not really what I envision for myself, however, as I only enjoy doing very niche things within WarCraft 3 itself.

People like TriggerHappy really seem to get into the machine level aspect of the code and I just don't understand how he knows so much about it to even try to get to anywhere near that point.
 
Top