Messed up delayed cleaving attack

Faust

You can change this now in User CP.
Reaction score
123
JASS:
scope StormStrike initializer I

private struct StormStrike
    real damage
    unit attacker
    trigger t 
    unit target
    timer clock = CreateTimer()
    group damaged = CreateGroup()

    method onDestroy takes nothing returns nothing
        call DestroyGroup(.damaged)
        call PauseTimer(.clock)
        call ClearTimerStructA(.clock)
        call DestroyTimer(.clock)
    endmethod
endstruct

private function C takes nothing returns boolean
    return GetUnitAbilityLevel(GetEventDamageSource(), 'A01I') > 0
endfunction

private function H takes nothing returns nothing
    local StormStrike dat = GetTimerStructA(GetExpiredTimer())
    local group g = CreateGroup()
    local unit u
    set udg_Player = GetOwningPlayer(dat.attacker)
    call GroupEnumUnitsInRange(g, GetUnitX(dat.target), GetUnitY(dat.target), 200, Condition(function IsUnitAnEnemy))
    set u = FirstOfGroup(g)
    if IsUnitInGroup(u, dat.damaged) != true then
     call GroupAddUnit(dat.damaged, u)
     call BJDebugMsg(GetUnitName(dat.target) + " is damaged for " + R2S(dat.damage))
     call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl", u, "chest"))
     call DisableTrigger(dat.t)
     call UnitDamageTarget(dat.attacker, dat.target, dat.damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
     call EnableTrigger(dat.t)
    endif
    if dat.target == null then
     call BJDebugMsg("ended")
     call dat.destroy()
    endif
    set dat.target = u
    call DestroyGroup(g)
    set g = null
    set u = null
endfunction

private function A takes nothing returns nothing
    local StormStrike dat = StormStrike.create()
    set dat.attacker = GetEventDamageSource()
    set dat.target = GetTriggerUnit()
    set dat.damage = GetEventDamage()
    set dat.t = GetTriggeringTrigger()
    call SetTimerStructA(dat.clock, dat)
    call TimerStart(dat.clock, 0.01, true, function H)
endfunction

//===========================================================================
private function I takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitDamaged(t)
    call TriggerAddCondition(t, Condition(function C))
    call TriggerAddAction(t, function A)
endfunction

endscope


This I can't quite explain.
This is for a passive ability, it should act somewhat similar to any cleaving attack, except it is delayed, and only effects one unit at a time.
So you damage unit A, and there is a unit B nearby, to whom close there is unit C.

The damage is dealt to unit A again, and then to B once, and then to C once.

Like: <Damaged for 50 hp> -> A takes the 50 damage -> pause -> A takes it once again (for the total of 100) -> pause -> B takes it once (50) -> pause -> C takes it once -> if no more units nearby who have not been hit, the link breaks.
I added a pretty visible effect for testing, and I can safely say it's messed up.

There are PLENTY of units nearby, yet it always only effects the unit that was damaged by the hero's attack. It keeps up for a few minute, then I do something or noting at all, and the creeps a lot farther get the effect and damage several times (you can tell it from the thickness of the effect).

So what did I mess up and how to fix it? Thanks in advance!
 

Faust

You can change this now in User CP.
Reaction score
123
When I woke up this morning I think I found the problem, and correcter the function. But now the callback function is not called :\

JASS:
scope StormStrike initializer I

private struct StormStrike
    real damage
    unit attacker
    trigger t 
    unit target
    timer clock = CreateTimer()
    group damaged = CreateGroup()

    method onDestroy takes nothing returns nothing
        call GroupClear(.damaged)
        call DestroyGroup(.damaged)
        call PauseTimer(.clock)
        call ClearTimerStructA(.clock)
        call DestroyTimer(.clock)
    endmethod
endstruct

private function C takes nothing returns boolean
    return GetUnitAbilityLevel(GetEventDamageSource(), &#039;A01I&#039;) &gt; 0
endfunction

private function H takes nothing returns nothing
    local StormStrike dat = GetTimerStructA(GetExpiredTimer())
    local group g = CreateGroup()
    local unit u
    call GroupAddUnit(dat.damaged, u)
    call BJDebugMsg(&quot;Hello?&quot;)
    call BJDebugMsg(GetUnitName(dat.target) + &quot; is damaged for &quot; + R2S(dat.damage))
    call DestroyEffect(AddSpecialEffectTarget(&quot;Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl&quot;, u, &quot;chest&quot;))
    call DisableTrigger(dat.t)
    call UnitDamageTarget(dat.attacker, dat.target, dat.damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
    call EnableTrigger(dat.t)
    set udg_Player = GetOwningPlayer(dat.attacker)
    call GroupEnumUnitsInRange(g, GetUnitX(dat.target), GetUnitY(dat.target), 200, Condition(function IsUnitAnEnemy))
    loop
     set u = FirstOfGroup(g)
    exitwhen IsUnitInGroup(u, dat.damaged) == false
    endloop
    set dat.target = u
    if dat.target == null then
     call BJDebugMsg(&quot;ended&quot;)
     call dat.destroy()
    endif
    call DestroyGroup(g)
    set g = null
    set u = null
endfunction

private function A takes nothing returns nothing
    local StormStrike dat = StormStrike.create()
    set dat.attacker = GetEventDamageSource()
    set dat.target = GetTriggerUnit()
    set dat.damage = GetEventDamage()
    set dat.t = GetTriggeringTrigger()
    call BJDebugMsg(GetUnitName(dat.attacker) + GetUnitName(dat.target) + R2S(dat.damage))
    call SetTimerStructA(dat.clock, dat)
    call TimerStart(dat.clock, 0.10, true, function H)
endfunction

//===========================================================================
private function I takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitDamaged(t)
    call TriggerAddCondition(t, Condition(function C))
    call TriggerAddAction(t, function A)
endfunction

endscope


The bjdebugmsg appears in function A, but in H, nothing appears.
 

Faust

You can change this now in User CP.
Reaction score
123
I didn't know uninitialized units stop the function executing o.o

Well I have this now and it keeps picking the same unit until it dies or I remove the damage source wtf.

JASS:
scope StormStrike initializer I

globals
    private group G
endglobals

private struct StormStrike
    real damage
    unit attacker
    trigger t 
    unit target
    timer clock = CreateTimer()
    group damaged = CreateGroup()

    method onDestroy takes nothing returns nothing
        call GroupClear(.damaged)
        call DestroyGroup(.damaged)
        call PauseTimer(.clock)
        call ClearTimerStructA(.clock)
        call DestroyTimer(.clock)
    endmethod
endstruct

private function C takes nothing returns boolean
    return GetUnitAbilityLevel(GetEventDamageSource(), &#039;A01I&#039;) &gt; 0
endfunction

private function C2 takes nothing returns boolean
    return IsUnitAnEnemy() == true and IsUnitInGroup(GetFilterUnit(), G) == false
endfunction

private function H takes nothing returns nothing
    local StormStrike dat = GetTimerStructA(GetExpiredTimer())
    local group g = CreateGroup()
    local unit u
    call GroupAddUnit(dat.damaged, dat.target)
    call BJDebugMsg(GetUnitName(dat.target) + &quot; is damaged for &quot; + R2S(dat.damage))
    call DestroyEffect(AddSpecialEffectTarget(&quot;Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl&quot;, dat.target, &quot;chest&quot;))
    call DisableTrigger(dat.t)
    call UnitDamageTarget(dat.attacker, dat.target, dat.damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
    call EnableTrigger(dat.t)
    set udg_Player = GetOwningPlayer(dat.attacker)
    set G = dat.damaged
    call GroupEnumUnitsInRange(g, GetUnitX(dat.target), GetUnitY(dat.target), 500, Condition(function C2))
    set u = FirstOfGroup(g)
    call BJDebugMsg(GetUnitName(u) + &quot; is u&quot;)
    if u == null then
     call BJDebugMsg(&quot;Destroying&quot;)
     call dat.destroy()
    endif
    call DestroyGroup(g)
    set g = null
    set u = null
endfunction

private function A takes nothing returns nothing
    local StormStrike dat = StormStrike.create()
    set dat.attacker = GetEventDamageSource()
    set dat.target = GetTriggerUnit()
    set dat.damage = GetEventDamage()
    set dat.t = GetTriggeringTrigger()
    call BJDebugMsg(GetUnitName(dat.attacker) + GetUnitName(dat.target) + R2S(dat.damage))
    call SetTimerStructA(dat.clock, dat)
    call TimerStart(dat.clock, 0.33, true, function H)
endfunction

//===========================================================================
private function I takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitDamaged(t)
    call TriggerAddCondition(t, Condition(function C))
    call TriggerAddAction(t, function A)
endfunction

endscope
 

T.s.e

Wish I was old and a little sentimental
Reaction score
133
JASS:
IsUnitAnEnemy() == true

What function is that?
 

Faust

You can change this now in User CP.
Reaction score
123

T.s.e

Wish I was old and a little sentimental
Reaction score
133
No problem with that.
Eh, are you sure? Because I don't see how GetFilterUnit would carry over from the enum function into the IsUnitAnEnemy without arguments :/
 

Faust

You can change this now in User CP.
Reaction score
123
JASS:
scope StormStrike initializer I

globals
    private group G
endglobals

private struct StormStrike
    real damage
    unit attacker
    trigger t 
    unit target
    timer clock = CreateTimer()
    group damaged = CreateGroup()

    method onDestroy takes nothing returns nothing
        call GroupClear(.damaged)
        call DestroyGroup(.damaged)
        call PauseTimer(.clock)
        call ClearTimerStructA(.clock)
        call DestroyTimer(.clock)
    endmethod
endstruct

private function C takes nothing returns boolean
    return GetUnitAbilityLevel(GetEventDamageSource(), &#039;A01I&#039;) &gt; 0
endfunction

private function C2 takes nothing returns boolean
    if IsPlayerEnemy(GetOwningPlayer(GetFilterUnit()), udg_Player) and GetUnitAbilityLevel(GetFilterUnit(), &#039;Aloc&#039;) == 0 and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) &gt; 0 and IsUnitInGroup(GetFilterUnit(), G) != true then
     return true
    else
     return false
    endif
endfunction

private function H takes nothing returns nothing
    local StormStrike dat = GetTimerStructA(GetExpiredTimer())
    local group g = CreateGroup()
    local unit u
    call GroupAddUnit(dat.damaged, dat.target)
    call BJDebugMsg(GetUnitName(dat.target) + &quot; is damaged for &quot; + R2S(dat.damage))
    call DestroyEffect(AddSpecialEffectTarget(&quot;Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl&quot;, dat.target, &quot;chest&quot;))
    call DisableTrigger(dat.t)
    call UnitDamageTarget(dat.attacker, dat.target, dat.damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
    call EnableTrigger(dat.t)
    set udg_Player = GetOwningPlayer(dat.attacker)
    set G = dat.damaged
    call GroupEnumUnitsInRange(g, GetUnitX(dat.target), GetUnitY(dat.target), 500, Condition(function C2))
    set u = FirstOfGroup(g)
    call BJDebugMsg(GetUnitName(u) + &quot; is u&quot;)
    if u == null then
     call BJDebugMsg(&quot;Destroying&quot;)
     call dat.destroy()
    endif
    call DestroyGroup(g)
    set g = null
    set u = null
endfunction

private function A takes nothing returns nothing
    local StormStrike dat = StormStrike.create()
    set dat.attacker = GetEventDamageSource()
    set dat.target = GetTriggerUnit()
    set dat.damage = GetEventDamage()
    set dat.t = GetTriggeringTrigger()
    call BJDebugMsg(GetUnitName(dat.attacker) + GetUnitName(dat.target) + R2S(dat.damage))
    call SetTimerStructA(dat.clock, dat)
    call TimerStart(dat.clock, 0.33, true, function H)
endfunction

//===========================================================================
private function I takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitDamaged(t)
    call TriggerAddCondition(t, Condition(function C))
    call TriggerAddAction(t, function A)
endfunction

endscope


This didn't make it any better.

If there is only one unit in range, the struct is gone in the first run, only one effect, once displayed messages, everything is fine
But when there are more units, it gets bugged up.
 

WolfieeifloW

WEHZ Helper
Reaction score
372
Why the "udg_"'s?
Just make the globals in the code itself:
JASS:
globals
   private player PLAYER
endglobals

----------
And I don't think it'll fix it, but optimization of this:
JASS:
private function C2 takes nothing returns boolean
    if IsPlayerEnemy(GetOwningPlayer(GetFilterUnit()), udg_Player) and GetUnitAbilityLevel(GetFilterUnit(), &#039;Aloc&#039;) == 0 and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) &gt; 0 and IsUnitInGroup(GetFilterUnit(), G) != true then
     return true
    else
     return false
    endif
endfunction

It becomes this:
JASS:
private function C2 takes nothing returns boolean
    return IsPlayerEnemy(GetOwningPlayer(GetFilterUnit()), udg_Player) and GetUnitAbilityLevel(GetFilterUnit(), &#039;Aloc&#039;) == 0 and GetWidgetLife(GetFilterUnit()) &gt; 0.405 and not IsUnitInGroup(GetFilterUnit(), G)
endfunction
 

WolfieeifloW

WEHZ Helper
Reaction score
372
Both work;
But the second one works better.
It does the returning in one line plus uses GetWidgetLife(unit whichUnit).
 

Faust

You can change this now in User CP.
Reaction score
123
...
I don't care if it works better, right now it's not working at all
 

Rainther

I guess I should write something of value here...
Reaction score
61
I may have found the solution to at least one of the problems.
Correct me if I'm wrong, but GroupAddUnit doesn't work before you've established a group. I've had the problem myself and I solves it with
JASS:
set groupName = GetUnitsOfTypeIdAll(&#039;YeaH)

I don't have any unit called 'YeaH' so it simply creates a group for me with none inside it so that I can use GroupAddUnit freely.

I may be wrong, however I made it work in my case when I did this.ä

Or maybe you can use CreateGroup :p should work too.
 

Faust

You can change this now in User CP.
Reaction score
123
I use CreateGroup() in the struct, and in the handler.

Group 'G' is the same as dat.damaged, not different. I set G to dat.damaged so I can refer to it in a condition.

So 'G' is more of a keyword than a group.

You made it work you say? Made what work? This exact script, or CreateGroup() in some other instance?
 

Faust

You can change this now in User CP.
Reaction score
123
Erm, of course it is possible, and customary.
I could say, 'everyone does that'.
 

Rainther

I guess I should write something of value here...
Reaction score
61
/Rolleyes

Have mostly been for myself doing Jass so I haven't seen how others might do it, explaining my wierd way for the solution for example. I'll look into the Jass and see if there's anything which I don't see as "correct".

None of the things that you've entered in function H happends? Or does it stop before the Debug msg?
 

SanKakU

Member
Reaction score
21
that's only slightly interesting so i'm not reading the whole thread right now but i wanted to ask you did you know cleaving attack damages the surrounding units AND the attacked unit? in other words an attacked unit gets hurt by more than the damage by the pit lord so the attacked unit and the other units also get damaged by the cleave, obviously you have a special cleave attack and i'm not sure if know this matters in your coding since i didn't look at it all but in case it does, there you go.

yeah i'm pretty sure something like orb of fire does not work that way...
 

Faust

You can change this now in User CP.
Reaction score
123
Already been said: http://www.thehelper.net/forums/showpost.php?p=1050112&postcount=8

@SanKaKU

This ability is "based on" a unit ability of Heroes of Might and Magic V (The Thane and Thunder Thane from Fortress).

Besides usual damage, this creature strikes the target with lightning (non-magical damage), which then hits another enemy creature if one is standing near the target, continuing on in this way until the chain is broken. The lighting's force is equal to that of the attack.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top