mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-26 21:48:21 +01:00
AStar update
This commit is contained in:
@@ -169,23 +169,6 @@ Turf and target are seperate in case you want to teleport some distance from a t
|
||||
|
||||
return destination
|
||||
|
||||
///////////////////
|
||||
//A* helpers procs
|
||||
///////////////////
|
||||
|
||||
// Returns true if a link is blocked and neither location has something climbable on
|
||||
// Used for inventory checks
|
||||
/proc/LinkBlockedUnclimbable(turf/A, turf/B)
|
||||
if (!A.LinkBlocked(A, B))
|
||||
return 0
|
||||
for (var/obj/structure/S in A.contents)
|
||||
if(S.climbable)
|
||||
return 0
|
||||
for (var/obj/structure/S in B.contents)
|
||||
if(S.climbable)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
// Returns true if direction is blocked from loc
|
||||
// Checks if doors are open
|
||||
/proc/DirBlocked(turf/loc,var/dir)
|
||||
|
||||
+37
-77
@@ -3,47 +3,25 @@ A Star pathfinding algorithm
|
||||
Returns a list of tiles forming a path from A to B, taking dense objects as well as walls, and the orientation of
|
||||
windows along the route into account.
|
||||
Use:
|
||||
your_list = AStar(start location, end location, adjacent turf proc, distance proc)
|
||||
For the adjacent turf proc i wrote:
|
||||
/turf/proc/AdjacentTurfs
|
||||
And for the distance one i wrote:
|
||||
/turf/proc/Distance
|
||||
So an example use might be:
|
||||
|
||||
src.path_list = AStar(src.loc, target.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance)
|
||||
|
||||
Then to start on the path, all you need to do it:
|
||||
Step_to(src, src.path_list[1])
|
||||
src.path_list -= src.path_list[1] or equivilent to remove that node from the list.
|
||||
your_list = AStar(start location, end location, moving atom, distance proc, max nodes, maximum node depth, minimum distance to target, adjacent proc, atom id, turfs to exclude, check only simulated)
|
||||
|
||||
Optional extras to add on (in order):
|
||||
Distance proc : the distance used in every A* calculation (length of path and heuristic)
|
||||
MaxNodes: The maximum number of nodes the returned path can be (0 = infinite)
|
||||
Maxnodedepth: The maximum number of nodes to search (default: 30, 0 = infinite)
|
||||
Mintargetdist: Minimum distance to the target before path returns, could be used to get
|
||||
near a target, but not right to it - for an AI mob with a gun, for example.
|
||||
Minnodedist: Minimum number of nodes to return in the path, could be used to give a path a minimum
|
||||
length to avoid portals or something i guess?? Not that they're counted right now but w/e.
|
||||
Adjacent proc : returns the turfs to consider around the actually processed node
|
||||
Simulated only : whether to consider unsimulated turfs or not (used by some Adjacent proc)
|
||||
|
||||
Also added 'exclude' turf to avoid travelling over; defaults to null
|
||||
|
||||
Modified to provide ID argument - supplied to 'adjacent' proc, defaults to null
|
||||
Used for checking if route exists through a door which can be opened
|
||||
Actual Adjacent procs :
|
||||
|
||||
Also added 'exclude' turf to avoid travelling over; defaults to null
|
||||
/turf/proc/reachableAdjacentTurfs : returns reachable turfs in cardinal directions (uses simulated_only)
|
||||
|
||||
Currently, there's four main ways to call AStar
|
||||
/turf/proc/reachableAdjacentAtmosTurfs : returns turfs in cardinal directions reachable via atmos
|
||||
|
||||
1) adjacent = "/turf/proc/AdjacentTurfsWithAccess" and distance = "/turf/proc/Distance"
|
||||
Seeks a path moving in all directions (including diagonal) and checking for the correct id to get through doors
|
||||
|
||||
2) adjacent = "/turf/proc/CardinalTurfsWithAccess" and distance = "/turf/proc/Distance_cardinal"
|
||||
Seeks a path moving only in cardinal directions and checking if for the correct id to get through doors
|
||||
Used by most bots, including Beepsky
|
||||
|
||||
3) adjacent = "/turf/proc/AdjacentTurfs" and distance = "/turf/proc/Distance"
|
||||
Same as 1), but don't check for ID. Can get only get through open doors
|
||||
|
||||
4) adjacent = "/turf/proc/AdjacentTurfsSpace" and distance = "/turf/proc/Distance"
|
||||
Same as 1), but check all turf, including unsimulated
|
||||
*/
|
||||
|
||||
//////////////////////
|
||||
@@ -83,26 +61,15 @@ length to avoid portals or something i guess?? Not that they're counted right no
|
||||
/proc/HeapPathWeightCompare(PathNode/a, PathNode/b)
|
||||
return b.f - a.f
|
||||
|
||||
//search if there's a PathNode that points to turf T in the Priority Queue
|
||||
/proc/SeekTurf(var/PriorityQueue/Queue, turf/T)
|
||||
var/i = 1
|
||||
var/PathNode/PN
|
||||
while(i < Queue.L.len + 1)
|
||||
PN = Queue.L[i]
|
||||
if(PN.source == T)
|
||||
return i
|
||||
i++
|
||||
return 0
|
||||
|
||||
//wrapper that returns an empty list if A* failed to find a path
|
||||
/proc/get_path_to(start, end, atom, dist, maxnodes, maxnodedepth = 30, mintargetdist, minnodedist, id=null, turf/exclude=null)
|
||||
var/list/path = AStar(start, end, atom, dist, maxnodes, maxnodedepth, mintargetdist, minnodedist,id, exclude)
|
||||
/proc/get_path_to(start, end, atom, dist, maxnodes, maxnodedepth = 30, mintargetdist, adjacent = /turf/proc/reachableAdjacentTurfs, id=null, turf/exclude=null, simulated_only = 1)
|
||||
var/list/path = AStar(start, end, atom, dist, maxnodes, maxnodedepth, mintargetdist, adjacent,id, exclude, simulated_only)
|
||||
if(!path)
|
||||
path = list()
|
||||
return path
|
||||
|
||||
//the actual algorithm
|
||||
/proc/AStar(start, end, atom, dist, maxnodes, maxnodedepth = 30, mintargetdist, minnodedist, id=null, turf/exclude=null)
|
||||
/proc/AStar(start, end, atom, dist, maxnodes, maxnodedepth = 30, mintargetdist, adjacent = /turf/proc/reachableAdjacentTurfs, id=null, turf/exclude=null, simulated_only = 1)
|
||||
var/Heap/open = new /Heap(/proc/HeapPathWeightCompare) //the open list
|
||||
var/list/closed = new() //the closed list
|
||||
var/list/path = null //the returned path, if any
|
||||
@@ -136,22 +103,15 @@ length to avoid portals or something i guess?? Not that they're counted right no
|
||||
if(cur.source == end || closeenough)
|
||||
path = new()
|
||||
path.Add(cur.source)
|
||||
|
||||
while(cur.prevNode)
|
||||
cur = cur.prevNode
|
||||
path.Add(cur.source)
|
||||
|
||||
break
|
||||
|
||||
//IMPLEMENTATION TO FINISH
|
||||
//do we really need this minnodedist ???
|
||||
/*if(minnodedist && maxnodedepth)
|
||||
if(call(cur.source,minnodedist)(end) + cur.nt >= maxnodedepth)
|
||||
continue
|
||||
*/
|
||||
|
||||
//get adjacents turfs using the adjacent proc, checking for access with id
|
||||
//var/list/L = call(cur.source,adjacent)(id,closed)
|
||||
var/list/L = cur.source.reachableAdjacentTurfs(atom, id)
|
||||
var/list/L = call(cur.source,adjacent)(atom,id, simulated_only)
|
||||
for(var/turf/T in L)
|
||||
if(T == exclude || T in closed)
|
||||
continue
|
||||
@@ -186,33 +146,33 @@ length to avoid portals or something i guess?? Not that they're counted right no
|
||||
|
||||
return path
|
||||
|
||||
/turf/proc/reachableAdjacentTurfs(atom, ID)
|
||||
//Returns adjacent turfs in cardinal directions that are reachable
|
||||
//simulated_only controls whether only simulated turfs are considered or not
|
||||
/turf/proc/reachableAdjacentTurfs(atom, ID, simulated_only)
|
||||
var/list/L = new()
|
||||
var/turf/simulated/T
|
||||
if(ID)
|
||||
for(var/dir in cardinal)
|
||||
T = get_step(src,dir)
|
||||
if(!istype(T) || T.density)
|
||||
continue
|
||||
if(!LinkBlockedWithAccess(T, ID))
|
||||
L.Add(T)
|
||||
else
|
||||
for(var/dir in cardinal)
|
||||
if(dir & atmos_adjacent_turfs)
|
||||
T = get_step(src,dir)
|
||||
if(!istype(T))
|
||||
continue
|
||||
if(!LinkBlocked(atom, T))
|
||||
L.Add(T)
|
||||
|
||||
for(var/dir in cardinal)
|
||||
T = get_step(src,dir)
|
||||
if(simulated_only && !istype(T))
|
||||
continue
|
||||
if(!T.density && !LinkBlockedWithAccess(T, ID))
|
||||
L.Add(T)
|
||||
return L
|
||||
|
||||
/turf/proc/LinkBlocked(atom, turf/T)
|
||||
if(istype(atom, /atom/movable))
|
||||
for(var/obj/O in T)
|
||||
if(!O.CanPass(atom, T, 1))
|
||||
return 1
|
||||
return 0
|
||||
return 0
|
||||
//Returns adjacent turfs in cardinal directions that are reachable via atmos
|
||||
/turf/proc/reachableAdjacentAtmosTurfs()
|
||||
var/list/L = new()
|
||||
var/turf/simulated/T
|
||||
|
||||
for(var/dir in cardinal)
|
||||
if(dir & atmos_adjacent_turfs)
|
||||
T = get_step(src,dir)
|
||||
if(!istype(T))
|
||||
continue
|
||||
if(CanAtmosPass(T))
|
||||
L.Add(T)
|
||||
return L
|
||||
|
||||
/turf/proc/LinkBlockedWithAccess(turf/T, obj/item/weapon/card/id/ID)
|
||||
var/adir = get_dir(src, T)
|
||||
@@ -237,4 +197,4 @@ length to avoid portals or something i guess?? Not that they're counted right no
|
||||
for(var/obj/machinery/door/D in T)
|
||||
if(!D.CanAStarPass(ID, dir))
|
||||
return 1
|
||||
return 0
|
||||
return 0
|
||||
@@ -39,9 +39,7 @@
|
||||
return
|
||||
if(!isturf(user.loc))
|
||||
return
|
||||
if(get_dist(user, target) > (user.mind.changeling.sting_range))
|
||||
return //sanity check as AStar is still throwing insane stunts
|
||||
if(!AStar(user.loc, target.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, user.mind.changeling.sting_range))
|
||||
if(!AStar(user.loc, target.loc, null, /turf/proc/Distance, user.mind.changeling.sting_range, simulated_only = 0))
|
||||
return //hope this ancient magic still works
|
||||
if(target.mind && target.mind.changeling)
|
||||
sting_feedback(user,target)
|
||||
|
||||
@@ -347,7 +347,7 @@
|
||||
if(locs.len == 2) //we found 2 locations and thats all we need
|
||||
break
|
||||
var/turf/T = get_step(M.current,direction) //getting a loc in that direction
|
||||
if(AStar(M.current.loc, T, /turf/proc/AdjacentTurfs, /turf/proc/Distance, 1)) // if a path exists, so no dense objects in the way its valid salid
|
||||
if(AStar(M.current.loc, T, /turf/proc/AdjacentTurfs, /turf/proc/Distance, 1, simulated_only = 0)) // if a path exists, so no dense objects in the way its valid salid
|
||||
locs += T
|
||||
if(locs.len)
|
||||
for(var/turf/tospawn in locs)
|
||||
|
||||
@@ -272,9 +272,9 @@
|
||||
if(path.len == 0)
|
||||
if(!istype(target, /turf/))
|
||||
var/turf/TL = get_turf(target)
|
||||
path = get_path_to(loc, TL, src, /turf/proc/Distance_cardinal, 0, 30, id=botcard)
|
||||
path = get_path_to(loc, TL, src, /turf/proc/Distance_cardinal, 0, 30, id=botcard, simulated_only = 0)
|
||||
else
|
||||
path = get_path_to(loc, target, src, /turf/proc/Distance_cardinal, 0, 30, id=botcard)
|
||||
path = get_path_to(loc, target, src, /turf/proc/Distance_cardinal, 0, 30, id=botcard, simulated_only = 0)
|
||||
|
||||
if(!bot_move(target))
|
||||
add_to_ignore(target)
|
||||
|
||||
@@ -273,7 +273,7 @@
|
||||
for(var/dir in cardinal)
|
||||
T = get_step(src, dir)
|
||||
if(istype(T) && !T.density)
|
||||
if(!LinkBlocked(src, T))
|
||||
if(!CanAtmosPass(T))
|
||||
L.Add(T)
|
||||
return L
|
||||
|
||||
@@ -304,7 +304,7 @@
|
||||
if(T in closed) //turf already proceeded by A*
|
||||
continue
|
||||
if(istype(T) && !T.density)
|
||||
if(!LinkBlocked(src, T))
|
||||
if(!CanAtmosPass(T))
|
||||
L.Add(T)
|
||||
return L
|
||||
|
||||
@@ -318,7 +318,7 @@
|
||||
continue
|
||||
if(istype(T) && !T.density)
|
||||
if(!ID)
|
||||
if(!LinkBlocked(src, T))
|
||||
if(!CanAtmosPass(T))
|
||||
L.Add(T)
|
||||
else
|
||||
if(!LinkBlockedWithAccess(src, T, ID))
|
||||
|
||||
@@ -618,7 +618,7 @@ It can still be worn/put on as normal.
|
||||
if(!source || !target) return //Target or source no longer exist
|
||||
if(source.loc != s_loc) return //source has moved
|
||||
if(target.loc != t_loc) return //target has moved
|
||||
if (LinkBlockedUnclimbable(t_loc, s_loc)) return
|
||||
if(!in_range(source, target)) return
|
||||
if(item && source.get_active_hand() != item) return //Swapped hands / removed item from the active one
|
||||
if ((source.restrained() || source.stat)) return //Source restrained or unconscious / dead
|
||||
if(target.frozen)
|
||||
|
||||
Reference in New Issue
Block a user