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

[JASS] UnitDamageTarget - Problems

Status
Not open for further replies.
Level 4
Joined
Apr 2, 2006
Messages
32
I'm making Impetus from dota, a spell where a projectile is thrown and after the target unit is hit, it takes a certain % of the distance the projectile covered in damage. I can do all of this just fine, although, I have run into a strange problem when I want to damage the target unit. If I use the UnitDamageTarget action, the game exits as soon as the projectile hits the target (as soon as it takes the damage).

The spell is auto-castable, which means the projectiles should fire whenever the spell is under auto-castable effects, but, at the moment, I'm still trying to get the "EVENT_UNIT_SPELL_EFFECT" side of things working. Afterwards, I'll add in more to the trigger which makes the auto-casting stuff work.

Here is my current code (WIP):
JASS:
scope Impetus

globals
    private constant integer Imp_ID       = 'A000'
    private constant real Percent_Base    = 0.04
    private constant real Max_Dmg         = 375
    private constant real Texttag_Vlcty   = 60
    private constant real Texttag_Size    = 10
    private constant real Texttag_Red     = 5
    private constant real Texttag_Green   = 80
    private constant real Texttag_Blue    = 85
    private constant real Texttag_Trsprcy = 8
    private constant real Texttag_Angle   = 90
    private constant real Texttag_Durtn   = 1.25
    private constant string Order_ID      = "flamingarrows"
    private constant string Un_Order_ID   = "unflamingarrows"
endglobals

struct Imp_Data
    unit U
endstruct

struct Imp_Data_2
    unit u
    unit h
    triggeraction a
endstruct

private function Impetus_Conditions_2 takes nothing returns boolean
    if GetTriggerEventId() == EVENT_UNIT_SPELL_EFFECT and GetSpellAbilityId() == Imp_ID then
        return true
    endif
    return false
endfunction

private function Impetus_Actions_3 takes nothing returns nothing
    local trigger x    = GetTriggeringTrigger()
    local Imp_Data_2 D = Imp_Data_2(GetHandleInt(x, "D"))
    local real X1      = GetUnitX(D.u)
    local real Y1      = GetUnitY(D.u)
    local real X2      = GetUnitX(D.h)
    local real Y2      = GetUnitY(D.h)
    local real dist    = SquareRoot((X2-X1) * (X2-X1) + (Y2-Y1) * (Y2-Y1))
    local real dmg     = (GetUnitAbilityLevel(D.u, Imp_ID) * Percent_Base) * dist
    local texttag t
 
    if D.u == GetEventDamageSource() then  
        if dmg > Max_Dmg then
            set dmg = Max_Dmg
        endif
        call UnitDamageTarget(D.u, D.h, dmg, false, false, ATTACK_TYPE_HERO, DAMAGE_TYPE_DIVINE, null)
        set t = CreateTextTagUnitBJ("+" + I2S(R2I(dmg)), D.h, Texttag_Vlcty, Texttag_Size, Texttag_Red, Texttag_Green, Texttag_Blue, Texttag_Trsprcy)
        call SetTextTagVelocityBJ(t, Texttag_Vlcty, Texttag_Angle)
        call PolledWait(Texttag_Durtn)
        call DestroyTextTag(t)
    endif

    call FlushHandleLocals(x)
    call TriggerRemoveAction(x, D.a)
    call DestroyTrigger(x)
    call D.destroy()

    set x = null
    set t = null
endfunction

private function Impetus_Actions_2 takes nothing returns nothing
    local trigger z    = GetTriggeringTrigger()
    local Imp_Data d   = Imp_Data(GetHandleInt(z, "d")) 
    local Imp_Data_2 D = Imp_Data_2.create()  
    local trigger x    = CreateTrigger() 

    if GetTriggerEventId() == EVENT_UNIT_SPELL_EFFECT then
        set D.h = GetSpellTargetUnit()
    endif

    set D.u = d.U
    call TriggerRegisterUnitEvent(x, D.h, EVENT_UNIT_DAMAGED)
    set D.a = TriggerAddAction(x, function Impetus_Actions_3)    

    call SetHandleInt(x, "D", D)

    set z = null
    set x = null
endfunction

private function Impetus_Actions takes nothing returns nothing
    local unit u     = GetTriggerUnit()
    local trigger t  = CreateTrigger()
    local boolexpr b = Condition(function Impetus_Conditions_2)
    local Imp_Data d = Imp_Data.create()  

    set d.U = u

    call TriggerRegisterUnitEvent(t, u, EVENT_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, b)
    call TriggerAddAction(t, function Impetus_Actions_2)
    call SetHandleInt(t, "d", d)

    call DestroyBoolExpr(b)

    set u = null
    set t = null
    set b = null
endfunction

private function Impetus_Conditions takes nothing returns boolean
    return GetLearnedSkill() == Imp_ID
endfunction

function InitTrig_Impetus takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL) 
    call TriggerAddCondition(t, Condition(function Impetus_Conditions))
    call TriggerAddAction(t, function Impetus_Actions)
    set t = null
endfunction

endscope


So there it is, my problem lies in the Impetus_Actions_3 function.
Everything works 100% perfect apart from the UnitDamageTarget line.
I know it's that line because after removing it, then testing the spell it doesn't exit the game/crash/malfunction.

What could be the problem here?
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Anyways, the problem is;

You detect when the unit is damaged and then run those actions.

However, when the unit is damaged it fires the actions again, causing more damage which fires the actions again and so on.

Destroy the trigger right at the start of the function.
 
Last edited:
Level 4
Joined
Apr 2, 2006
Messages
32
The CreateTextTagUnitBJ saves me some lines, even though it is highly inefficient compared to creating it "manually" with natives =p

I've had bad experiences with setting a texttag's velocity when using the native.
So I just stick to the BJ version and it works fine (I think most people do).

Well, anyway, I've completed the coding for Impetus, but, the only problem is,
is that, it isn't that MUI. For example, If I put down say 10 heroes, give them
the ability, make them learn it, and then get them all to attack the same unit
all having the ability on auto-cast, only 1 caster manages to damage the unit
at a time. This is highly annoying because I was aiming to make this spell 100%
MUI, and also enhanced with New Gen.

What could the problem be now?
JASS:
scope Impetus

globals
    private constant integer Imp_ID       = 'A000'
    private constant real Percent_Base    = 0.04
    private constant real Max_Dmg         = 375
    private constant real Texttag_Vlcty   = 60
    private constant real Texttag_Size    = 10
    private constant real Texttag_Red     = 5
    private constant real Texttag_Green   = 80
    private constant real Texttag_Blue    = 85
    private constant real Texttag_Trsprcy = 8
    private constant real Texttag_Angle   = 90
    private constant real Texttag_Durtn   = 1.25
    private constant real Cut_Off_Durtn   = 2.5
    private constant string Order_ID      = "flamingarrows"
    private constant string Un_Order_ID   = "unflamingarrows"
    private constant string SFX           = "Abilities\\Spells\\Orc\\FeralSpirit\\feralspiritdone.mdl"
    private constant string SFX_Point     = "origin"
endglobals

struct Imp_Data
    unit U
    boolean b
endstruct

struct Imp_Data_2
    unit u
    unit h
    triggeraction a
    real OX
    real OY
endstruct

private function Impetus_Conditions_2 takes nothing returns boolean
    local trigger t  = GetTriggeringTrigger()
    local Imp_Data d = Imp_Data(GetHandleInt(t, "d"))

    if GetTriggerEventId() == EVENT_UNIT_SPELL_EFFECT and GetSpellAbilityId() == Imp_ID then
        return true
    elseif GetTriggerEventId() == EVENT_PLAYER_UNIT_ATTACKED and GetUnitAbilityLevel(GetAttacker(), Imp_ID) > 0 and d.b == true and IsUnitType(GetTriggerUnit(), UNIT_TYPE_STRUCTURE) == false and GetAttacker() == d.U then
	return true
    elseif GetTriggerEventId() == EVENT_UNIT_ISSUED_ORDER then
        if GetIssuedOrderId() == OrderId(Order_ID) then
            set d.b = true
        elseif GetIssuedOrderId() == OrderId(Un_Order_ID) then
            set d.b = false
        endif
    endif

    set t = null
    return false
endfunction

private function Impetus_Actions_3 takes nothing returns nothing
    local trigger x    = GetTriggeringTrigger()
    local Imp_Data_2 D = Imp_Data_2(GetHandleInt(x, "D"))
    local real X2      = GetUnitX(D.h)
    local real Y2      = GetUnitY(D.h)
    local real dist    = SquareRoot((X2-D.OX) * (X2-D.OX) + (Y2-D.OY) * (Y2-D.OY))
    local real dmg     = (GetUnitAbilityLevel(D.u, Imp_ID) * Percent_Base) * dist
    local texttag t

    call TriggerRemoveAction(x, D.a)
    call FlushHandleLocals(x)
    call DestroyTrigger(x)
 
    if D.u == GetEventDamageSource() then  
        if dmg > Max_Dmg then
            set dmg = Max_Dmg
        endif
        call DestroyEffect(AddSpecialEffectTarget(SFX, D.h, SFX_Point))
        call UnitDamageTarget(D.u, D.h, dmg, false, false, ATTACK_TYPE_HERO, DAMAGE_TYPE_DIVINE, null)
        set t = CreateTextTagUnitBJ("+" + I2S(R2I(dmg)), D.h, Texttag_Vlcty, Texttag_Size, Texttag_Red, Texttag_Green, Texttag_Blue, Texttag_Trsprcy)
        call SetTextTagVelocityBJ(t, Texttag_Vlcty, Texttag_Angle)
        call SetTextTagPermanent(t, false)
        call SetTextTagLifespan(t, Texttag_Durtn)
    endif

    call D.destroy()

    set x = null
    set t = null
endfunction

private function Impetus_Actions_2 takes nothing returns nothing
    local trigger z    = GetTriggeringTrigger()
    local Imp_Data d   = Imp_Data(GetHandleInt(z, "d")) 
    local Imp_Data_2 D = Imp_Data_2.create()  
    local trigger x    = CreateTrigger() 

    if GetTriggerEventId() == EVENT_UNIT_SPELL_EFFECT then
        set D.h = GetSpellTargetUnit()
    else
        set D.h = GetTriggerUnit()
    endif

    set D.u = d.U
    set D.OX = GetUnitX(D.u)
    set D.OY = GetUnitY(D.u)
    call TriggerRegisterUnitEvent(x, D.h, EVENT_UNIT_DAMAGED)
    set D.a = TriggerAddAction(x, function Impetus_Actions_3)  
    call SetHandleInt(x, "D", D)

    //Safety
    call PolledWait(Cut_Off_Durtn)
    call TriggerRemoveAction(x, D.a)
    call FlushHandleLocals(x)
    call DestroyTrigger(x)
    call D.destroy()
    //

    set z = null
    set x = null
endfunction

private function Impetus_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local trigger t  
    local Imp_Data d   

    if GetUnitAbilityLevel(u, Imp_ID) == 1 then
        set d = Imp_Data.create()
        set d.U = u
        set d.b = false
        set t = CreateTrigger()

	call TriggerRegisterUnitEvent(t, d.U, EVENT_UNIT_ISSUED_ORDER)
        call TriggerRegisterUnitEvent(t, d.U, EVENT_UNIT_SPELL_EFFECT)
	call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ATTACKED)
        call TriggerAddCondition(t, Condition(function Impetus_Conditions_2))
        call TriggerAddAction(t, function Impetus_Actions_2)
        call SetHandleInt(t, "d", d)

        set t = null
    endif

    set u = null
endfunction

private function Impetus_Conditions takes nothing returns boolean
    return GetLearnedSkill() == Imp_ID
endfunction

function InitTrig_Impetus takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL) 
    call TriggerAddCondition(t, Condition(function Impetus_Conditions))
    call TriggerAddAction(t, function Impetus_Actions)
    set t = null
endfunction

endscope
 
Level 4
Joined
Apr 2, 2006
Messages
32
> Something else is the problem here.

I feared that.

> Probably has to do with the fact that any unit can trigger the damage event... add a condition.

I have a condition in the Actions_3 function:
JASS:
if D.u == GetEventDamageSource() then
...
endif
Or did you mean something slightly different?
 
Level 4
Joined
Apr 2, 2006
Messages
32
> you destroy the trigger even if the attacker wasn't the right one, that could be a problem.

You mean here:
JASS:
private function Impetus_Actions_3 takes nothing returns nothing
    local trigger x    = GetTriggeringTrigger()
    local Imp_Data_2 D = Imp_Data_2(GetHandleInt(x, "D"))
    local real X2      = GetUnitX(D.h)
    local real Y2      = GetUnitY(D.h)
    local real dist    = SquareRoot((X2-D.OX) * (X2-D.OX) + (Y2-D.OY) * (Y2-D.OY))
    local real dmg     = (GetUnitAbilityLevel(D.u, Imp_ID) * Percent_Base) * dist
    local texttag t

    call TriggerRemoveAction(x, D.a)
    call FlushHandleLocals(x)
    call DestroyTrigger(x)
 
    if D.u == GetEventDamageSource() then  
        if dmg > Max_Dmg then
            set dmg = Max_Dmg
        endif
        call DestroyEffect(AddSpecialEffectTarget(SFX, D.h, SFX_Point))
        call UnitDamageTarget(D.u, D.h, dmg, false, false, ATTACK_TYPE_HERO, DAMAGE_TYPE_DIVINE, null)
        set t = CreateTextTagUnitBJ("+" + I2S(R2I(dmg)), D.h, Texttag_Vlcty, Texttag_Size, Texttag_Red, Texttag_Green, Texttag_Blue, Texttag_Trsprcy)
        call SetTextTagVelocityBJ(t, Texttag_Vlcty, Texttag_Angle)
        call SetTextTagPermanent(t, false)
        call SetTextTagLifespan(t, Texttag_Durtn)
    endif

    call D.destroy()

    set x = null
    set t = null
endfunction
Is there anyway to fix this?
 
Status
Not open for further replies.
Top