anchor.diff:  		maxnodedepth = maxnodes //no need to consider path longer than maxnodes
   
   	var/Heap/open = new /Heap(/proc/HeapPathWeightCompare) //the open list
  -	var/list/path = null //the returned path, if any
  -	var/datum/PathNode/cur //current processed turf
  +	var/list/path //the returned path, if any
  +	var/list/closed = exclude
   
   	//initialization
   	open.Insert(new /datum/PathNode(start, astar_id, null, 0, call(start ,dist)(end), 0))
   
  +
   	//then run the main loop
   	while(length(open.L) && !path)
  +		path = AStar_whileloop(open, turfs, maxnodes, dist, end, mintargetdist, maxnodedepth, closed, adjacent, id, astar_id, simulated_only, caller)
  +
  +		CHECK_TICK
  +
  +	AStar_cleanup(turfs, astar_id)
  +
  +
  +
  +	//reverse the path to get it from start to finish
  +	if (path)
  +		AStar_reverse(path)
  +
  +	return path
  +
  +/proc/AStar_reverse(list/path)
  +	for(var/i in 1 to  path.len/2)
  +		path.Swap(i,path.len-i+1)
  +
  +
  +/proc/AStar_cleanup(list/turfs, astar_id)
  +	//cleaning up after us
  +	for(var/thing in turfs)
  +		var/turf/T = thing
  +		var/datum/PathNode/head = T.pathnodes
  +		if (head.astar_id == astar_id)
  +			T.pathnodes = head.next
  +			continue
  +		var/datum/PathNode/P = head
  +		while (P)
  +			var/datum/PathNode/next = P.next
  +			if (next && next.astar_id == astar_id)
  +				P.next = next.next
  +				break
  +			P = next
  +
  +
  +
  +
  +/proc/AStar_whileloop(Heap/open, list/turfs, maxnodes, dist, turf/end, mintargetdist, maxnodedepth, list/exclude, adjacent, id, astar_id, simulated_only, caller)
  +	//get the lower f node on the open list
  +	var/datum/PathNode/cur = open.Pop() //current processed turf
  +	exclude += cur.source //and tell we've processed it
  +
  +	//if we only want to get near the target, check if we're close enough
  +	var/closeenough
  +	if(mintargetdist)
  +		closeenough = call(cur.source, dist)(end) <= mintargetdist
  +
  +	//if too many steps, abandon that path
  +	if(maxnodedepth && (cur.depth > maxnodedepth))
  +		return
  +
  +	//found the target turf (or close enough), let's create the path to it
  +	if(cur.source == end || closeenough)
  +		var/list/path = list(cur.source)
  +
  +		while(cur.parent)
  +			cur = cur.parent
  +			path.Add(cur.source)
  +
  +		return path
  +
  +	//get adjacent turfs using the adjacent proc, checking for access with id
  +	var/list/L = call(cur.source, adjacent)(caller, id, simulated_only)
  +	AStar_filter_turfs(L, cur, open, turfs, astar_id, dist, end, exclude)
  +
  +/proc/AStar_filter_turfs(list/L, datum/PathNode/cur, Heap/open, list/turfs, astar_id, dist, end, list/exclude)
  +	for(var/turf/T in L-exclude)
  +
  +		var/datum/PathNode/P = AStar_find_pathnode(T, astar_id)
  +		if(!P)
  +			AStar_make_new_pathnode(cur, dist, T, turfs, astar_id, end, open)
  +
  +		else //is already in open list, check if it's a better way from the current turf
  +			AStar_check_existing_pathnode(cur, P, dist, L, T, open)
  +
  +/proc/AStar_check_existing_pathnode(datum/PathNode/cur, datum/PathNode/P, dist, list/L, turf/T, Heap/open)
  +	var/newcost = cur.cost + call(cur.source, dist)(T)
  +	if(newcost < P.cost)
  +		AStar_recalc_existing_pathnode(cur, newcost, P, L, open)
  +
  +/proc/AStar_recalc_existing_pathnode(datum/PathNode/cur, newcost, datum/PathNode/P, list/L, Heap/open)
  +	P.parent = cur
  +	P.cost = (newcost * length(L) / 9)
  +	P.weight = P.cost + P.heuristic
  +	P.depth = cur.depth + 1
  +	open.ReSort(P)//reorder the changed element in the list
  +
  +/proc/AStar_make_new_pathnode(datum/PathNode/cur, dist, turf/T, turfs, astar_id, end, Heap/open)
  +	var/newcost = cur.cost + call(cur.source, dist)(T)
  +	var/datum/PathNode/newnode = new /datum/PathNode(T, astar_id, cur, newcost, call(T, dist)(end), cur.depth+1)
  +	open.Insert(newnode)
  +	newnode.next = T.pathnodes
  +	T.pathnodes = newnode
  +	turfs += T
  +
  +/proc/AStar_find_pathnode(turf/T, astar_id)
  +	//99% of the time, the first node will be ours, so we can skip a for overhead by lazy accessing.
  +	var/datum/PathNode/P = AStar_find_pathnode_quick_try(T)
  +
  +	if (!P || P.astar_id != astar_id)
  +		return AStar_find_pathnode_full_try(P, astar_id)
  +
  +	return P
  +
  +/proc/AStar_find_pathnode_full_try(datum/PathNode/P, astar_id)
  +	var/datum/PathNode/PN
  +	for(PN = P; PN && PN.astar_id != astar_id; PN = PN.next); //byond magic
  +	return PN
  +
  +/proc/AStar_find_pathnode_quick_try(turf/T)
  +	return T.pathnodes
  +
  +
  +/turf/var/list/pathnodes
  +
  +
  +//////////////////////
  +//PathNode object
  +//////////////////////
  +
  +//A* nodes variables
  +/PathNode
  +	var/turf/source //turf associated with the PathNode
  +	var/PathNode/prevNode //link to the parent PathNode
  +	var/f		//A* Node weight (f = g + h)
  +	var/g		//A* movement cost variable
  +	var/h		//A* heuristic variable
  +	var/nt		//count the number of Nodes traversed
  +
  +/PathNode/New(s,p,pg,ph,pnt)
  +	source = s
  +	prevNode = p
  +	g = pg
  +	h = ph
  +	f = g + h
  +	source.PNode = src
  +	nt = pnt
  +
  +/PathNode/proc/calc_f()
  +	f = g + h
  +
  +//////////////////////
  +//A* procs
  +//////////////////////
  +
  +//the weighting function, used in the A* algorithm
  +///proc/PathWeightCompare2(PathNode/a, PathNode/b)
  +//	return a.f - b.f
  +
  +//reversed so that the Heap is a MinHeap rather than a MaxHeap
  +/proc/HeapPathWeightCompare2(PathNode/a, PathNode/b)
  +	return b.f - a.f
  +
  +//the actual algorithm
  +/proc/AStar_goof(caller, end, dist, maxnodes, maxnodedepth = 30, mintargetdist, adjacent = /turf/proc/reachableAdjacentTurfs, id=null, turf/exclude=null, simulated_only = 1)
  +	//sanitation
  +	var/start = get_turf(caller)
  +	if(!start)
  +		return 0
  +
  +	if(maxnodes)
  +		//if start turf is farther than maxnodes from end turf, no need to do anything
  +		if(call(start, dist)(end) > maxnodes)
  +			return 0
  +		maxnodedepth = maxnodes //no need to consider path longer than maxnodes
  +
  +	var/Heap/open = new /Heap(/proc/HeapPathWeightCompare2) //the open list
  +	var/list/closed = new() //the closed list
  +	var/list/path = null //the returned path, if any
  +	var/PathNode/cur //current processed turf
  +
  +	//initialization
  +	open.Insert(new /PathNode(start,null,0,call(start,dist)(end),0))
  +
  +	//then run the main loop
  +	while(!open.IsEmpty() && !path)
   		//get the lower f node on the open list
   		cur = open.Pop() //get the lower f turf in the open list
  -		cur.closed = TRUE //and tell we've processed it
  +		closed.Add(cur.source) //and tell we've processed it
   
   		//if we only want to get near the target, check if we're close enough
   		var/closeenough
   		if(mintargetdist)
  -			closeenough = call(cur.source, dist)(end) <= mintargetdist
  +			closeenough = call(cur.source,dist)(end) <= mintargetdist
   
   		//if too many steps, abandon that path
  -		if(maxnodedepth && (cur.depth > maxnodedepth))
  +		if(maxnodedepth && (cur.nt > maxnodedepth))
   			continue
   
   		//found the target turf (or close enough), let's create the path to it
  
positive.code: 			path = new()
  			path.Add(cur.source)
  
  			while(cur.parent)
  				cur = cur.parent
  				path.Add(cur.source)
  
  			break
  
  		//get adjacents turfs using the adjacent proc, checking for access with id
  		var/list/L = call(cur.source,adjacent)(caller, id, simulated_only)
  		for(var/turf/T in L)
  			if(exclude[T])
  				continue
  
  
  
  			//99% of the time, the first node will be ours, so we can skip a for overhead by lazy accessing.
  			var/datum/PathNode/P = LAZYACCESSFAST(T.pathnodes, 1)
  
  			if (!P || P.astar_id != astar_id)
  				P = null
  				for (var/thing in T.pathnodes)
  					var/datum/PathNode/PN = thing
  					if (PN.astar_id == astar_id)
  						P = PN
  						break
  			if(!P)
  				//is not already in open list, so add it
  				var/newcost = cur.cost + call(cur.source,dist)(T)
  				var/datum/PathNode/newnode = new /datum/PathNode(T, astar_id, cur, newcost, call(T, dist)(end), cur.depth+1)
  				open.Insert(newnode)
  				LAZYADD(T.pathnodes, newnode)
  				turfs += T
  
  			else //is already in open list, check if it's a better way from the current turf
  				if (P.closed)
  					continue
  				var/newcost = cur.cost + call(cur.source,dist)(T)
  				if(newcost < P.cost)
  					P.parent = cur
  					P.cost = (newcost * length(L) / 9)
  					P.weight = P.cost + P.heuristic
  					P.depth = cur.depth + 1
  					open.ReSort(P)//reorder the changed element in the list
  		CHECK_TICK
  
  
  	//cleaning up after us
  	for(var/thing in turfs)
  		var/turf/T = thing
  
  		var/datum/PathNode/P = LAZYACCESSFAST(T.pathnodes, 1)
  
  		if (!P || P.astar_id != astar_id)
  			for (var/thing2 in T.pathnodes)
  				var/datum/PathNode/PN = thing2
  				if (PN.astar_id == astar_id)
  					P = PN
  					break
  
  		T.pathnodes -= P
  		UNSETEMPTY(T.pathnodes)
  
  
  
  	//reverse the path to get it from start to finish
  	if(path)
  		for(var/i in 1 to  path.len/2)
  			path.Swap(i,path.len-i+1)
  
  	return path
  
  /turf/var/list/pathnodes
  
  //Returns adjacent turfs in cardinal directions that are reachable
  //simulated_only controls whether only simulated turfs are considered or not
  
negative.code: /datum/PathNode
  	var/turf/source 			//turf associated with the PathNode
  	var/astar_id				//Id of the astar operation we belong to
  	var/datum/PathNode/parent	//link to the parent PathNode
  	var/weight					//f A* Node weight (f = g + h)
  	var/cost					//g A* movement cost variable
  	var/heuristic				//h A* heuristic variable = h
  	var/depth					//ht count the number of Nodes traversed
  	var/PathNode/next			//next node in the linked list stack.
  
  /datum/PathNode/New(s, id, p, pg, ph, pnt)
  	source = s
  