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

[Trigger] WayGate Help

Status
Not open for further replies.
Level 37
Joined
Jul 22, 2015
Messages
3,485
If you're having problems with a trigger, please make a post in Triggers & Scripts. Second, you shouldn't expect people to download your "map" off some third-party site you uploaded it on. You can just upload the map as an attachment on your post or use Hive's pastebin.

Since you just need help with triggers, do you mind just posting the triggers used to point the waygates to each other? If you need helping on how to post the triggers, check out this quick and easy tutorial.
 
Level 12
Joined
Jan 2, 2016
Messages
973
I have made something similar on my map, with 2 differenced:
1) Each player can build up to 3 teleporters (not 2)
2) Players use a SKILL to chose where to teleport their units, instead of it happening automatically.
JASS:
scope Teleporters

    globals
        private unit array building [12] [3]
        private real array X [12] [3]
        private real array Y [12] [3]
        private integer array count
        private texttag array indicator [12] [3]
        private group gr = CreateGroup()
    endglobals

    function SetTeleporsAvailable takes integer i returns nothing
        if count[i] >= 2 then
            call SetPlayerAbilityAvailable( Player(i), 'A027', true)
        else
            call SetPlayerAbilityAvailable( Player(i), 'A027', false)
        endif
        if count[i] >= 3 then
            call SetPlayerAbilityAvailable( Player(i), 'A028', true)
        else
            call SetPlayerAbilityAvailable( Player(i), 'A028', false)
        endif
    endfunction

    function Trig_Teleporter_Building_Conditions takes nothing returns boolean
        local unit str = GetConstructedStructure()
        local integer i
        if GetUnitTypeId(str) == 'n00W' then
            set i = GetPlayerId(GetOwningPlayer(str))
            set building[i][count[i]] = str
            set X[i][count[i]] = GetUnitX(str)
            set Y[i][count[i]] = GetUnitY(str)
            set indicator[i][count[i]] = CreateTextTag()
            call SetTextTagText( indicator[i][count[i]], I2S(count[i]+1), 1.5*0.023 )
            call SetTextTagPos( indicator[i][count[i]], X[i][count[i]], Y[i][count[i]], 100 )
            call SetTextTagColor( indicator[i][count[i]], 75, 60, 60, 50 )
            set count[i] = count[i] + 1
        endif
        call SetTeleporsAvailable(i)
        set str = null
        return false
    endfunction

    function Teleporter_Death takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local integer i
        local integer j
        local boolean b = false
        if GetUnitTypeId(u) == 'n00W' then
            set i = GetPlayerId(GetOwningPlayer(u))
            call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl", u, "overhead"))
            set j = 0
            loop
                exitwhen j > count[i]
                if building[i][j] == u then
                    set b = true
                    call DestroyTextTag(indicator[i][j])
                endif
                if b then
                    if j != count[i] then
                        set building[i][j] = building[i][j+1]
                        set X[i][j] = X[i][j+1]
                        set Y[i][j] = Y[i][j+1]
                        set indicator[i][j] = indicator[i][j+1]
                        call SetTextTagText( indicator[i][j], I2S(j+1), 1.5* 0.023 )
                        call SetTextTagPos( indicator[i][j], X[i][j], Y[i][j], 100 )
                    else
                        set building[i][j] = null
                        set indicator[i][j] = null
                        set count[i] = count[i] - 1
                    endif
                endif
                set j = j + 1
            endloop
            call SetTeleporsAvailable(i)
        endif
        return false
    endfunction
    
    private struct TeleData
        player p
        unit u
        integer i
        group g
        integer c
        real x
        real y
        integer t
        
        static method create takes unit u, integer abil returns TeleData
            local TeleData TD = TeleData.allocate()
            set TD.u = u
            set TD.p = GetOwningPlayer(u)
            set TD.i = GetPlayerId(TD.p)
            set TD.g = CreateGroup()
            set TD.x = GetUnitX(u)
            set TD.y = GetUnitY(u)
            set TD.c = 2
            if u != building[TD.i][0] and abil == 1 then
                set TD.t = 0
            elseif u != building[TD.i][2] and abil == 2 then
                set TD.t = 2
            else
                set TD.t = 1
            endif
            return TD
        endmethod
        
        method onDestroy takes nothing returns nothing
            local unit u
            loop
                set u = FirstOfGroup(.g)
                exitwhen u == null
                call RemoveSavedBoolean(udg_Unit_Table, GetHandleId(u), 'tptd')
                call GroupRemoveUnit(.g, u)
            endloop
            call DestroyGroup(.g)
        endmethod
    endstruct

    function TeleLoop takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local TeleData TD = LoadInteger(udg_Table, GetHandleId(t), 'tpst')
        local unit FoG
        local real x
        local real y
        call GroupEnumUnitsInRange(gr, TD.x, TD.y, I2R(TD.c)*100.00, null)
        loop
            set FoG = FirstOfGroup(gr)
            exitwhen FoG == null
            if IsUnitAliveBJ(FoG) and IsUnitAlly(FoG, TD.p) and not IsUnitType(FoG, UNIT_TYPE_STRUCTURE) and not LoadBoolean(udg_Unit_Table, GetHandleId(FoG), 'tptd') then
                set x = GetUnitX(FoG)
                set y = GetUnitY(FoG)
                call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl", x, y))
                set x = X[TD.i][TD.t] + (x - TD.x)/2
                set y = Y[TD.i][TD.t] + (y - TD.y)/2
                call SetUnitX(FoG, x)
                call SetUnitY(FoG, y)
                call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl", x, y))
                call GroupAddUnit(TD.g, FoG)
                call SaveBoolean(udg_Unit_Table, GetHandleId(FoG), 'tptd', true)
            endif
            call GroupRemoveUnit(gr, FoG)
        endloop
        if TD.c >= 5 then
            call RecTimer(t)
            call TeleData.destroy(TD)
        else
            set TD.c = TD.c + 1
        endif
        set t = null
    endfunction

    function Teleport_1 takes nothing returns boolean
        local timer t
        local unit FoG
        local TeleData TD
        local real x
        local real y
        local integer abil = GetSpellAbilityId()
        if abil == 'A027' or abil == 'A028' then
            if abil == 'A027' then
                set TD = TD.create(GetTriggerUnit(),1)
            else
                set TD = TD.create(GetTriggerUnit(),2)
            endif
            set t = GetFreeTimer()
            call SaveInteger(udg_Table, GetHandleId(t), 'tpst', TD)
            call GroupEnumUnitsInRange( gr, TD.x, TD.y, 100.00, null)
            loop
                set FoG = FirstOfGroup(gr)
                exitwhen FoG == null
                if IsUnitAliveBJ(FoG) and IsUnitAlly(FoG, TD.p) and not IsUnitType(FoG, UNIT_TYPE_STRUCTURE) and not LoadBoolean(udg_Unit_Table, GetHandleId(FoG), 'tptd') then
                    set x = GetUnitX(FoG)
                    set y = GetUnitY(FoG)
                    call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl", x, y))
                    set x = X[TD.i][TD.t] + (x - TD.x)/2
                    set y = Y[TD.i][TD.t] + (y - TD.y)/2
                    call SetUnitX(FoG, x)
                    call SetUnitY(FoG, y)
                    call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl", x, y))
                    call GroupAddUnit(TD.g, FoG)
                    call SaveBoolean(udg_Unit_Table, GetHandleId(FoG), 'tptd', true)
                endif
                call GroupRemoveUnit(gr, FoG)
            endloop
            call TimerStart(t, 0.5, true, function TeleLoop)
            set t = null
        endif
        return false
    endfunction

//===========================================================================
    function InitTrig_Teleporters takes nothing returns nothing
        local integer i = 0
        local trigger t = CreateTrigger()
        set gg_trg_Teleporters = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ( gg_trg_Teleporters, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH )
        call TriggerAddCondition( gg_trg_Teleporters, Condition( function Trig_Teleporter_Building_Conditions ) )
        call TriggerRegisterAnyUnitEventBJ( t , EVENT_PLAYER_UNIT_DEATH )
        call TriggerAddCondition( t , Condition( function Teleporter_Death ) )
        set t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition( t, Condition( function Teleport_1 ) )
        loop
            exitwhen i > 11
            set count[i] = 0
            set i = i + 1
        endloop
        set t = null
    endfunction

endscope
This used to be 4 GUI triggers, but I combined them into 1 vJASS scope :p

The idea is:
1) When a teleporter is built - save its X, and Y, and increase a counter by 1 (each player has his own counter)
2) Have the teleport skills initially disabled
3) When 2 teleporters are built - enable the '1-st' teleport skill, which teleports units between the 2
4) When 3 teleporters are built - enable the '2-nd' skill, which enables teleporting to the 3-rd portal (and from the 3-rd portal - the 1-st skill teleports units to the 1-st build teleporter, and the 2-nd skill teleports them to the 2-nd built teleporter)
5) When a teleporter dies - if it's the 1-st teleporter, make the 2-nd one be the new '1-st' and the 3-rd one the new '2-nd'.
6) I'm also putting "indications" above teleporters (1/2/3) not to get confused. They also get changed upon teleporter's death.

There are more things I could explain, but think this will be enough xP
 
Level 8
Joined
Jan 28, 2016
Messages
486
What you got there is pretty neat WereElf. I can't imagine a scenario where you would want 3 gates that loop but I guess if anyone wants to, it's there.

As for the OP, I downloaded the map against all common sense because I had nothing better to do (I'm sorry KILLCIDE) and found the problem. You have 16 triggers to run all this; 8 for when you create the gates and another 8 for when they're destroyed. For those of you wondering, there is one trigger per player (i.e. 8 players) for both events. To save everyone the trouble I'll post one of each type instead.

  • WayGate
    • Events
      • Unit - A unit Finishes construction
    • Conditions
      • (Unit-type of (Constructed structure)) Equal to Way Gate
    • Actions
      • For each (Integer A) from 1 to 8, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Owner of (Triggering unit)) Equal to Player 8 (Pink)
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • WayGateUnit8[1] Equal to No unit
                • Then - Actions
                  • Set WayGateUnit8[1] = (Triggering unit)
                  • Set WayGatePoint8[2] = (Position of (Triggering unit))
                • Else - Actions
                  • Set WayGateUnit8[1] = (Triggering unit)
                  • Set WayGatePoint8[2] = (Position of (Triggering unit))
                  • Neutral Building - Enable WayGateUnit8[1]
                  • Neutral Building - Enable WayGateUnit8[2]
            • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Triggering unit) Equal to WayGateUnit8[1]
        • Then - Actions
          • Neutral Building - Set (Triggering unit) destination to WayGatePoint8[2]
          • Neutral Building - Set WayGateUnit8[2] destination to WayGatePoint8[1]
        • Else - Actions
          • Neutral Building - Set (Triggering unit) destination to WayGatePoint8[1]
          • Neutral Building - Set WayGateUnit8[1] destination to WayGatePoint8[2]
  • WayGate Destroyed
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Way Gate
    • Actions
      • For each (Integer A) from 1 to 2, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Triggering unit) Equal to WayGateUnit8[(Integer A)]
            • Then - Actions
              • Set WayGateUnit8[(Integer A)] = No unit
            • Else - Actions
      • Neutral Building - Disable WayGateUnit8[1]
      • Neutral Building - Disable WayGateUnit8[2]
I'd attempt to fix it but it's a headache to say the least. If anything, I would start over but it has been a long day and I'm tired. Maybe tomorrow.
 
Last edited:
Level 12
Joined
Jan 2, 2016
Messages
973
Alright, I can see what is wrong.
I'm not sure if Dehua posted the original trigger, or he added the loop as a suggestion how it can be done with 1 trigger, but things should looks more like this:
  • WayGates
    • Events
      • Unit - A unit Finishes construction
    • Conditions
      • (Unit-type of (Constructed structure)) Equal to Way Gate
    • Actions
      • Set TempInteger = (((Player number of (Owner of (Constructed structure))) - 1) x 2)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • WayGateUnit[(TempInteger + 1)] Equal to No unit
        • Then - Actions
          • Set WayGateUnit[(TempInteger + 1)] = (Constructed structure)
          • Set WayGatePoint[(TempInteger + 1)] = (Position of WayGateUnit[(TempInteger + 1)])
        • Else - Actions
          • Set WayGateUnit[(TempInteger + 2)] = (Constructed structure)
          • Set WayGatePoint[(TempInteger + 2)] = (Position of WayGateUnit[(TempInteger + 2)])
          • Neutral Building - Set WayGateUnit[(TempInteger + 1)] destination to WayGatePoint[(TempInteger + 2)]
          • Neutral Building - Set WayGateUnit[(TempInteger + 2)] destination to WayGatePoint[(TempInteger + 1)]
          • Neutral Building - Enable WayGateUnit[(TempInteger + 1)]
          • Neutral Building - Enable WayGateUnit[(TempInteger + 2)]
  • WayGate Destroyed
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Way Gate
    • Actions
      • Set TempInteger = (((Player number of (Owner of (Triggering unit))) - 1) x 2)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • WayGateUnit[(TempInteger+ 2)] Not equal to No unit
        • Then - Actions
          • Neutral Building - Disable WayGateUnit[(TempInteger + 1)]
          • Neutral Building - Disable WayGateUnit[(TempInteger + 2)]
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Triggering unit) Equal to WayGateUnit[(TempInteger + 1)]
            • Then - Actions
              • Set WayGateUnit[(TempInteger + 1)] = WayGateUnit[(TempInteger + 2)]
              • Custom script: call RemoveLocation(udg_WayGatePoint[udg_TempInteger + 1])
              • Set WayGatePoint[(TempInteger + 1)] = WayGatePoint[(TempInteger + 2)]
            • Else - Actions
              • Custom script: call RemoveLocation(udg_WayGatePoint[udg_TempInteger + 2])
          • Set WayGateUnit[(TempInteger + 2)] = No unit
        • Else - Actions
          • Set WayGateUnit[(TempInteger + 1)] = No unit
          • Custom script: call RemoveLocation(udg_WayGatePoint[udg_TempInteger + 1])
These 2 triggers will be enough for ALL the players :)
No need to make 8 triggers, 1 for each player.

EDIT: Improved it 'a bit'.
 
Last edited:
Level 8
Joined
Jan 28, 2016
Messages
486
Nah I didn't add the loop; it's all original. By the way, you're leaking 2 locations in the ITE statement of the 1st trigger. Nevermind, I just had a brain fart :|
 
Level 5
Joined
Apr 13, 2008
Messages
184
Hi guys! Thanks for the response, sorry i didnt know how to upload the map onto hive and post the triggers up, i'll do a read on the tutorial. Thanks for the code too didnt know i could just run it with 2 triggers for ALL 8 players, thats amazing!!!!!!! Didnt know i could do a loop like that, thats pretty mindblowing for me.

What went wrong? Was there a location leak or something?
 
Level 12
Joined
Jan 2, 2016
Messages
973
A location leak wouldn't cause the trigger to not work. Leaks cause lag long term if allowed to accumulate, not immediate problems. I'll leave Wereelf to explain what went wrong if she can seeing as she fixed it for you.

Lol :D

Anyways... there were several things that were wrong:
1) You didn't need a loop, I don't know why it was there...
You usually need loops if
- you need to do the same action several times
- you need to check/set different array members of variables
You weren't doing either of these...

2) You were always using WayGateUnit[1] for the way gate, and WayGatePoint[2] for the location, when you were supposed to use WayGateUnit[1] for the FIRST way gate, and WayGateUnit[2] for the SECOND way gate, and WayGatePoint[1] for the location of the FIRST way gate, and WayGatePoint[2] for the location of the SECOND.

3) I made 2 triggers able to handle all the players by using the player number as part of the array. This way [1] and [2] will belong to Player 1, [3] and [4] will belong to Player 2, [5] and [6] will belong to Player 3, and so on...
Explaining:
Since TempInteger is equal to (PlayerNumber - 1) x 2, then for player 1 it will be 0, for player 2 will be 2, for player 3 will be 4, and so on...
the 1-st teleporter for player 2 will be saved as [2 + 1], and the 2-nd as [2 + 2], for player 8 it will be saved as [14 + 1] and [14 + 2]

Thus you don't need loops, you just need the player's number :p
 
Level 5
Joined
Apr 13, 2008
Messages
184
Lol :D

Anyways... there were several things that were wrong:
1) You didn't need a loop, I don't know why it was there...
You usually need loops if
- you need to do the same action several times
- you need to check/set different array members of variables
You weren't doing either of these...

2) You were always using WayGateUnit[1] for the way gate, and WayGatePoint[2] for the location, when you were supposed to use WayGateUnit[1] for the FIRST way gate, and WayGateUnit[2] for the SECOND way gate, and WayGatePoint[1] for the location of the FIRST way gate, and WayGatePoint[2] for the location of the SECOND.

3) I made 2 triggers able to handle all the players by using the player number as part of the array. This way [1] and [2] will belong to Player 1, [3] and [4] will belong to Player 2, [5] and [6] will belong to Player 3, and so on...
Explaining:
Since TempInteger is equal to (PlayerNumber - 1) x 2, then for player 1 it will be 0, for player 2 will be 2, for player 3 will be 4, and so on...
the 1-st teleporter for player 2 will be saved as [2 + 1], and the 2-nd as [2 + 2], for player 8 it will be saved as [14 + 1] and [14 + 2]

Thus you don't need loops, you just need the player's number :p

Hi yeah i understood your code :D would try out something similar next time! Thanks the waygate seems to work perfectly now except when its destroyed and rebuilt it seems to not work sometimes hmm
 
Status
Not open for further replies.
Top