Name | Type | is_array | initial_value |
library TerrainPathability initializer Init
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This script can be used to detect the type of pathing at a specific point.
//* It is valuable to do it this way because the IsTerrainPathable is very
//* counterintuitive and returns in odd ways and aren't always as you would
//* expect. This library, however, facilitates detecting those things reliably
//* and easily.
//*
//******************************************************************************
//*
//* > function IsTerrainDeepWater takes real x, real y returns boolean
//* > function IsTerrainShallowWater takes real x, real y returns boolean
//* > function IsTerrainLand takes real x, real y returns boolean
//* > function IsTerrainPlatform takes real x, real y returns boolean
//* > function IsTerrainWalkable takes real x, real y returns boolean
//*
//* These functions return true if the given point is of the type specified
//* in the function's name and false if it is not. For the IsTerrainWalkable
//* function, the MAX_RANGE constant below is the maximum deviation range from
//* the supplied coordinates that will still return true.
//*
//* The IsTerrainPlatform works for any preplaced walkable destructable. It will
//* return true over bridges, destructable ramps, elevators, and invisible
//* platforms. Walkable destructables created at runtime do not create the same
//* pathing hole as preplaced ones do, so this will return false for them. All
//* other functions except IsTerrainWalkable return false for platforms, because
//* the platform itself erases their pathing when the map is saved.
//*
//* After calling IsTerrainWalkable(x, y), the following two global variables
//* gain meaning. They return the X and Y coordinates of the nearest walkable
//* point to the specified coordinates. These will only deviate from the
//* IsTerrainWalkable function arguments if the function returned false.
//*
//* Variables that can be used from the library:
//* [real] TerrainPathability_X
//* [real] TerrainPathability_Y
//*
globals
private constant real MAX_RANGE = 10.
private constant integer DUMMY_ITEM_ID = 'wolg'
endglobals
globals
private item Item = null
private rect Find = null
private item array Hid
private integer HidMax = 0
public real X = 0.
public real Y = 0.
endglobals
function IsTerrainDeepWater takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
function IsTerrainShallowWater takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
function IsTerrainLand takes real x, real y returns boolean
return IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY)
endfunction
function IsTerrainPlatform takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
private function HideItem takes nothing returns nothing
if IsItemVisible(GetEnumItem()) then
set Hid[HidMax] = GetEnumItem()
call SetItemVisible(Hid[HidMax], false)
set HidMax = HidMax + 1
endif
endfunction
function IsTerrainWalkable takes real x, real y returns boolean
//Hide any items in the area to avoid conflicts with our item
call MoveRectTo(Find, x, y)
call EnumItemsInRect(Find ,null, function HideItem)
//Try to move the test item and get its coords
call SetItemPosition(Item, x, y) //Unhides the item
set X = GetItemX(Item)
set Y = GetItemY(Item)
static if LIBRARY_IsTerrainWalkable then
//This is for compatibility with the IsTerrainWalkable library
set IsTerrainWalkable_X = X
set IsTerrainWalkable_Y = Y
endif
call SetItemVisible(Item, false)//Hide it again
//Unhide any items hidden at the start
loop
exitwhen HidMax <= 0
set HidMax = HidMax - 1
call SetItemVisible(Hid[HidMax], true)
set Hid[HidMax] = null
endloop
//Return walkability
return (X-x)*(X-x)+(Y-y)*(Y-y) <= MAX_RANGE*MAX_RANGE and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
private function Init takes nothing returns nothing
set Find = Rect(0., 0., 128., 128.)
set Item = CreateItem(DUMMY_ITEM_ID, 0, 0)
call SetItemVisible(Item, false)
endfunction
endlibrary
library IsPathWalkable initializer init uses TerrainPathability // v1.0
//get it here: [url]http://www.wc3c.net/showthread.php?t=103862[/url]
/*
Description:
This snippet uses the Bresenham algorithm of Pixelgraphics to check if the direct path between two cells (as a straight line) is walkable or not. It does so by looping through each cell between the two coordinates and checking their respective pathabilities.
Note: This snippet will ignore the collision of units, but will consider all doodad, destructable or terrain pathing. If you want to consider unit collision aswell, simply swap out TerrainPathability for your desired resource and replace all IsTerrainWalkable calls in the script.
Configurables:
private constant boolean DIAGONAL_SAFETY
- determines if on any diagonal step an adjacent cell is checked for extra safety (since units can not pass between two diagonally blocked cells). Default: enabled (true)
private constant integer MIN_CELL_SIZE
- determines the cell size for the Bresenham algorithm. As default pathing textures have a minimum cell size of 64, lowering this to 32 only makes sense if custom pathing textures are used. Default: 64.
API:
function IsPathWalkable takes real x1, real y1, real x2, real y2 returns boolean
- returns true if the path between coordinates x1|y1 (start) and x2|y2 (end) is walkable
function GetPathLastX takes nothing returns real
function GetPathLastY takes nothing returns real
- after using IsPathWalkable, these two functions will return the x and y coordinate of the last pathable cell between the start and end coordinate.
*/
globals
private constant boolean DIAGONAL_SAFETY = true
private constant integer MIN_CELL_SIZE = 64
private constant integer CELL_CENTER_OFFSET = MIN_CELL_SIZE/2
private real X = 0
private real Y = 0
private real WORLD_MIN_X = 0
private real WORLD_MIN_Y = 0
endglobals
function IsPathWalkable takes real x1, real y1, real x2, real y2 returns boolean
local integer xstart = R2I(x1-WORLD_MIN_X) / MIN_CELL_SIZE
local integer xend = R2I(x2-WORLD_MIN_X) / MIN_CELL_SIZE
local integer ystart = R2I(y1-WORLD_MIN_Y) / MIN_CELL_SIZE
local integer yend = R2I(y2-WORLD_MIN_Y) / MIN_CELL_SIZE
local integer dx = xend - xstart
local integer dy = yend - ystart
local integer adx = dx
local integer ady = dy
local integer sdx = 0
local integer sdy = 0
local integer pdx
local integer pdy
local integer ddx
local integer ddy
local integer es
local integer el
local integer error
local integer x = xstart
local integer y = ystart
local integer i = 1
set X = x1
set Y = y1
//calculate abs values and signs
if adx < 0 then
set adx = -adx
set sdx = -1
elseif adx > 0 then
set sdx = 1
endif
if ady < 0 then
set ady = -ady
set sdy = -1
elseif ady > 0 then
set sdy = 1
endif
if adx > ady then
set pdx = sdx
set pdy = 0
set es = ady
set el = adx
else
set pdx = 0
set pdy = sdy
set es = adx
set el = ady
endif
set ddx = sdx
set ddy = sdy
if not IsTerrainWalkable(x*MIN_CELL_SIZE+CELL_CENTER_OFFSET+WORLD_MIN_X, y*MIN_CELL_SIZE+CELL_CENTER_OFFSET+WORLD_MIN_Y) then
return false
endif
set error = el/2
loop
exitwhen i > el
set error = error - es
if error < 0 then
if DIAGONAL_SAFETY then
set dx = x+ddx-pdx
set dy = y+ddy-pdy
if IsTerrainWalkable(dx*MIN_CELL_SIZE+CELL_CENTER_OFFSET+WORLD_MIN_X, dy*MIN_CELL_SIZE+CELL_CENTER_OFFSET+WORLD_MIN_Y) then
set X = dx*MIN_CELL_SIZE+CELL_CENTER_OFFSET+WORLD_MIN_X
set Y = dy*MIN_CELL_SIZE+CELL_CENTER_OFFSET+WORLD_MIN_Y
else
return false
endif
endif
set error = error + el
set x = x + ddx
set y = y + ddy
else
set x = x + pdx
set y = y + pdy
endif
if IsTerrainWalkable(x*MIN_CELL_SIZE+CELL_CENTER_OFFSET+WORLD_MIN_X, y*MIN_CELL_SIZE+CELL_CENTER_OFFSET+WORLD_MIN_Y) then
set X = x*MIN_CELL_SIZE+CELL_CENTER_OFFSET+WORLD_MIN_X
set Y = y*MIN_CELL_SIZE+CELL_CENTER_OFFSET+WORLD_MIN_Y
else
return false
endif
set i = i + 1
endloop
return true
endfunction
function GetPathLastX takes nothing returns real
return X
endfunction
function GetPathLastY takes nothing returns real
return Y
endfunction
private function init takes nothing returns nothing
local rect r = GetWorldBounds()
set WORLD_MIN_X = GetRectMinX(r)
set WORLD_MIN_Y = GetRectMinY(r)
set r = null
endfunction
endlibrary
function Trig_MovementFix_Actions takes nothing returns nothing
local real X1 = GetUnitX(GetTriggerUnit())
local real Y1 = GetUnitY(GetTriggerUnit())
local real X2 = GetOrderPointX()
local real Y2 = GetOrderPointY()
if ( not IsPathWalkable(X1, Y1, X2, Y2)) then
call IssuePointOrder( GetTriggerUnit(), "move", GetPathLastX(), GetPathLastY())
endif
endfunction
//===========================================================================
function InitTrig_MovementFix takes nothing returns nothing
set gg_trg_MovementFix = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_MovementFix, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerAddAction( gg_trg_MovementFix, function Trig_MovementFix_Actions )
endfunction