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

[JASS] UnitDamageTarget not working

Status
Not open for further replies.
Level 11
Joined
Sep 14, 2009
Messages
284
I gone through my code countless times, and I just cannot find what is the problem here. The spell deals damage sometimes, and sometimes it does not. But the dummy using soulburn inside the loop always works, but the damage does not.

And no, it's not becuase it's non-MUI. There is only one unit with the ability on the entire map.

Code:
JASS:
globals
    boolean darkEruptionOnCD = false
    unit darkEruptionCaster = null
endglobals
//===========================================================================
function DarkEruptionResetCD takes nothing returns nothing
    call DestroyTimer(GetExpiredTimer())
    set darkEruptionOnCD = false
endfunction
function DarkEruptionDummyIndicatorDeath_Conditions takes nothing returns boolean
    return GetUnitTypeId(GetTriggerUnit()) == 'u001'
endfunction
function DarkEruptionDummyIndicatorDeath_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local group g = CreateGroup()
    local player p = GetOwningPlayer(u)
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local unit dum = null
    call DestroyEffect(AddSpecialEffect("MDX\\Effect_DarkEruption.mdx", x, y))
    call GroupEnumUnitsInRange(g, x, y, 220, null)
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        if IsUnitEnemy(u, p) and GetUnitState(u, UNIT_STATE_LIFE) > 0 and GetUnitAbilityLevel(u, dumAbility) == 0 then
            set dmgTypeAbility = true
            set dmgTypeMagic = true
            call UnitDamageTarget(darkEruptionCaster, u, 800, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
            set dmgTypeMagic = false
            set dmgTypeAbility = false
            set dum = CreateUnit(p, 'uloc', GetUnitX(u), GetUnitY(u), 0)
            call UnitApplyTimedLife(dum, 'BTLF', 1.5)
            call UnitAddAbility(dum, 'A00L')
            call SetUnitAbilityLevel(dum, 'A00L', 2)
            call IssueTargetOrder(dum, "soulburn", u)
        endif
        call GroupRemoveUnit(g, u)
    endloop
    call DestroyGroup(g)
    set g = null
    set p = null
    set dum = null
endfunction
//===========================================================================
function DarkEruptionCast_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A00K'
endfunction
function DarkEruptionCast_Actions takes nothing returns nothing
    local unit targ = GetSpellTargetUnit()
    local unit dum = null
    set darkEruptionCaster = GetTriggerUnit()
    set darkEruptionOnCD = true
    set dum = CreateUnit(GetOwningPlayer(darkEruptionCaster), 'u001', GetUnitX(targ), GetUnitY(targ), GetRandomReal(0, 360))
    call UnitApplyTimedLife(dum, 'BTLF', 5)
    call UnitRemoveAbility(darkEruptionCaster, 'A00K')
    call TimerStart(CreateTimer(), 12.5, false, function DarkEruptionResetCD)
    set targ = null
    set dum = null
endfunction
//===========================================================================
function DarkEruption_Conditions takes nothing returns boolean
    local unit atkd = GetTriggerUnit()
    local boolean b = false
    if darkEruptionOnCD == false and GetUnitAbilityLevel(atkd, 'A00G') >= 1 and GetUnitState(atkd, UNIT_STATE_LIFE) <= 0.55 * GetUnitState(atkd, UNIT_STATE_MAX_LIFE) then
        set b = true
    endif
    set atkd = null
    return b
endfunction
function DarkEruption_Actions takes nothing returns nothing
    local unit atkd = GetTriggerUnit()
    call UnitAddAbility(atkd, 'A00K')
    call IssueTargetOrder(atkd, "forkedlightning", GetAttacker())
    set atkd = null
endfunction
//===========================================================================
function InitTrig_DarkEruption takes nothing returns nothing
    local trigger DarkEruptionCast = CreateTrigger()
    local trigger DarkEruptionDummyIndicatorDeath = CreateTrigger()
    set gg_trg_DarkEruption = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_DarkEruption, EVENT_PLAYER_UNIT_ATTACKED)
    call TriggerAddCondition(gg_trg_DarkEruption, Condition(function DarkEruption_Conditions))
    call TriggerAddAction(gg_trg_DarkEruption, function DarkEruption_Actions)
    //----------
    call TriggerRegisterAnyUnitEventBJ(DarkEruptionCast, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(DarkEruptionCast, Condition(function DarkEruptionCast_Conditions))
    call TriggerAddAction(DarkEruptionCast, function DarkEruptionCast_Actions)
    //----------
    call TriggerRegisterAnyUnitEventBJ(DarkEruptionDummyIndicatorDeath, EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddCondition(DarkEruptionDummyIndicatorDeath, Condition(function DarkEruptionDummyIndicatorDeath_Conditions))
    call TriggerAddAction(DarkEruptionDummyIndicatorDeath, function DarkEruptionDummyIndicatorDeath_Actions)
endfunction
 
Level 15
Joined
Mar 25, 2016
Messages
1,327
I am trying to understand what your spell is supposed to do:

A passive ability, that triggers a forked lightning, when the owner of the ability is attacked.
An eruption dummy is created a the target's position and the ability is set to be on cooldown for 12.5 seconds.
Once the dummy expires nearby enemies are damaged and soulburned.

Please correct me if I am wrong.

But the dummy using soulburn inside the loop always works, but the damage does not.

Maybe darkEruptionCaster is null? Even though it should not be null, it could be the reason for not dealing damage.
Try to use debug messages to verify that darkEruptionCaster is the correct unit. u is not the problem, as it is used below without problems.

Maybe something with your damage system does not work correctly and the damage is not dealt because of it.
 
Level 11
Joined
Sep 14, 2009
Messages
284
I used your method and was able to confirm that darkEruptionCaster is never null, so the problem does not lie there. I was able to identify that the problem cease when I disable the trigger below. I suppose the math is messed up somewhere. If you can see where I would greatly appreciate it.

The code uses Agility as a custom stat (Resistance) which reduces a custom damage type called dmgTypeMagic.

Code:
JASS:
function GetResistance_Conditions takes nothing returns boolean
    return dmgTypeMagic == true
endfunction
function GetResistance_Actions takes nothing returns nothing
    local real r = 1
    local unit source = dmgEvSource
    local unit targ = dmgEvTarg
    local real hAgi = I2R(GetHeroAgi(targ, true))
    local integer i = 0
    //Resistance stat
    if hAgi > 0 then
        loop
            //Item that causes the wearer to ignore 50% of resistance, but also cause enemies to ignore 50% of wearers resitance
            if GetItemTypeId(UnitItemInSlot(source, i)) == 'I001' or GetItemTypeId(UnitItemInSlot(targ, i)) == 'I001' then
                set hAgi = hAgi * 0.5
                set i = 6
            endif
            exitwhen i >= 6
            set i = i + 1
        endloop
        set r = r - (hAgi/(100 + hAgi))
    endif
    //Final calculation
    if r <= 0 then
        set dmgEvAmt = 0
    else
        set dmgEvAmt = dmgEvAmt * r
    endif
    set source = null
    set targ = null
endfunction
//===========================================================================
function InitTrig_GetResistance takes nothing returns nothing
    set gg_trg_GetResistance = CreateTrigger()
    call TriggerRegisterVariableEvent(gg_trg_GetResistance, "dmgEvMod", EQUAL, 1.0)
    call TriggerAddCondition(gg_trg_GetResistance, Condition(function GetResistance_Conditions))
    call TriggerAddAction(gg_trg_GetResistance, function GetResistance_Actions)
endfunction
 
Level 15
Joined
Mar 25, 2016
Messages
1,327
Maybe if used on units(no agility) something weird happens?

How much agility does a hero have?

I did not see a mistake in this trigger.

Try debug message again. Display r. If r is 0 you know that this trigger causes the bug.

Remove the block with the item and try again. Maybe this causes the bug.
 
Level 11
Joined
Sep 14, 2009
Messages
284
I was hoping I not had to spoil my map, but it seems I cannot avoid posting the log.






As you can see r is reduced as intended. However, as you can see original damage is still 800, and the hero hit by the purple stuff (Dark Eruption) simply does not take any damage at all.

Since when I disable this trigger, the damage is dealt but not reduced. I suppose the problem must occur when this trigger is combined with the damage detection system (it's a modified version of Bribe's dds).

I will post it here but I worry any one will have te time to look through it. (I have done it myself but I dont understand it)

JASS:
globals
    boolean dmgEvOverride = false
    boolean array dmgEvUnitDmgReg
    integer dmgEvBlockAbility = 'AIlz'
    integer dmgEvN = 0
    integer dmgEvType = 0
    integer dmgEvTypePrev = 0
    integer dmgEvsWasted = 0
    real dmgEv = 0
    real dmgEvAmt = 0
    real dmgEvLife = 0
    real dmgEvMod = 0
    real dmgEvPrevAmt = 0
    timer dmgEvTimer = CreateTimer()
    trigger dmgEvTrig = CreateTrigger()
    unit dmgEvSource = null
    unit dmgEvTarg = null
    unit dmgEvTempUnit = null
    unit array dmgEvStack
endglobals
//===========================================================================
function DmgEvRemoveAbils takes nothing returns nothing
    local real r = 0
    loop
        set dmgEvN = dmgEvN - 1
        set r = GetWidgetLife(dmgEvStack[dmgEvN])
        call UnitRemoveAbility(dmgEvStack[dmgEvN], dmgEvBlockAbility)
        call SetWidgetLife(dmgEvStack[dmgEvN], r)
        set dmgEvStack[dmgEvN] = null
        exitwhen dmgEvN == 0
    endloop
endfunction
//===========================================================================
function DmgEvSetVars takes nothing returns nothing
    set dmgEvAmt = GetEventDamage()
    set dmgEvSource = GetEventDamageSource()
    set dmgEvTarg = GetTriggerUnit()
endfunction
//===========================================================================
function FireDmgEv takes nothing returns nothing
    local boolean b = GetUnitAbilityLevel(dmgEvTarg, dmgEvBlockAbility) > 0
    local real life = 0
    local real pain = 0
    if b then
        set life = GetWidgetLife(dmgEvTarg)
        call UnitRemoveAbility(dmgEvTarg, dmgEvBlockAbility)
        call SetWidgetLife(dmgEvTarg, life)
        set pain = GetWidgetLife(dmgEvTarg)
    endif
    set dmgEvPrevAmt = dmgEvAmt
    set dmgEvOverride = false
    if dmgEvAmt == 0.00 then
        set dmgEv = 2.00
    else
        set dmgEvMod = 1.00
        set dmgEv = 1.00
    endif
    if b then
        call UnitAddAbility(dmgEvTarg, dmgEvBlockAbility)
        call SetWidgetLife(dmgEvTarg, life + GetWidgetLife(dmgEvTarg) - pain)
    endif
    if dmgEvAmt != dmgEvPrevAmt then
        set dmgEvLife = GetUnitState(dmgEvTarg, UNIT_STATE_LIFE) + (dmgEvPrevAmt - dmgEvAmt)
        if dmgEvAmt > dmgEvPrevAmt then
            call SetUnitState(dmgEvTarg, UNIT_STATE_LIFE,  RMaxBJ(0.41, dmgEvLife))
            if dmgEvLife <= .405 then
                call DisableTrigger(dmgEvTrig)
                call UnitDamageTarget(dmgEvSource, dmgEvTarg, 999, false, false, null, null, null)
                call EnableTrigger(dmgEvTrig)
            endif
        else
            if GetUnitState(dmgEvTarg, UNIT_STATE_MAX_LIFE) < dmgEvLife then
                call UnitAddAbility(dmgEvTarg, dmgEvBlockAbility)
                set dmgEvStack[dmgEvN] = dmgEvTarg
                set dmgEvN = dmgEvN + 1
                if dmgEvN == 1 then
                    call TimerStart(dmgEvTimer, 0, false, function DmgEvRemoveAbils)
                endif
            endif
            call SetUnitState(dmgEvTarg, UNIT_STATE_LIFE, dmgEvLife)
        endif
    endif
endfunction
//===========================================================================
function FireRecursiveDmgEv takes nothing returns nothing
    local real d = dmgEvAmt
    local unit s = dmgEvSource
    local unit t = dmgEvTarg
    local integer ptype = dmgEvTypePrev
    local boolean override = dmgEvOverride
    local real prev = dmgEvPrevAmt
    call DmgEvSetVars()
    if dmgEvTarg != t or dmgEvSource != s or dmgEvAmt != d or dmgEvType != ptype then
        set dmgEv = 0.00
        set dmgEvMod = 0.00
        call FireDmgEv()
    else
        call DisplayTextToPlayer(Player(8), 0, 0, "|cffFF2222Warning|r: Damage detection system recursion bug. Please report to the map creator. Thanks.")
    endif
    set dmgEvOverride = override
    set dmgEvPrevAmt = prev
    set dmgEvTypePrev = ptype
    set dmgEvAmt = d
    set dmgEvSource = s
    set dmgEvTarg = t
    set s = null
    set t = null
endfunction
//===========================================================================
function OnDmgEv takes nothing returns boolean
    if dmgEv == 0.00 then
        set dmgEvTypePrev = dmgEvType
        call DmgEvSetVars()
        call FireDmgEv()
        set dmgEvMod = 0.00
        set dmgEv = 0.00
        set dmgEvType = 0
    else
        call FireRecursiveDmgEv()
    endif
    return false
endfunction
//===========================================================================
function CreateDmgEv takes nothing returns nothing
    set dmgEvTrig = CreateTrigger()
    call TriggerAddCondition(dmgEvTrig, Filter(function OnDmgEv))
endfunction
//===========================================================================
function SetupDmgEv takes nothing returns boolean
    local integer pdex = uDex
    if uDexEvent == 1.00 then
        set dmgEvTempUnit = uDexUnits[uDex]
        if GetUnitAbilityLevel(dmgEvTempUnit, 'Aloc') == 0 then
            set dmgEvUnitDmgReg[uDex] = true
            call TriggerRegisterUnitEvent(dmgEvTrig, dmgEvTempUnit, EVENT_UNIT_DAMAGED)
        endif
    else
        if dmgEvUnitDmgReg[uDex] == true then
            set dmgEvUnitDmgReg[uDex] = false
            set dmgEvsWasted = dmgEvsWasted + 1
            if dmgEvsWasted == 15 then
                set dmgEvsWasted = 0
                call DestroyTrigger(dmgEvTrig)
                call CreateDmgEv()
                set uDex = uDexNext[0]
                loop
                    exitwhen uDex == 0
                    if dmgEvUnitDmgReg[uDex] == true then
                        call TriggerRegisterUnitEvent(dmgEvTrig, uDexUnits[uDex], EVENT_UNIT_DAMAGED)
                    endif
                    set uDex = uDexNext[uDex]
                endloop
                set uDex = pdex
            endif
        endif
    endif
    return false
endfunction
//===========================================================================
function InitDmgEv takes nothing returns nothing
    local trigger t = GetTriggeringTrigger()
    call CreateDmgEv()
    call TriggerAddCondition(t, Filter(function SetupDmgEv))
    set uDexEnabled = false
    set dmgEvTempUnit = CreateUnit(Player(15), 'uloc', 0, 0, 0)
    set uDexEnabled = true
    call UnitAddAbility(dmgEvTempUnit, dmgEvBlockAbility)
    call RemoveUnit(dmgEvTempUnit)
    call TimerStart(dmgEvTimer, 0.00, false, null)
    if TriggerEvaluate(t) then
        call TriggerExecute(t)
    endif
    set t = null
endfunction
//===========================================================================
function InitTrig_DamageEngine takes nothing returns nothing
    set gg_trg_DamageEngine = CreateTrigger()
    call TriggerRegisterVariableEvent(gg_trg_DamageEngine, "uDexEvent", EQUAL, 1.00)
    call TriggerRegisterVariableEvent(gg_trg_DamageEngine, "uDexEvent", EQUAL, 2.00)
    call TriggerAddAction(gg_trg_DamageEngine, function InitDmgEv)
endfunction
 

Attachments

  • r.jpg
    r.jpg
    1.1 MB · Views: 138
Level 15
Joined
Mar 25, 2016
Messages
1,327
You should put the debug message that displays dmgEvAmt at the end of your trigger, so you see what dmgEvAmt is after the trigger.

Your trigger runs when dmgEvMod==1 maybe another trigger at dmgEvMod==2 changes dmgEvAmt to 0.
But then it would not make sense, that disabling the trigger solves the problem.
 
Level 11
Joined
Sep 14, 2009
Messages
284
use "true, true" options instead of "false, true"
JASS:
call UnitDamageTarget(dmgEvSource, dmgEvTarg, 999, false, false, null, null, null)
Just out of curiousity, why?

You should put the debug message that displays dmgEvAmt at the end of your trigger, so you see what dmgEvAmt is after the trigger.

Your trigger runs when dmgEvMod==1 maybe another trigger at dmgEvMod==2 changes dmgEvAmt to 0.
But then it would not make sense, that disabling the trigger solves the problem.

There are no other triggers that uses "dmgEvMod" event. I noticed however that I was wrong. Becuase the units had full hp, I thought no damage was dealt, but when damaged units are hit by the eruption, their health are restored instead o_O. So there must be a math problem somewhere.
Thanks for putting so much effort into helping me btw :)

EDIT: Solved. The problem was the DDS(Bribe's). Replaced it with a different DDS(IDDS) and works perfectly now.
 
Last edited:
Status
Not open for further replies.
Top