• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

Textmacro/Loop Problem

Status
Not open for further replies.
Level 13
Joined
Jan 2, 2016
Messages
973
Now I have another problem tho:
The 2-nd and the 3-rd (type of) effect loops, just as I want it to, while the 1-st appears only once, and that's it....

EDIT: I made it a textmacro, to make sure I haven't misspelled anything, but still doesn't loop:
JASS:
//! textmacro SEF_EndUnFade takes LETTER
set $LETTER$B[i] = false
call PauseUnit(u, false)
call UnitAddAbility(u, 'A02O')
call IssuePointOrder(u, "channel", SEF_X[i], SEF_Y[i])
call SaveEffectHandle(udg_Unit_Table, GetHandleId(u), 'sefe', AddSpecialEffectTarget( s, u, "origin"))
//! endtextmacro

            if SU[i] == u and SB[i] then
                set s = "Doodads\\Cinematic\\Lightningbolt\\Lightningbolt.mdl"
                //! runtextmacro SEF_EndUnFade("S")
            elseif EU[i] == u and EB[i] then
                set s = "Abilities\\Spells\\Orc\\EarthQuake\\EarthQuakeTarget.mdl"
                //! runtextmacro SEF_EndUnFade("E")
            elseif FU[i] == u and FB[i] then
                set s = "Doodads\\Cinematic\\TownBurningFireEmitter\\TownBurningFireEmitter.mdl"
                //! runtextmacro SEF_EndUnFade("F")
            endif

lol, this trigger has 6 textmacros to save space, yet it's still my longest trigger x_x


EDIT 2: would it be wise to just put doodads (trough the volcano skill), with the right model at the units' positions instead?
 
Last edited by a moderator:
Level 13
Joined
Jan 2, 2016
Messages
973
I did it with textmacro to save space. I have 6x textmacros in this trigger, and it's still my longest trigger (and it's using functions from libraries too) ,and it's still just about 80% complete :vw_death:
Anyways. I will keep adding more functions inside this textmacro once I figure out how to make the special effect (lightning bolt) looping.

I don't expect you to understand what's going on if you look at the whole trigger, but I'll post it anyways..
JASS:
scope StormEarthFire //initializer InitTrig_SEF

    globals
        boolean array SB // Storm boolean - a storm unit has been absorbed
        boolean array EB // Earth boolean - an earth unit has been absorbed
        boolean array FB // Fire boolean - a fire unit has been absorbed
        unit array SU // Storm unit
        unit array EU // Earth unit
        unit array FU // Fire unit
        unit array SEF_U // Caster
        real array SEF_X // X of cast point
        real array SEF_Y // Y of cast point
        timer array SEF_T // Cooldown timers
        integer array SEF_C // Storm Earth and Fire count - counts how many units have been absorbed
        integer array TC // time count
        integer array Current_Type
        effect array SEF_E
        private trigger Fade = CreateTrigger()
        private trigger UnFade = CreateTrigger()
        timerdialog array SEF_TD
    endglobals
    
    private function GetIndex takes timer t returns integer
        local integer i = 0
        loop
            exitwhen i > 11
            if t == SEF_T[i] then
                return i
            endif
            set i = i + 1
        endloop
        return 12
    endfunction
    
//! textmacro SEF_OutOfTime takes LETTER, ORBL
if $LETTER$B[i] then
    call RemoveUnit($LETTER$U[i])
    set $LETTER$B[i] = false
    set $LETTER$U[i] = null
    call UnitRemoveAbility( SEF_U[i], 'A02$ORBL$')
endif
//! endtextmacro
    
    private function OutOfTime takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer i = GetIndex(t)
        call TimerDialogDisplayForPlayerBJ( false, SEF_TD[i] , Player(i))
        if Current_Type[i] > 0 then
            set t = null
            return
        endif
        //! runtextmacro SEF_OutOfTime("S","L")
        //! runtextmacro SEF_OutOfTime("E","K")
        //! runtextmacro SEF_OutOfTime("F","M")
        if SEF_C[i] == 3 then
            call UnitRemoveAbility( SEF_U[i], 'A02N')
            call UnitAddAbility( SEF_U[i], 'A02J')
        endif
        call DisplayTextToPlayer(Player(i), 0, 0, "You didn't use Storm Earth and Fire on time, so the souls of your units passed away")
        set SEF_C[i] = 0
    endfunction
    
//! textmacro SEF_EndUnFade takes LETTER
set $LETTER$B[i] = false
call PauseUnit(u, false)
call UnitAddAbility(u, 'A02O')
call IssuePointOrder(u, "channel", SEF_X[i], SEF_Y[i])
call SaveEffectHandle(udg_Unit_Table, GetHandleId(u), 'sefe', AddSpecialEffectTarget( s, u, "origin"))
//! endtextmacro

    private function FuncUnFade takes nothing returns boolean
        local trigger t = GetTriggeringTrigger()
        local integer id = GetHandleId(t)
        local unit u = LoadUnitHandle(udg_Table, id, 'unit')
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local integer i = GetPlayerId(GetOwningPlayer(u))
        local real d = (SquareRoot((x-SEF_X[i])*(x-SEF_X[i])+(y-SEF_Y[i])*(y-SEF_Y[i]))-75.00)/2.25
        local string s
        call SetUnitVertexColor( u , 255, 255, 255, R2I(d) )
        if (d*2.25)+75 >= 370 then
            if SU[i] == u and SB[i] then
                set s = "Doodads\\Cinematic\\Lightningbolt\\Lightningbolt.mdl"
                //! runtextmacro SEF_EndUnFade("S")
            elseif EU[i] == u and EB[i] then
                set s = "Abilities\\Spells\\Orc\\EarthQuake\\EarthQuakeTarget.mdl"
                //! runtextmacro SEF_EndUnFade("E")
            elseif FU[i] == u and FB[i] then
                set s = "Doodads\\Cinematic\\TownBurningFireEmitter\\TownBurningFireEmitter.mdl"
                //! runtextmacro SEF_EndUnFade("F")
            endif
        endif
        set u = null
        set t = null
        return false
    endfunction

    private function FadeFunc takes nothing returns boolean
        local trigger t = GetTriggeringTrigger()
        local integer id = GetHandleId(t)
        local unit c = LoadUnitHandle(udg_Table, id, 'unit')
        local unit u = LoadUnitHandle(udg_Table, id, 'targ')
        local real dist = LoadReal(udg_Table, id, 'dist')
        local integer i = GetPlayerId(GetOwningPlayer(u))
        if IsUnitAliveBJ( u ) then
            if dist <= 10000.00 then
                call ShowUnit( c , false )
                call UnitRemoveAbility( u , 'A02J' )
                if Current_Type[i] == 1 then
                    call UnitAddAbility( u , 'A02L' )
                elseif Current_Type[i] == 2 then
                    call UnitAddAbility( u , 'A02K' )
                elseif Current_Type[i] == 3 then
                    call UnitAddAbility( u , 'A02M' )
                endif
                set SEF_C[i] = SEF_C[i] + 1
                set Current_Type[i] = 0
                call TimerStart(SEF_T[i], 30.00, false, function OutOfTime)
                call TimerDialogSetTitle(SEF_TD[i], "Use SEF within:")
                call TimerDialogDisplayForPlayerBJ( true, SEF_TD[i] , Player(i))
                if SEF_C[i] < 3 then
                    call UnitAddAbility( u , 'A02J' )
                else
                    call UnitAddAbility( u , 'A02N' )
                endif
            else
                call SetUnitVertexColor(c, 255, 255, 255, (255*R2I(dist)/250000)-10)
            endif
        endif
        set t = null
        set c = null
        set u = null
        return false
    endfunction

    private function PeriodicCheck takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer id = GetHandleId(t)
        local unit c = LoadUnitHandle(udg_Table, id, 'cast')
        local unit u = LoadUnitHandle(udg_Table, id, 'targ')
        local integer i = GetPlayerId(GetOwningPlayer(c))
        set TC[i] = TC[i] + 1
        if IsUnitDeadBJ(c) or IsUnitDeadBJ(u) then
            set TC[i] = 0
            call DestroyEffect(SEF_E[i])
            if Current_Type[i] == 1 then
                set SU[i] = null
                set SB[i] = false
            elseif Current_Type[i] == 2 then
                set EU[i] = null
                set EB[i] = false
            elseif Current_Type[i] == 3 then
                set FU[i] = null
                set FB[i] = false
            endif
            if IsUnitAliveBJ( c ) then
                call UnitRemoveAbility( c, 'A02J')
                call UnitAddAbility( c, 'A02J')
            endif
            set Current_Type[i] = 0
        elseif TC[i] >= 20 then
            call DestroyEffect(SEF_E[i])
            set TC[i] = 0
            call UnitAddAbility( u , 'Aloc' )
            call RecTimer(t)
            call SlideToUnit( u , c , 400.00 , Fade)
        endif
        set t = null
        set c = null
        set u = null
    endfunction
    
    function SEF_Init takes unit u, unit c returns nothing
        local timer t = GetFreeTimer()
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real xc = GetUnitX(c)
        local real yc = GetUnitY(c)
        local integer id = GetHandleId(t)
        set SEF_E[GetPlayerId(GetOwningPlayer(c))] = AddSpecialEffectTarget( "Abilities\\Spells\\Items\\StaffOfSanctuary\\Staff_Sanctuary_Target.mdl", u, "chest")
        call SaveUnitHandle(udg_Table, id, 'cast', c)
        call SaveUnitHandle(udg_Table, id, 'targ', u)
        call SetUnitFacing( u, bj_RADTODEG*Atan2(yc-y,xc-x))
        call PauseUnit( u , true )
        call TimerStart( t, 0.10, true, function PeriodicCheck)
    endfunction
    
    function CooldownEnd takes nothing returns nothing
    
    endfunction
    
//! textmacro SEF_CastInit takes LETTER, ORBL
call SetUnitFacing( $LETTER$U[i], 180+(c*120)+(ang*bj_RADTODEG))
call SetUnitPosition( $LETTER$U[i], SEF_X[i]+75*Cos(ang+c*2*bj_PI/3), SEF_Y[i]+75*Sin(ang+c*2*bj_PI/3) )
call UnitRemoveAbility( $LETTER$U[i], 'Aloc' )
call UnitRemoveAbility( SEF_U[i], 'A02$ORBL$' )
call ShowUnit( $LETTER$U[i], true )
call UnitAddAbility( $LETTER$U[i], 'Aloc' )
call SlideTo( $LETTER$U[i], SEF_X[i]+375*Cos(ang+c*2*bj_PI/3), SEF_Y[i]+375*Sin(ang+c*2*bj_PI/3), 100, UnFade)
//! endtextmacro
    
    function SEF_Cast takes integer i returns nothing
        local integer c = 0
        local real ang = Atan2(SEF_Y[i]-GetUnitY(SEF_U[i]), SEF_X[i] - GetUnitX(SEF_U[i]))
        call TimerStart( SEF_T[i], 180.00, false, function CooldownEnd )
        call TimerDialogSetTitle( SEF_TD[i], "SEF Cooldown:" )
        call UnitRemoveAbility(SEF_U[i], 'A02N')
        call UnitAddAbility(SEF_U[i], 'A02J')
        call SetPlayerAbilityAvailable( Player(i), 'A02J', false )
        //! runtextmacro SEF_CastInit("S","L")
        set c = 1
        //! runtextmacro SEF_CastInit("E","K")
        set c = 2
        //! runtextmacro SEF_CastInit("F","M")
    endfunction
    
//! textmacro SEF_UnitSet takes LETTER, WHICH, TYPE
if not $LETTER$B[i] then
    set SEF_U[i] = c
    set $LETTER$U[i] = t
    set $LETTER$B[i] = true
    set Current_Type[i] = $TYPE$
    call SEF_Init(t, c)
else
    call UnitRemoveAbility( c , 'A02J' )
    call UnitAddAbility( c , 'A02J' )
    call DisplayTextToPlayer(p, 0, 0, "You already have a chosen caster for the $WHICH$ part of the spell.")
endif
//! endtextmacro

    function SEF_Check takes nothing returns boolean
        local unit c = GetTriggerUnit()
        local unit t = GetSpellTargetUnit()
        local integer utid = GetUnitTypeId(t)
        local player p = GetOwningPlayer(c)
        local integer i = GetPlayerId(p)
        if GetSpellAbilityId() == 'A02J' then
            if utid  == 'odoc' then
                //! runtextmacro SEF_UnitSet("F","Fire","3")
            elseif utid == 'oshm' then
                //! runtextmacro SEF_UnitSet("S","Storm","1")
            elseif utid == 'ospw' then
                //! runtextmacro SEF_UnitSet("E","Earth","2")
            else
                call UnitRemoveAbility( c , 'A02J' )
                call UnitAddAbility( c , 'A02J' )
                call DisplayTextToPlayer(p, 0, 0, "With this spell you need to target one of each: Shaman, Witch Doctor and a Spirit Walker")
            endif
        elseif GetSpellAbilityId() == 'A02N' then
            set SEF_X[i] = GetSpellTargetX()
            set SEF_Y[i] = GetSpellTargetY()
            call SEF_Cast(i)
        endif
        set c = null
        set t = null
        set p = null
        return false
    endfunction
    
//! textmacro SEF_Now takes LETTER
call ShowUnit( $LETTER$U[i], false )
call UnitRemoveAbility( $LETTER$U[i] , 'Aloc' )
call ShowUnit( $LETTER$U[i], true )
call SetUnitVertexColor($LETTER$U[i], 255, 255, 255, 255)
call PauseUnit( $LETTER$U[i], false)
set $LETTER$B[i] = false
set $LETTER$U[i] = null
set Current_Type[i] = 0
//! endtextmacro

//! textmacro SEF_Past takes LETTER, UNITX, UNITY
if $LETTER$B[i] then
    call SetUnitX( $LETTER$U[i], GetUnitX(u)$UNITX$)
    call SetUnitY( $LETTER$U[i], GetUnitY(u)$UNITY$)
    call ShowUnit( $LETTER$U[i], true )
    call UnitRemoveAbility( $LETTER$U[i] , 'Aloc' )
    call SetUnitVertexColor( $LETTER$U[i], 255, 255, 255, 255)
    call PauseUnit( $LETTER$U[i], false)
    set $LETTER$B[i] = false
    set $LETTER$U[i] = null
endif
//! endtextmacro
                
    private function OnDeath takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local integer i = GetPlayerId(GetOwningPlayer(u))
        if u == SEF_U[i] and SEF_C[i] > 0 then
            if Current_Type[i] == 1 then
                //! runtextmacro SEF_Now("S")
            elseif Current_Type[i] == 2 then
                //! runtextmacro SEF_Now("E")
            elseif Current_Type[i] == 3 then
                //! runtextmacro SEF_Now("F")
            endif
            //! runtextmacro SEF_Past("S","","+75")
            //! runtextmacro SEF_Past("E","-64.952","-37.5")
            //! runtextmacro SEF_Past("F","+64.952","-37.5")
            set SEF_C[i] = 0
        endif
        return false
    endfunction
    
//==============================================================================
    function InitTrig_SEF takes nothing returns nothing
        local integer i = 0
        local trigger t = CreateTrigger()
        set gg_trg_SEF = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ( gg_trg_SEF, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition( gg_trg_SEF, Condition( function SEF_Check ) )
        call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_DEATH )
        call TriggerAddCondition( t, Condition( function OnDeath ))
        call TriggerAddCondition( Fade, Condition( function FadeFunc ))
        call TriggerAddCondition( UnFade, Condition( function FuncUnFade ))
        loop
            exitwhen i > 11
            set SB[i] = false
            set EB[i] = false
            set FB[i] = false
            set SEF_T[i] = CreateTimer()
            set SEF_TD[i] = CreateTimerDialog(SEF_T[i])
            set i = i + 1
        endloop
        set t = null
    endfunction

endscope
My problem isn't with the textmacro, it's with the special effect - I need ALL of them to be looping, but right now only the 2-nd and 3-rd are.
 
Level 7
Joined
Oct 19, 2015
Messages
286
First, confirm that it's not an issue with the effect model: try switching the order of the effects and see if it's still the same one that bugs. If the replacement effect bugs instead, then the problem lies in the code.
 
Level 13
Joined
Jan 2, 2016
Messages
973
Well, since I'm using a textmacro, and 'model 1' bugs, but 'model 2' and 'model 3' are working, it's highly likely that the model is the problem (since the code for all 3 is esentially the same ~thanks to the textmacro~).
By "looping" i mean - I don't want the special effect to happen only once, I want it to continiue appearing over and over again, without making me manually create-destroy a new effect every time.
The model is a "lightning", I want it to keep striking until I destroy the effect.

Without the textmacro it will look like this:
JASS:
            if SU[i] == u and SB[i] then
                set SB[i] = false
                call PauseUnit(u, false)
                call UnitAddAbility(u, 'A02O')
                call IssuePointOrder(u, "channel", SEF_X[i], SEF_Y[i])
                call SaveEffectHandle(udg_Unit_Table, GetHandleId(u), 'sefe', AddSpecialEffectTarget( "Doodads\\Cinematic\\Lightningbolt\\Lightningbolt.mdl", u, "origin"))
            elseif EU[i] == u and EB[i] then
                set EB[i] = false
                call PauseUnit(u, false)
                call UnitAddAbility(u, 'A02O')
                call IssuePointOrder(u, "channel", SEF_X[i], SEF_Y[i])
                call SaveEffectHandle(udg_Unit_Table, GetHandleId(u), 'sefe', AddSpecialEffectTarget( "Abilities\\Spells\\Orc\\EarthQuake\\EarthQuakeTarget.mdl", u, "origin"))
            elseif FU[i] == u and FB[i] then
                set FB[i] = false
                call PauseUnit(u, false)
                call UnitAddAbility(u, 'A02O')
                call IssuePointOrder(u, "channel", SEF_X[i], SEF_Y[i])
                call SaveEffectHandle(udg_Unit_Table, GetHandleId(u), 'sefe', AddSpecialEffectTarget( "Doodads\\Cinematic\\TownBurningFireEmitter\\TownBurningFireEmitter.mdl", u, "origin"))
            endif
 
Level 7
Joined
Oct 19, 2015
Messages
286
Well, since I'm using a textmacro, and 'model 1' bugs, but 'model 2' and 'model 3' are working, it's highly likely that the model is the problem (since the code for all 3 is esentially the same ~thanks to the textmacro~).
It's "highly likely", yes, but if you don't confirm it then you can't solve your problem. That's why I said, try confirming this by switching the model paths. Try using the earth model for the storm effect, for example. If it doesn't bug any more, then the problem was in the model and there's no point to looking at the code.
 
Level 13
Joined
Jan 2, 2016
Messages
973
Okay, I can 100% confirm that it's the model
JASS:
            if SU[i] == u and SB[i] then
                //set s = "Doodads\\Cinematic\\Lightningbolt\\Lightningbolt.mdl"
                set s = "Abilities\\Spells\\Orc\\EarthQuake\\EarthQuakeTarget.mdl"
                //! runtextmacro SEF_EndUnFade("S")
            elseif EU[i] == u and EB[i] then
                set s = "Abilities\\Spells\\Orc\\EarthQuake\\EarthQuakeTarget.mdl"
                //! runtextmacro SEF_EndUnFade("E")
            elseif FU[i] == u and FB[i] then
                set s = "Doodads\\Cinematic\\TownBurningFireEmitter\\TownBurningFireEmitter.mdl"
                //! runtextmacro SEF_EndUnFade("F")
            endif
This works.
So... how do I make the effect keep restarting every time it ends?
Shall I create a lightning doodad with the volcano skill, or is there a more efficient way?
 
Level 7
Joined
Oct 19, 2015
Messages
286
I'm guessing that some sort of simple model edit is required to make the stand animation loop when used as an effect, but I'm not familiar enough with model editing to know what needs to be changed. Your best bet is to ask the question in the Modeling&animation forum. I think importing a modified model is a better solution than changing your code to use a destructable instead of an effect.
 
Status
Not open for further replies.
Top