library IsPathBlocked uses Table, IsPathable
private keyword Path
private function NormalizeAngle takes real angle returns real
local integer a
if (0 > angle) then
set a = R2I(angle*180/bj_PI - 45)/90*90
else
set a = R2I(angle*180/bj_PI + 45)/90*90
endif
if (0 > a or 360 < a) then
set a = a - a/360*360
if (0 > a) then
set a = a + 360
endif
endif
return a/180.*bj_PI
endfunction
private function NormalizeComponent takes real p returns integer
if (0 < p) then
return R2I(p + 16)/32*32
endif
return R2I(p - 16)/32*32
endfunction
private function CalculateAngleBetweenPoints takes real x, real y, real x2, real y2 returns real
return Atan2(y2 - y, x2 - x)
endfunction
private function CalculateComponentX takes real angle returns real
return 32*Cos(angle)
endfunction
private function CalculateComponentY takes real angle returns real
return 32*Sin(angle)
endfunction
private module InitTiles
private static method onInit takes nothing returns nothing
set table = Table.create()
endmethod
endmodule
private struct Tile extends array
private static Table table
method operator [] takes integer y returns boolean
return table.boolean[this*256+y]
endmethod
method operator []= takes integer y, boolean v returns nothing
set table.boolean[this*256+y] = v
endmethod
static method clear takes nothing returns nothing
call table.flush()
endmethod
implement InitTiles
endstruct
private struct Stack extends array
private static thistype this
private Path pathp
static method operator first takes nothing returns thistype
return this.pathp
endmethod
static method push takes Path path returns nothing
set this = this + 1
set this.pathp = path
endmethod
static method pop takes nothing returns nothing
set this = this - 1
endmethod
static method clear takes nothing returns nothing
set this = 0
endmethod
endstruct
private struct Path extends array
private static integer instanceCount = 0
private static integer array recycler
readonly static real tx = 0
readonly static real ty = 0
readonly static real tr = 0
readonly static integer pt = 0
readonly static boolean isBlocked = true
readonly real x
readonly real y
readonly integer xi
readonly integer yi
readonly boolean open0
readonly boolean open90
readonly boolean open180
readonly boolean open270
readonly integer px
readonly integer py
readonly real ox
readonly real oy
readonly integer ax
readonly integer ay
readonly boolean open
static method create takes real x, real y, real ox, real oy, boolean o returns thistype
local thistype this
local integer xi = NormalizeComponent(x)
local integer yi = NormalizeComponent(y)
local real angle
if (Tile[xi][yi]) then
return -1
endif
if (IsPathable(xi, yi, pt)) then
set Tile[xi][yi] = true
set this = recycler[0]
if (0 == this) then
set this = instanceCount + 1
set instanceCount = this
else
set recycler[0] = recycler[this]
endif
set this.xi = NormalizeComponent(x)
set this.yi = NormalizeComponent(y)
set this.ax = NormalizeComponent(ox)
set this.ay = NormalizeComponent(oy)
set this.open = o
if (o) then
set this.x = x
set this.y = y
set this.ox = ox
set this.oy = oy
set angle = CalculateAngleBetweenPoints(x, y, tx, ty)
set ox = CalculateComponentX(angle)
set oy = CalculateComponentY(angle)
set isBlocked = x + tr < tx or x - tr > tx or y + tr < ty or y - tr > ty
else
set isBlocked = xi + tr < tx or xi - tr > tx or yi + tr < ty or yi - tr > ty
endif
set open0 = IsPathable(xi + 32, yi, pt)
set open90 = IsPathable(xi, yi + 32, pt)
set open180 = IsPathable(xi - 32, yi, pt)
set open270 = IsPathable(xi, yi - 32, pt)
return this
endif
return 0
endmethod
method destroy takes nothing returns nothing
set recycler[this] = recycler[0]
set recycler[0] = this
endmethod
static method clear takes nothing returns nothing
set instanceCount = 0
set recycler[0] = 0
endmethod
static method initialize takes real targetX, real targetY, real targetRadius, integer pathingType returns nothing
set thistype.tx = targetX
set thistype.ty = targetY
set thistype.tr = targetRadius
set thistype.pt = pathingType
set thistype.isBlocked = true
endmethod
private method branchEx2 takes boolean os, boolean oe, integer ax, integer ay returns nothing
local Path path
if (os != oe) then
if (os) then
set path = Path.create(px + ax, py + ay, ax, ay, false)
else
set path = Path.create(xi + ax, yi + ay, ax, ay, false)
endif
if (0 < path) then
call Stack.push(path)
endif
endif
endmethod
private method branchEx takes boolean os, boolean oe, integer ax, integer ay returns nothing
local Path path
if (os != oe) then
if (os) then
set path = Path.create(px + ox, py + oy, ox, oy, true)
if (0 < path) then
call Stack.push(path)
endif
set path = Path.create(px + ax, py + ay, ax, ay, false)
if (0 < path) then
call Stack.push(path)
endif
else
set path = Path.create(xi + ox, yi + oy, ox, oy, true)
if (0 < path) then
call Stack.push(path)
endif
set path = Path.create(xi + ax, yi + ay, ax, ay, false)
if (0 < path) then
call Stack.push(path)
endif
endif
endif
endmethod
method branch takes integer ax, integer ay returns nothing
local Path path = thistype.create(NormalizeComponent(this.xi) + ax, NormalizeComponent(this.yi) + ay, ax, ay, false)
if (0 < path) then
call Stack.push(path)
endif
endmethod
method move takes nothing returns integer
local boolean o0 = open0
local boolean o90 = open90
local boolean o180 = open180
local boolean o270 = open270
local boolean o = open
local real angle
local real nAngle
local Path np
set px = xi
set py = yi
if (o) then
set xi = NormalizeComponent(x + ox)
set yi = NormalizeComponent(y + oy)
else
set xi = xi + ax
set yi = yi + ay
endif
if (Tile[xi][yi]) then
return -1
endif
if (IsPathable(xi, yi, pt)) then
set Tile[xi][yi] = true
// Test
//call CreateUnit(Player(0), 'hfoo', xi, yi, 0)
// Test
set open0 = IsPathable(xi + 32, yi, pt)
set open90 = IsPathable(xi, yi + 32, pt)
set open180 = IsPathable(xi - 32, yi, pt)
set open270 = IsPathable(xi, yi - 32, pt)
if (not o) then
set angle = CalculateAngleBetweenPoints(xi, yi, tx, ty)
set nAngle = NormalizeAngle(angle)
set ox = CalculateComponentX(angle)
set oy = CalculateComponentY(angle)
call branchEx(o0, open0, 32, 0)
call branchEx(o90, open90, 0, 32)
call branchEx(o180, open180, -32, 0)
call branchEx(o270, open270, 0, -32)
else
call branchEx2(o0, open0, 32, 0)
call branchEx2(o90, open90, 0, 32)
call branchEx2(o180, open180, -32, 0)
call branchEx2(o270, open270, 0, -32)
endif
if (o) then
set x = x + ox
set y = y + oy
set isBlocked = x + tr < tx or x - tr > tx or y + tr < ty or y - tr > ty
else
set isBlocked = xi + tr < tx or xi - tr > tx or yi + tr < ty or yi - tr > ty
endif
return 1
endif
if (o) then
set xi = NormalizeComponent(x)
set yi = NormalizeComponent(y)
else
set xi = xi - ax
set yi = yi - ay
endif
return 0
endmethod
endstruct
static if DEBUG_MODE then
private struct Thread extends array
static constant integer OP_LIMIT = 200
private static boolean finished = false
static method start takes nothing returns nothing
set finished = false
endmethod
static method finish takes nothing returns nothing
set finished = true
endmethod
static method operator crashed takes nothing returns boolean
return not finished
endmethod
endstruct
endif
private function ClearAll takes nothing returns nothing
call Path.clear()
call Stack.clear()
call Tile.clear()
endfunction
private module InitializeIsBlocked
private static method onInit takes nothing returns nothing
set isPathBlockedT = CreateTrigger()
call TriggerAddCondition(isPathBlockedT, Condition(function thistype.isPathBlocked))
endmethod
endmodule
private struct IsBlocked extends array
private static trigger isPathBlockedT
private static method isPathBlocked takes nothing returns boolean
local integer op = Thread.OP_LIMIT
local Path path
local integer move
call Thread.start()
loop
set path = Stack.first
exitwhen 0 == path or not path.isBlocked or 0 == op
set op = op - 1
set move = path.move()
if (1 != move) then
call Stack.pop()
if (0 == path.move()) then
call path.branch(0, 32)
call path.branch(0, -32)
call path.branch(32, 0)
call path.branch(-32, 0)
endif
call path.destroy()
endif
endloop
call Thread.finish()
/*
if ((not Path.isBlocked or 0 == Stack.first) and null != GetExpiredTimer()) then
if (Path.isBlocked) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Blocked")
else
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Not Blocked")
endif
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
endif
*/
return not Path.isBlocked or 0 == Stack.first
endmethod
private static method initialize takes real originX, real originY, real targetX, real targetY, real targetRadius, integer pathingType returns boolean
local Path o
local Path origin
local real angle
local real ax
local real ay
local boolean init = false
call ClearAll()
call Path.initialize(targetX, targetY, targetRadius, pathingType)
set angle = CalculateAngleBetweenPoints(originX, originY, targetX, targetY)
set o = Path.create(originX, originY, CalculateComponentX(angle), CalculateComponentY(angle), true)
set angle = NormalizeAngle(angle)
set angle = NormalizeAngle(angle + bj_PI/2)
set ax = CalculateComponentX(angle)
set ay = CalculateComponentY(angle)
set origin = Path.create(originX + ax, originY + ay, ax, ay, false)
if (0 != origin) then
call Stack.push(origin)
set init = true
endif
set angle = NormalizeAngle(angle + bj_PI/2)
set ax = CalculateComponentX(angle)
set ay = CalculateComponentY(angle)
set origin = Path.create(originX + ax, originY + ay, ax, ay, false)
if (0 != origin) then
call Stack.push(origin)
set init = true
endif
set angle = NormalizeAngle(angle + bj_PI/2)
set ax = CalculateComponentX(angle)
set ay = CalculateComponentY(angle)
set origin = Path.create(originX + ax, originY + ay, ax, ay, false)
if (0 != origin) then
call Stack.push(origin)
set init = true
endif
if (0 != o) then
call Stack.push(o)
set init = true
endif
return init
endmethod
static method calculate takes real originX, real originY, real targetX, real targetY, real targetRadius, integer pathingType returns boolean
if (initialize(originX, originY, targetX, targetY, targetRadius, pathingType)) then
loop
exitwhen TriggerEvaluate(isPathBlockedT)
debug if (Thread.crashed) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"IS PATH BLOCKED ERROR: THREAD CRASHED")
debug return true
debug endif
endloop
//call TimerStart(CreateTimer(), .025, true, function thistype.isPathBlocked)
endif
return Path.isBlocked
endmethod
implement InitializeIsBlocked
endstruct
function IsPathBlocked takes real originX, real originY, real targetX, real targetY, real targetRadius, integer pathingType returns boolean
return IsBlocked.calculate(originX, originY, targetX, targetY, targetRadius, pathingType)
endfunction
endlibrary