// *********************************
// Handle Converters
// *********************************
function HandleToInt takes handle h returns integer
return h
return 0
endfunction
function IntToHandle takes integer i returns handle
return i
return null
endfunction
// *********************************
// Local Vars Utility
// *********************************
function LocalVars takes nothing returns gamecache
return InitGameCache("jasslocalvars.w3v")
endfunction
function SetHandleHandle takes handle subject, string name, handle value returns nothing
if value==null then
call FlushStoredInteger(LocalVars(),I2S(HandleToInt(subject)),name)
else
call StoreInteger(LocalVars(), I2S(HandleToInt(subject)), name, HandleToInt(value))
endif
endfunction
function SetHandleInt takes handle subject, string name, integer value returns nothing
if value==0 then
call FlushStoredInteger(LocalVars(),I2S(HandleToInt(subject)),name)
else
call StoreInteger(LocalVars(), I2S(HandleToInt(subject)), name, value)
endif
endfunction
function SetHandleReal takes handle subject, string name, real value returns nothing
if value==0 then
call FlushStoredReal(LocalVars(), I2S(HandleToInt(subject)), name)
else
call StoreReal(LocalVars(), I2S(HandleToInt(subject)), name, value)
endif
endfunction
function SetHandleString takes handle subject, string name, string value returns nothing
if value == "" or value == null then
call FlushStoredString(LocalVars(), I2S(HandleToInt(subject)), name)
else
call StoreString(LocalVars(), I2S(HandleToInt(subject)), name, value)
endif
endfunction
function GetHandleHandle takes handle subject, string name returns handle
return GetStoredInteger(LocalVars(), I2S(HandleToInt(subject)), name)
return null
endfunction
function GetHandleInt takes handle subject, string name returns integer
return GetStoredInteger(LocalVars(), I2S(HandleToInt(subject)), name)
endfunction
function GetHandleReal takes handle subject, string name returns real
return GetStoredReal(LocalVars(), I2S(HandleToInt(subject)), name)
endfunction
function GetHandleUnit takes handle subject, string name returns unit
return GetStoredInteger(LocalVars(), I2S(HandleToInt(subject)), name)
return null
endfunction
function GetHandleTimer takes handle subject, string name returns timer
return GetStoredInteger(LocalVars(), I2S(HandleToInt(subject)), name)
return null
endfunction
function GetHandleString takes handle subject, string name returns string
return GetStoredString(LocalVars(), I2S(HandleToInt(subject)), name)
endfunction
function FlushHandleLocals takes handle subject returns nothing
call FlushStoredMission(LocalVars(), I2S(HandleToInt(subject)) )
endfunction
// *********************************
// List Utility
// *********************************
// The cache storing the lists
function ListCache takes nothing returns gamecache
return InitGameCache("listcache")
endfunction
// Returns a pointer to a new list. Old pointers are not recycled!
function ListNew takes nothing returns integer
local gamecache gc = ListCache()
local integer n = GetStoredInteger(gc, "lists", "count")
call StoreInteger(gc, "lists", "count", n+1)
return n
endfunction
// Returns the length of the list
function ListLength takes integer list returns integer
return GetStoredInteger(ListCache(), "list"+I2S(list), "length")
endfunction
// Returns the value of an item
function ListGet takes integer list, integer index returns integer
return GetStoredInteger(ListCache(), "list"+I2S(list), "item"+I2S(index))
endfunction
// Changes the value of a list item, and increases the length of the list if necessary
function ListSetValue takes integer list, integer index, integer value returns nothing
local gamecache gc = ListCache()
call StoreInteger(gc, "list"+I2S(list), "item"+I2S(index), value)
if ( index >= ListLength(list) ) then
call StoreInteger(gc, "list"+I2S(list), "length", index+1)
endif
endfunction
// Adds an item at the end of a list
function ListAdd takes integer list, integer value returns nothing
call ListSetValue(list, ListLength(list), value)
endfunction
// Removes the last item in a list
function ListRemoveLast takes integer list returns nothing
local gamecache gc = ListCache()
local integer index = ListLength(list)-1
call FlushStoredInteger(gc, "list"+I2S(list), "item"+I2S(index))
if ( index >= 0 ) then
call StoreInteger(gc, "list"+I2S(list), "length", index)
endif
endfunction
// Inserts an item in a list
function ListInsert takes integer list, integer index, integer value returns nothing
local integer i = ListLength(list)
loop // Push all items beyond index
exitwhen i <= index
call ListSetValue(list, i, ListGet(list, i-1))
set i = i - 1
endloop
call ListSetValue(list, index, value)
endfunction
// Adds listB to the end of listA
function ListAddList takes integer listA, integer listB returns nothing
local integer i = 0
local integer max = ListLength(listB)
local integer index = ListLength(listA)
loop
exitwhen i >= max
call ListSetValue(listA, index+i, ListGet(listB, i))
set i = i + 1
endloop
endfunction
// Deletes the list
function ListClear takes integer list returns nothing
call FlushStoredMission(ListCache(), "list"+I2S(list))
endfunction
// Removes an item from the list. All items beyond this will be pulled one index down
function ListRemove takes integer list, integer index returns nothing
local integer i = index
local integer max = ListLength(list)
loop
exitwhen i >= max
call ListSetValue(list, i, ListGet(list, i+1))
set i = i + 1
endloop
call ListRemoveLast(list)
endfunction
// Finds an item with the value, beginning the search at start. (Use 0 for a complete search)
// Returns the index or -1 if not found
function ListFind takes integer list, integer value, integer start returns integer
local integer i = start
local integer max = ListLength(list)
loop
exitwhen i >= max
if ( ListGet(list, i) == value ) then
return i
endif
set i = i + 1
endloop
return -1
endfunction
// Returns a copy of the list
function ListClone takes integer list returns integer
local integer new = ListNew()
call ListAddList(new, list)
return new
endfunction
// Returns the value of the item in question, used in ListFilter's filter parameter
function ListFilterValue takes nothing returns integer
return GetStoredInteger(ListCache(), "lists", "filtervalue")
endfunction
// Returns the value of the item in question, used in ListFilter's filter parameter
function ListFilterIndex takes nothing returns integer
return GetStoredInteger(ListCache(), "lists", "filterindex")
endfunction
// Removes all items NOT matching filter. Returns the amount of items removed
function ListFilter takes integer list, boolexpr filter returns integer
local integer n = ListLength(list)
local integer i = 0
local integer o = 0
local trigger trg = CreateTrigger()
local triggercondition c = TriggerAddCondition(trg, filter)
local gamecache gc = ListCache()
local integer removed = 0
local boolean array remove
loop
exitwhen i >= n
call StoreInteger(gc, "lists", "filtervalue", ListGet(list, i))
call StoreInteger(gc, "lists", "filterindex", i)
if ( not TriggerEvaluate(trg) ) then
set remove[i] = true
set removed = removed + 1
endif
set i = i + 1
endloop
call TriggerRemoveCondition(trg, c)
call DestroyTrigger(trg)
if ( removed == 0 ) then
return 0
endif
set i = 0
loop
exitwhen i >= n-removed
loop
exitwhen not remove[i+o]
set o = o + 1
endloop
if ( o != 0 ) then
call ListSetValue(list, i, ListGet(list, i+o))
endif
set i = i + 1
endloop
loop
exitwhen i >= n
call FlushStoredInteger(gc, "list"+I2S(list), "item"+I2S(i))
set i = i + 1
endloop
call StoreInteger(gc, "list"+I2S(list), "length", n-removed)
return removed
endfunction
// Will display the whole list to all players.
// For example: list0(12, 1, 68, 42, 1, 3, 8)
function ListDebug takes integer list returns nothing
local integer n = ListLength(list)
local integer i = 0
local string s = "list"+I2S(list)+"("
loop
exitwhen i >= n
set s = s + I2S(ListGet(list, i))
if ( i != n-1 ) then
set s = s + ", "
endif
set i = i + 1
endloop
set s = s + ")"
call DisplayTextToForce(GetPlayersAll(), s)
endfunction
// **************************************
// Waypoint Utility
// **************************************
function WPCache takes nothing returns gamecache
return InitGameCache("wpsystem")
endfunction
function GetWPConnectCount takes integer wp returns integer
return GetStoredInteger(InitGameCache("wpsystem"), "wp"+I2S(wp), "connects")
endfunction
function WPListClear takes nothing returns nothing
call FlushStoredMission(WPCache(), "wplist")
endfunction
function WPSetTarget takes integer wp returns nothing
call StoreInteger(WPCache(), "wp", "target", wp)
endfunction
function WPGetTarget takes nothing returns integer
return GetStoredInteger(WPCache(), "wp", "target")
endfunction
function WPSetDist takes real dist returns nothing
call StoreReal(WPCache(), "wp", "dist", dist)
endfunction
function WPGetDist takes nothing returns real
return GetStoredReal(WPCache(), "wp", "dist")
endfunction
function WPListPost takes integer wp, real dist returns boolean
local real d = GetStoredReal(WPCache(), "wplist", "wp"+I2S(wp))
if ( d <= dist and d != 0 ) then
return false
endif
call StoreReal(WPCache(), "wplist", "wp"+I2S(wp), dist)
return true
endfunction
function WPX takes integer wp returns real
return GetStoredReal(WPCache(), "wp"+I2S(wp), "x")
endfunction
function WPY takes integer wp returns real
return GetStoredReal(WPCache(), "wp"+I2S(wp), "y")
endfunction
function WPDist takes integer wp1, integer wp2 returns real
local gamecache gc = WPCache()
local real dx = GetStoredReal(gc, "wp"+I2S(wp1), "x") - GetStoredReal(gc, "wp"+I2S(wp2), "x")
local real dy = GetStoredReal(gc, "wp"+I2S(wp1), "y") - GetStoredReal(gc, "wp"+I2S(wp2), "y")
return dx*dx + dy*dy
endfunction
function NewWaypoint takes real x, real y returns integer
local gamecache gc = WPCache()
local integer id = GetStoredInteger(gc, "wp", "wpcounter") // Get unique id
call StoreInteger(gc, "wp", "wpcounter", id+1) // Increase reference
call StoreReal(gc, "wp"+I2S(id), "x", x)
call StoreReal(gc, "wp"+I2S(id), "y", y)
return id
endfunction
// Only tests if they are directly connected.
function AreWaypointsConnected takes integer wp1, integer wp2 returns boolean
local gamecache gc = WPCache()
local integer i
local integer max = GetWPConnectCount(wp1)
if ( GetWPConnectCount(wp2) < max ) then
set max = GetWPConnectCount(wp2)
set i = wp1
set wp1 = wp2
set wp2 = wp1
endif
set i = 0
loop
exitwhen i >= max
if ( GetStoredInteger(gc, "wp"+I2S(wp1), "connect"+I2S(i)) == wp2 ) then
return true
endif
set i = i + 1
endloop
return false
endfunction
function ConnectWaypoints takes integer wp1, integer wp2 returns nothing
local gamecache gc = WPCache()
local integer n = GetStoredInteger(gc, "wp"+I2S(wp1), "connects")
if ( AreWaypointsConnected(wp1, wp2) ) then
return
endif
call StoreInteger(gc, "wp"+I2S(wp1), "connect"+I2S(n), wp2)
call StoreInteger(gc, "wp"+I2S(wp1), "connects", n+1)
set n = GetStoredInteger(gc, "wp"+I2S(wp2), "connects")
call StoreInteger(gc, "wp"+I2S(wp2), "connect"+I2S(n), wp1)
call StoreInteger(gc, "wp"+I2S(wp2), "connects", n+1)
endfunction
function WPIterateConnections takes integer wp, real dist, integer list, integer level returns boolean
local integer i = 0
local integer m = GetWPConnectCount(wp)
local integer id
local real d
local boolean r = false
if ( wp == WPGetTarget() ) then
call ListSetValue(list, level, wp)
return true
endif
loop
exitwhen i >= m
set id = GetStoredInteger(WPCache(), "wp"+I2S(wp), "connect"+I2S(i))
set d = WPDist(wp, id) + dist
if ( id != wp and WPListPost(id, d) ) then
if ( WPIterateConnections(id, d, list, level+1) ) then
call ListSetValue(list, level, wp)
set r = true
endif
endif
set i = i + 1
endloop
return r
endfunction
function GetWaypointPathList takes integer wpstart, integer wpend returns integer
local integer list = ListNew()
call WPListClear()
call WPSetTarget(wpend)
if ( not WPIterateConnections(wpstart, 1, list, 0) ) then
call ListClear(list)
return -1
endif
return list
endfunction
function WPIterateSmall takes integer wp, real x, real y returns nothing
local gamecache gc = WPCache()
local real dx = WPX(wp) - x
local real dy = WPY(wp) - y
local real dist = dx*dx + dy*dy
local integer i = 0
local integer n = GetWPConnectCount(wp)
local integer id
if ( not WPListPost(wp, 1)) then
return
endif
if ( dist < GetStoredReal(gc, "wp", "mindist") ) then
call StoreReal(gc, "wp", "mindist", dist)
call StoreInteger(gc, "wp", "mindistwp", wp)
endif
loop
exitwhen i >= n
set id = GetStoredInteger(gc, "wp"+I2S(wp), "connect"+I2S(i))
call WPIterateSmall(id, x, y)
set i = i + 1
endloop
endfunction
// Gets the waypoint closest to (x,y) that is somehow connected to wp
function GetClosestWaypoint takes real x, real y, integer wp returns integer
local gamecache gc = WPCache()
local real dx = WPX(wp) - x
local real dy = WPY(wp) - y
local integer i = 0
call WPListClear()
call StoreReal(gc, "wp", "mindist", dx*dx+dy*dy)
call StoreInteger(gc, "wp", "mindistwp", wp)
call WPIterateSmall(wp, x, y)
return GetStoredInteger(gc, "wp", "mindistwp")
endfunction
function UnitStopFollowWaypointPath takes unit u returns nothing
local timer t = GetHandleTimer(u, "wptimer")
local integer list = GetHandleInt(t, "list")
call ListClear(list)
call FlushHandleLocals(t)
call SetHandleHandle(u, "wptimer", null)
call DestroyTimer(t)
endfunction
function IsOrderFromWP takes nothing returns boolean
return GetStoredBoolean(WPCache(), "wp", "wp"+I2S(HandleToInt(GetOrderedUnit()))+"order")
endfunction
function SetOrderFromWP takes unit u, boolean b returns nothing
call StoreBoolean(WPCache(), "wp", "wp"+I2S(HandleToInt(u))+"order", b)
endfunction
function UnitGotoWaypoint_Loop takes nothing returns nothing
local timer t = GetExpiredTimer()
local unit u = GetHandleUnit(t, "u")
local string order = GetHandleString(t, "order")
local integer list = GetHandleInt(t, "list")
local integer level = GetHandleInt(t, "level")
local integer wp = ListGet(list, level)
local real dx = GetUnitX(u) - WPX(wp)
local real dy = GetUnitY(u) - WPY(wp)
local real dist = dx*dx + dy*dy
if ( dist <= 400*400 ) then
set level = level + 1
set wp = ListGet(list, level)
if ( wp == 0 ) then // Target waypoint reached
call UnitStopFollowWaypointPath(u)
else // Goto next waypoint
call SetOrderFromWP(u, true)
call IssuePointOrder(u, order, WPX(wp), WPY(wp))
call SetOrderFromWP(u, false)
call SetHandleInt(t, "level", level)
endif
endif
if ( GetUnitCurrentOrder(u) != OrderId(order) ) then
call UnitStopFollowWaypointPath(u)
endif
endfunction
// Lets unit u move to waypoint wp through the shortest waypointed path.
// If attack=true he will be ordered to attack-move instead of just move
function UnitGotoWaypoint takes unit u, integer wp, boolean attack returns nothing
local integer wpstart = GetClosestWaypoint(GetUnitX(u), GetUnitY(u), wp)
local integer list = GetWaypointPathList(wpstart, wp)
local timer t = CreateTimer()
local string order = "move"
if ( attack ) then
set order = "attack"
endif
call SetHandleHandle(t, "u", u)
call SetHandleInt(t, "list", list)
call SetHandleString(t, "order", order)
call SetHandleHandle(u, "wptimer", t)
call SetOrderFromWP(u, true)
call IssuePointOrder(u, order, WPX(ListGet(list, 0)), WPY(ListGet(list, 0)))
call SetOrderFromWP(u, false)
call TimerStart(t, 1, true, function UnitGotoWaypoint_Loop)
endfunction
//------------------------------------------------------------------------
//------------------------------------------------------------------------
function InitWaypoints takes nothing returns nothing
local integer array p
// Make a square of waypoints
set p[0] = NewWaypoint(100, 100)
set udg_WPTopRightCorner = p[0]
set p[1] = NewWaypoint(-100, 100)
set p[2] = NewWaypoint(-100, -100)
set p[3] = NewWaypoint(100, -100)
call ConnectWaypoints(p[0], p[1])
call ConnectWaypoints(p[1], p[2])
call ConnectWaypoints(p[2], p[3])
call ConnectWaypoints(p[3], p[0])
endfunction
function UnitGotoTopRightCorner takes unit u returns nothing
call UnitGotoWaypoint(u, udg_WPTopRightCorner, false)
endfunction