I just rewrote a old rally points system to use structs and I'd like to see if I can finally get it polished.
Hidden information:
Useful common functions.
JASS:
library Functions initializer Init
globals
gamecache cache = InitGameCache ("Cache" )
boolexpr True
endglobals
function H2I takes handle h returns integer
return h
return 0
endfunction
function FlushCache takes handle subject returns nothing
call FlushStoredMission (cache , I2S (H2I (subject )) )
endfunction
function SetCacheInt takes handle subject , string name , integer value returns nothing
call StoreInteger (cache , I2S (H2I (subject )), name , value )
endfunction
function GetCacheInt takes handle subject , string name returns integer
return GetStoredInteger (cache , I2S (H2I (subject )), name )
endfunction
function TrueFunc takes nothing returns boolean
return true
endfunction
function Init takes nothing returns nothing
set True = Condition (function TrueFunc )
endfunction
function SimError takes player ForPlayer , string msg returns nothing
if (GetLocalPlayer () == ForPlayer ) then
if (msg !="" ) and (msg !=null ) then
call ClearTextMessages ()
call DisplayTimedTextToPlayer ( ForPlayer , 0.52 , -1.00 , 2.00 , "|cffffcc00" +msg +"|r" )
endif
endif
endfunction
endlibrary
The actual system.
JASS:
library RallyPointSystem needs Functions
globals
integer ORPId = 'ARal'
integer IntLimit = 10
endglobals
struct crp
trigger train
trigger spell
trigger select
integer flagno
unit array flagunit [10 ]
trigger array flagtrig [10 ]
real array flagx [10 ]
real array flagy [10 ]
lightning array flaglight [10 ]
integer range = 70
integer flagcode
string order = "attack"
string ltype
integer red = 1
integer blue = 1
integer green = 1
integer alpha = 1
integer limit = IntLimit
integer tlimit = IntLimit
integer slimit = IntLimit
integer rlimit = IntLimit
endstruct
struct crpu
unit origin
integer limit
integer lastflag = 1
endstruct
struct crpt
unit origin
integer flagno
endstruct
function RemoveCRP takes unit u returns nothing
local integer i = 0
local crp c = GetCacheInt (u , "CRP" )
loop
set i = i + 1
exitwhen i > c.flagno
call RemoveUnit (c.flagunit [i ])
call DestroyTrigger (c.flagtrig [i ])
call DestroyLightning (c.flaglight [i ])
endloop
call DestroyTrigger (c.train )
call DestroyTrigger (c.spell )
call DestroyTrigger (c.select )
call UnitAddAbility (u , ORPId )
call c.destroy ()
endfunction
function MoveToNextFlag takes nothing returns nothing
local unit u = GetTriggerUnit ()
local trigger t = GetTriggeringTrigger ()
local crpu cu = GetCacheInt (u ,"CRP" )
local crpt ct = GetCacheInt (t ,"CRP" )
local crp c = GetCacheInt (cu.origin ,"CRP" )
if cu.lastflag < c.flagno and ct.flagno < cu.limit then
if cu.lastflag == ct.flagno and cu.origin == ct.origin then
set cu.lastflag = cu.lastflag + 1
call IssuePointOrder (u , c.order , c.flagx [cu.lastflag ], c.flagy [cu.lastflag ])
endif
else
call cu.destroy ()
call FlushCache (u )
endif
set u = null
set t = null
endfunction
function MoveToFirstFlag takes nothing returns nothing
local unit u = GetTriggerUnit ()
local unit m
local crp c = GetCacheInt (u , "CRP" )
local crpu cu
if c.limit != 0 and c.flagno > 0 then
set cu = crpu.create ()
if GetTrainedUnit () != null then
set m = GetTrainedUnit ()
set cu.limit = c.tlimit
elseif GetSoldUnit () != null then
set m = GetSoldUnit ()
set cu.limit = c.slimit
elseif GetRevivingUnit () != null then
set m = GetRevivingUnit ()
set cu.limit = c.rlimit
endif
set cu.origin = u
call SetCacheInt (m , "CRP" , cu )
call IssuePointOrder (m , c.order , c.flagx [1 ], c.flagy [1 ])
endif
set u = null
set m = null
endfunction
function AddRallyPoint takes unit u , real x , real y returns integer
local integer i = 0
local crp c = GetCacheInt (u , "CRP" )
local crpt ct
local fogmodifier v
if c.flagno < c.limit then
set c.flagno = c.flagno + 1
set c.flagx [c.flagno ] = x
set c.flagy [c.flagno ] = y
if IsVisibleToPlayer (c.flagx [c.flagno ], c.flagy [c.flagno ], GetOwningPlayer (u )) == false then
call SimError (GetOwningPlayer (u ), "Effects will not display properly outside your line of sight" )
endif
set v = CreateFogModifierRadius (GetOwningPlayer (u ),FOG_OF_WAR_VISIBLE , c.flagx [c.flagno ], c.flagy [c.flagno ], 128 , false , false )
call FogModifierStart (v )
set c.flagtrig [c.flagno ] = CreateTrigger ()
call TriggerAddAction (c.flagtrig [c.flagno ], function MoveToNextFlag )
set ct = crpt.create ()
set ct.origin = u
set ct.flagno = c.flagno
call SetCacheInt (c.flagtrig [c.flagno ],"CRP" ,ct )
set c.flagunit [c.flagno ] = CreateUnit (GetOwningPlayer (u ), c.flagcode , c.flagx [c.flagno ], c.flagy [c.flagno ], 0 )
call TriggerRegisterUnitInRange (c.flagtrig [c.flagno ], c.flagunit [c.flagno ], c.range , True )
if GetLocalPlayer () == GetOwningPlayer (u ) then
if c.flagno > 1 then
set c.flaglight [c.flagno ] = AddLightning (c.ltype , true , c.flagx [c.flagno -1 ], c.flagy [c.flagno -1 ], c.flagx [c.flagno ], c.flagy [c.flagno ])
else
set c.flaglight [c.flagno ] = AddLightning (c.ltype , true , GetUnitX (u ), GetUnitY (u ), c.flagx [c.flagno ], c.flagy [c.flagno ])
endif
call SetLightningColor ( c.flaglight [c.flagno ], c.red , c.green , c.blue , c.alpha )
else
call SetUnitVertexColor ( c.flagunit [c.flagno ], 255 , 255 , 255 , 0 )
endif
call DestroyFogModifier (v )
endif
return c.flagno
endfunction
function RemoveLastRallyPoint takes unit u returns nothing
local crp c = GetCacheInt (u , "CRP" )
if c.flagno > 0 then
call DestroyTrigger (c.flagtrig [c.flagno ])
call RemoveUnit (c.flagunit [c.flagno ])
call DestroyLightning (c.flaglight [c.flagno ])
set c.flagno = c.flagno - 1
endif
set u = null
endfunction
function ClearRallyPoint takes unit u returns nothing
local integer i = 0
local crp c = GetCacheInt (u , "CRP" )
loop
set i = i + 1
exitwhen i > c.flagno
call RemoveUnit (c.flagunit [i ])
call DestroyTrigger (c.flagtrig [i ])
call DestroyLightning (c.flaglight [i ])
endloop
set c.flagno = 0
set u = null
endfunction
function Select takes nothing returns nothing
local integer i = 0
local unit u = GetTriggerUnit ()
local crp c = GetCacheInt (u , "CRP" )
if GetTriggerEventId () == EVENT_UNIT_SELECTED then
loop
set i = i + 1
exitwhen i > c.flagno
if GetLocalPlayer () == GetOwningPlayer (u ) then
call SetLightningColor ( c.flaglight [i ], c.red , c.green , c.blue , c.alpha )
call SetUnitVertexColor ( c.flagunit [i ], 255 , 255 , 255 , 255 )
endif
endloop
elseif GetTriggerEventId () == EVENT_UNIT_DESELECTED then
loop
set i = i + 1
exitwhen i > c.flagno
call SetUnitVertexColor ( c.flagunit [i ], 255 , 255 , 255 , 0 )
call SetLightningColor ( c.flaglight [i ], 255 , 255 , 255 , 0 )
endloop
endif
set u = null
endfunction
function RegisterCRP takes unit u ,integer flag , string ltype returns nothing
local trigger train = CreateTrigger ()
local trigger spell = CreateTrigger ()
local trigger select = CreateTrigger ()
local crp c = crp.create ()
call TriggerAddAction (train , function MoveToFirstFlag )
call TriggerRegisterUnitEvent ( train , u , EVENT_UNIT_SELL )
call TriggerRegisterUnitEvent ( train , u , EVENT_UNIT_TRAIN_FINISH )
call TriggerRegisterUnitEvent ( train , u , EVENT_UNIT_HERO_REVIVE_FINISH )
call TriggerAddAction (select , function Select )
call TriggerRegisterUnitEvent ( select , u , EVENT_UNIT_SELECTED )
call TriggerRegisterUnitEvent ( select , u , EVENT_UNIT_DESELECTED )
call UnitRemoveAbility (u , ORPId )
set c.train = train
set c.spell = spell
set c.select = select
set c.flagcode = flag
set c.ltype = ltype
call SetCacheInt (u , "CRP" , c )
set train = null
set spell = null
set select = null
endfunction
endlibrary
Advanced commands for configuration.
JASS:
library RallyPointCommands needs RallyPointSystem
function SetFlagRange takes unit u , integer range returns nothing
local crp c = GetCacheInt (u , "CRP" )
set c.range = range
endfunction
function SetCRPOrder takes unit u , string order returns nothing
local crp c = GetCacheInt (u , "CRP" )
set c.order = order
endfunction
function SetFlagCode takes unit u , integer model returns nothing
local crp c = GetCacheInt (u , "CRP" )
local group g = CreateGroup ()
call GroupEnumUnitsSelected (g , GetOwningPlayer (u ), True )
set c.flagcode = model
if IsUnitInGroup (u , g ) and GetLocalPlayer () == GetOwningPlayer (u ) then
call SelectUnit (u , false )
call SelectUnit (u , true )
endif
call DestroyGroup (g )
set g = null
endfunction
function SetLightningType takes unit u , string ltype returns nothing
local crp c = GetCacheInt (u , "CRP" )
local group g = CreateGroup ()
call GroupEnumUnitsSelected (g , GetOwningPlayer (u ), True )
set c.ltype = ltype
if IsUnitInGroup (u , g ) and GetLocalPlayer () == GetOwningPlayer (u ) then
call SelectUnit (u , false )
call SelectUnit (u , true )
endif
call DestroyGroup (g )
set g = null
endfunction
function SetLightningShade takes unit u , integer red , integer green , integer blue , integer alpha returns nothing
local crp c = GetCacheInt (u ,"CRP" )
local group g = CreateGroup ()
call GroupEnumUnitsSelected (g , GetOwningPlayer (u ), True )
set c.red = red
set c.green = green
set c.blue = blue
set c.alpha = alpha
if IsUnitInGroup (u , g ) and GetLocalPlayer () == GetOwningPlayer (u ) then
call SelectUnit (u , false )
call SelectUnit (u , true )
endif
call DestroyGroup (g )
set g = null
endfunction
function SetMaxPoints takes unit u , integer max returns nothing
local crp c = GetCacheInt (u ,"CRP" )
local integer i
if max == -1 then
set max = IntLimit
endif
set c.limit = max
if max > c.flagno then
set i = c.flagno
loop
set i = i + 1
exitwhen i > max
call RemoveUnit (c.flagunit [i ])
call DestroyLightning (c.flaglight [i ])
endloop
set c.flagno = max
endif
endfunction
function SetEventLimit takes unit u , event etype , integer max returns nothing
local crp c = GetCacheInt (u ,"CRP" )
if max == -1 then
set max = IntLimit
endif
if etype == EVENT_UNIT_TRAIN_FINISH then
set c.tlimit = max
elseif etype == EVENT_UNIT_SELL then
set c.slimit = max
elseif etype == EVENT_UNIT_HERO_REVIVE_FINISH then
set c.rlimit = max
endif
endfunction
function RemoveRallyPoint takes unit u , integer i returns nothing
local crp c = GetCacheInt (u , "CRP" )
local integer n = i
if i > 0 and i < c.flagno then
call DestroyTrigger (c.flagtrig [i ])
call RemoveUnit (c.flagunit [i ])
call DestroyLightning (c.flaglight [i ])
loop
exitwhen n > c.flagno
set c.flagtrig [n ] = c.flagtrig [n +1 ]
set c.flagunit [n ] = c.flagunit [n +1 ]
set c.flaglight [n ] = c.flaglight [n +1 ]
set n = n + 1
endloop
set c.flagno = c.flagno - 1
endif
set u = null
endfunction
endlibrary
It's working fine (haven't tested multiplayer/advanced commands yet though) but I've run into several problems I can't figure out how to solve:
Particles on the flags still appear when they are hidden because SetUnitVertexColor doesn't work completely. I could change the flags to effects, but that would add extra overhead I don't want. The flags doesn't appear when they are out of your line of sight. I've tried them as units and effects and neither works correctly. Because I'm using an array inside a struct, the user is limited by the maximum number vs. the units with rally points. I have no idea how to properly clean up structs attached to units currently moving between flags when the flags are destroyed. I could use a lot of collections, but does anyone have a better idea?
Does anyone have any idea on how to solve these?