Swap System
Story
I was chatting with Romek on MSN, looking for a system idea. Suddenly I come upon an idea; a swap system. I told Romek, asked him if it could be useful. And here is the result.
Implementing
Implementing is easy; just import the dummy and the trigger, and set the raw code in the code to match your imported dummy's raw code. (To view raw codes, press CTRL + D in object editor)
Why gamecache?
Because I didn't want to create a struct for just player id storing and speed doesn't really matter in such a system.
What is it?
This system registers when a player types -swaphero, puts up a dialog for the typing player which asks what player the typing player wants to swap with. When selected, a dialog is shown for the choosen player, which asks if he/she wants to swap with the typing player. If yes, replaces the hero of the typing player with the choosen player's hero. Of course items is transfered.
Code
JASS:
//*********************************************************
//* VESSwapSystem
//* ------------
//*
//* By Vestras
//* Implementation
//*
//* Simply import the trigger Table and this trigger
//* into your map and change the configuration
//* until it fits your needs.
//*
//* Credits
//* I would like to thank Romek for helping me a little
//* and telling me I should make this
//* Furthermore, I would like to thank Flare for his
//* eternal pester about me improving the code <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite7" alt=":p" title="Stick Out Tongue :p" loading="lazy" data-shortname=":p" />
//* Without him this script would leak badly
//* And when using this, remember to credit me!
//*********************************************************
library VESSwapSystem initializer Initialize_VESSetup uses Table
globals
private constant string COMMAND = "-swaphero" // The command
private constant real MAXELAPSED = 60 // Maximum elapsed game time before you can't swap anymore
// Use 0 if there should be no limit
private constant boolean DIVIDETEAM = false // Make players only able to swap with teammates?
private constant integer PLAYERSTEAM = 6 // Number of players on each team
// Will only be used if DIVIDETEAM is true
private constant boolean USEHERONAMES = true // Use hero names instead of player names?
// Will use player names if the players don't got any heroes
// Necessary
private timer REGTIMER = CreateTimer()
private group GRP = CreateGroup()
private group NOSWAP = CreateGroup()
private trigger tc = CreateTrigger()
private StringTable st
private boolean array ALRDYSWP[12]
private button array BUTN [12][12]
endglobals
private function GetPlayerNameColored takes player id returns string // thanks to Vexorian for this function
local playercolor col=GetPlayerColor(id)
local string r=GetPlayerName(id)
if col == PLAYER_COLOR_RED then
set r="|cffff0000"+r+"|r"
elseif col == PLAYER_COLOR_BLUE then
set r="|cff0000ff"+r+"|r"
elseif col == PLAYER_COLOR_CYAN then
set r="|cff93ffc9"+r+"|r"
elseif col == PLAYER_COLOR_PURPLE then
set r="|cff400080"+r+"|r"
elseif col == PLAYER_COLOR_YELLOW then
set r="|cffffff00"+r+"|r"
elseif col == PLAYER_COLOR_ORANGE then
set r="|cffff8000"+r+"|r"
elseif col == PLAYER_COLOR_GREEN then
set r="|cff00c400"+r+"|r"
elseif col == PLAYER_COLOR_PINK then
set r="|cffff80c0"+r+"|r"
elseif col == PLAYER_COLOR_LIGHT_GRAY then
set r="|cff808080"+r+"|r"
elseif col == PLAYER_COLOR_LIGHT_BLUE then
set r="|cffc1c1ff"+r+"|r"
elseif col == PLAYER_COLOR_AQUA then
set r="|cff5e5e2f"+r+"|r"
elseif col == PLAYER_COLOR_BROWN then
set r="|cff004000"+r+"|r"
else
set r="|cff000000"+r+"|r"
endif
//set col=null commented because Romek told me that playercolors don't leak
return r
endfunction
private function GetUnitNameColored takes unit u returns string
local playercolor col=GetPlayerColor(GetOwningPlayer(u))
local string r=GetUnitName(u)
if col == PLAYER_COLOR_RED then
set r="|cffff0000"+r+"|r"
elseif col == PLAYER_COLOR_BLUE then
set r="|cff0000ff"+r+"|r"
elseif col == PLAYER_COLOR_CYAN then
set r="|cff93ffc9"+r+"|r"
elseif col == PLAYER_COLOR_PURPLE then
set r="|cff400080"+r+"|r"
elseif col == PLAYER_COLOR_YELLOW then
set r="|cffffff00"+r+"|r"
elseif col == PLAYER_COLOR_ORANGE then
set r="|cffff8000"+r+"|r"
elseif col == PLAYER_COLOR_GREEN then
set r="|cff00c400"+r+"|r"
elseif col == PLAYER_COLOR_PINK then
set r="|cffff80c0"+r+"|r"
elseif col == PLAYER_COLOR_LIGHT_GRAY then
set r="|cff808080"+r+"|r"
elseif col == PLAYER_COLOR_LIGHT_BLUE then
set r="|cffc1c1ff"+r+"|r"
elseif col == PLAYER_COLOR_AQUA then
set r="|cff5e5e2f"+r+"|r"
elseif col == PLAYER_COLOR_BROWN then
set r="|cff004000"+r+"|r"
else
set r="|cff000000"+r+"|r"
endif
//set col=null commented because Romek told me that playercolors don't leak
return r
endfunction
private function onSwapCommand_CondFilt takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_HERO) == true and GetOwningPlayer(GetFilterUnit()) == Player(st["tplayer"])
endfunction
private function onSwap_CondFilt1 takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_HERO) == true and GetOwningPlayer(GetFilterUnit()) == Player(st["swapp"])
endfunction
private function onSwap_CondFilt2 takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_HERO) == true and GetOwningPlayer(GetFilterUnit()) == Player(st["temps2"])
endfunction
private function onSwapCommand_Conditions takes nothing returns boolean
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
local unit s = null
set st["tplayer"] = id
call GroupEnumUnitsInRect(GRP, bj_mapInitialPlayableArea, Filter(function onSwapCommand_CondFilt))
set s = FirstOfGroup(GRP)
call GroupClear(GRP)
if MAXELAPSED > 0 then
if not IsTriggerEnabled(tc) then
call DisplayTextToPlayer(p, 0, 0, "|cffff0000SWAP ERROR:|r You can039;t swap heroes anymore.")
set s = null
return false
endif
endif
if GetUnitState(s, UNIT_STATE_LIFE) <= 0 then
call DisplayTextToPlayer(p, 0, 0, "|cffff0000SWAP ERROR:|r Your hero must be alive in order to swap.")
set s = null
return false
endif
if ALRDYSWP[id] then
call DisplayTextToPlayer(p, 0, 0, "|cffff0000SWAP ERROR:|r You can039;t swap heroes more than once per game.")
set s = null
return false
endif
set s = null
return true
endfunction
// By Flare
globals
private integer array ItemIds[2][6]
private integer array ItemCharges[2][6]
endglobals
private function SwapItems takes unit first, unit second returns nothing
local integer i = 0
local item itm
loop
exitwhen i == 6
set itm = UnitItemInSlot (first, i)
set ItemIds[0]<i> = GetItemTypeId (itm)
set ItemCharges[0]<i> = GetItemCharges (itm)
call RemoveItem (itm)
set itm = UnitItemInSlot (second, i)
set ItemIds[1]<i> = GetItemTypeId (itm)
set ItemCharges[1]<i> = GetItemCharges (itm)
call RemoveItem (itm)
set i = i + 1
endloop
set i = 0
loop
exitwhen i == 6
set itm = UnitAddItemById (first, ItemIds[1]<i>)
call SetItemCharges (itm, ItemCharges[1]<i>)
set itm = UnitAddItemById (second, ItemIds[0]<i>)
call SetItemCharges (itm, ItemCharges[0]<i>)
set i = i + 1
endloop
set itm = null
endfunction
private function onSwap takes nothing returns boolean
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
local integer id = st["swapp"]
local integer j = 0
local unit s1
local unit s2
call GroupEnumUnitsInRect(GRP, bj_mapInitialPlayableArea, Filter(function onSwap_CondFilt1))
set s1 = FirstOfGroup(GRP)
call GroupClear(GRP)
if GetUnitState(s1, UNIT_STATE_LIFE) <= 0 or s1 == null then
call DisplayTextToPlayer(Player(id), 0, 0, "|cffff0000SWAP ERROR:|r Your hero must be alive in order to swap.")
set ALRDYSWP[pid] = false
set s1 = null
return false
endif
if ALRDYSWP[id] then
call DisplayTextToPlayer(Player(id), 0, 0, "|cffff0000SWAP ERROR:|r You can039;t swap heroes more than once per game.")
set s1 = null
return false
endif
set st["temps2"] = pid
call GroupEnumUnitsInRect(GRP, bj_mapInitialPlayableArea, Filter(function onSwap_CondFilt2))
set s2 = FirstOfGroup(GRP)
call GroupClear(GRP)
if IsUnitInGroup(s1, NOSWAP) then
call DisplayTextToPlayer(Player(id), 0, 0, "|cffff0000SWAP ERROR:|r One or more units are unable to be swapped.")
set s1 = null
set s2 = null
return false
elseif IsUnitInGroup(s2, NOSWAP) then
call DisplayTextToPlayer(Player(id), 0, 0, "|cffff0000SWAP ERROR:|r One or more units are unable to be swapped.")
set s1 = null
set s2 = null
return false
endif
set ALRDYSWP[id] = true
set ALRDYSWP[pid] = true
call SwapItems(s1, s2)
call SetUnitOwner(s1, p, true)
call SetUnitOwner(s2, Player(id), true)
if GetLocalPlayer() == p then
call ClearSelection()
call SelectUnit(s1, true)
endif
if GetLocalPlayer() == Player(id) then
call ClearSelection()
call SelectUnit(s2, true)
endif
set s1 = null
set s2 = null
return false
endfunction
private function onSwapRequest takes player p returns nothing
local integer id = st["swapp"]
local dialog d = DialogCreate()
local button b = DialogAddButton(d, "Yes", 0)
local trigger t = CreateTrigger()
call DialogAddButton(d, "No", 0)
call DialogSetMessage(d, "Swap heroes with " + GetPlayerNameColored(p) + "?")
call TriggerRegisterDialogButtonEvent(t, b)
call TriggerAddCondition(t, Condition(function onSwap))
call DialogDisplay(Player(id), d, true)
set d = null
set t = null
endfunction
private function onSwapWithPlayer takes nothing returns boolean
local player p = GetTriggerPlayer()
local integer j = 0
loop
if GetClickedButton() == BUTN[GetPlayerId(p)][j] and j < 12 then // I had to do the j < 12 (here and other places), because else it would fuck up the dialog
set st["swapp"] = j
endif
set j = j + 1
exitwhen j == bj_MAX_PLAYER_SLOTS
endloop
call onSwapRequest(p)
return false
endfunction
private function onSwapCommand_Actions takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
local dialog d = DialogCreate()
local integer j = 0
local trigger t = CreateTrigger()
local trigger trg = CreateTrigger()
local unit s = null
local string str = ""
call DialogSetMessage(d, "Pick a player to swap heroes with")
call DialogAddButton(d, "Cancel", 0)
if not DIVIDETEAM then
loop
if Player(j) != p and j < 12 then
if not USEHERONAMES then
set BUTN[id][j + 1] = DialogAddButton(d, GetPlayerNameColored(Player(j)) + " [" + I2S(j + 1) + "]", 0)
else
set st["temps2"] = j
call GroupEnumUnitsInRect(GRP, bj_mapInitialPlayableArea, Filter(function onSwap_CondFilt2))
if CountUnitsInGroup(GRP) > 0 then
set s = FirstOfGroup(GRP)
set str = GetUnitNameColored(s)
else
set str = GetPlayerNameColored(Player(j))
endif
call GroupClear(GRP)
call st.flush("temps2")
set BUTN[id][j + 1] = DialogAddButton(d, str + " [" + I2S(j + 1) + "]", 0)
endif
call TriggerRegisterDialogButtonEvent(t, BUTN[id][j + 1])
endif
set j = j + 1
exitwhen j == bj_MAX_PLAYER_SLOTS
endloop
else
if id < PLAYERSTEAM then
loop
if Player(j) != p then
if not USEHERONAMES then
set BUTN[id][j + 1] = DialogAddButton(d, GetPlayerNameColored(Player(j)) + " [" + I2S(j + 1) + "]", 0)
else
set st["temps2"] = j
call GroupEnumUnitsInRect(GRP, bj_mapInitialPlayableArea, Filter(function onSwap_CondFilt2))
if CountUnitsInGroup(GRP) > 0 then
set s = FirstOfGroup(GRP)
set str = GetUnitNameColored(s)
else
set str = GetPlayerNameColored(Player(j))
endif
call GroupClear(GRP)
call st.flush("temps2")
set BUTN[id][j + 1] = DialogAddButton(d, str + " [" + I2S(j + 1) + "]", 0)
endif
call TriggerRegisterDialogButtonEvent(t, BUTN[id][j + 1])
endif
set j = j + 1
exitwhen j == PLAYERSTEAM
endloop
else
set j = PLAYERSTEAM
loop
if Player(j) != p then
if not USEHERONAMES then
set BUTN[id][j + 1] = DialogAddButton(d, GetPlayerNameColored(Player(j)) + " [" + I2S(j + 1) + "]", 0)
else
set st["temps2"] = j
call GroupEnumUnitsInRect(GRP, bj_mapInitialPlayableArea, Filter(function onSwap_CondFilt2))
if CountUnitsInGroup(GRP) > 0 then
set s = FirstOfGroup(GRP)
set str = GetUnitNameColored(s)
else
set str = GetPlayerNameColored(Player(j))
endif
call GroupClear(GRP)
call st.flush("temps2")
set BUTN[id][j + 1] = DialogAddButton(d, str + " [" + I2S(j + 1) + "]", 0)
endif
call TriggerRegisterDialogButtonEvent(t, BUTN[id][j + 1])
endif
set j = j + 1
exitwhen j == PLAYERSTEAM * 2
endloop
endif
endif
call TriggerAddCondition(t, Condition(function onSwapWithPlayer))
call DialogDisplay(p, d, true)
set d = null
set s = null
endfunction
function SetUnitMaySwap takes unit whichUnit, boolean flag returns boolean
if flag then
call GroupAddUnit(NOSWAP, whichUnit)
set flag = true
else
if IsUnitInGroup(whichUnit, NOSWAP) then
call GroupRemoveUnit(NOSWAP, whichUnit)
set flag = true
else
call DisplayTextToPlayer(GetOwningPlayer(whichUnit), 0, 0, "|cffff0000SWAP ERROR:|r The unit is already able to be swapped.")
set flag = false
endif
endif
return flag
endfunction
//===========================================================================
private function onEndCleanUp takes nothing returns nothing
call st.destroy()
call DestroyTimer(GetExpiredTimer())
call DisableTrigger(tc)
endfunction
private function Initialize_VESSetup takes nothing returns nothing
local integer j = 0
loop
call TriggerRegisterPlayerChatEvent(tc, Player(j), COMMAND, true)
set j = j + 1
exitwhen j == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(tc, Condition(function onSwapCommand_Conditions))
call TriggerAddAction(tc, function onSwapCommand_Actions)
call TimerStart(REGTIMER, MAXELAPSED, false, function onEndCleanUp) // This is just a dummy timer for registering when the MAXELAPSED has passed
set st = StringTable.create()
endfunction
endlibrary</i></i></i></i></i></i></i></i>
Credits
I would like to thank Romek for looking a little bit at the code and telling me that I should make this.
Furthermore, credit me when using this.
Test map
Test map is attached here: