/tg/ 4/14 (#367)
* outside code stuff * defines, helpers, etc * everything not module * modules * compiled fixes + missing sounds
This commit is contained in:
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
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, 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.
|
||||
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
|
||||
|
||||
Actual Adjacent procs :
|
||||
|
||||
/turf/proc/reachableAdjacentTurfs : returns reachable turfs in cardinal directions (uses simulated_only)
|
||||
|
||||
/turf/proc/reachableAdjacentAtmosTurfs : returns turfs in cardinal directions reachable via atmos
|
||||
|
||||
*/
|
||||
|
||||
//////////////////////
|
||||
//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
|
||||
nt = pnt
|
||||
|
||||
/PathNode/proc/calc_f()
|
||||
f = g + h
|
||||
|
||||
//////////////////////
|
||||
//A* procs
|
||||
//////////////////////
|
||||
|
||||
//the weighting function, used in the A* algorithm
|
||||
/proc/PathWeightCompare(PathNode/a, PathNode/b)
|
||||
return a.f - b.f
|
||||
|
||||
//reversed so that the Heap is a MinHeap rather than a MaxHeap
|
||||
/proc/HeapPathWeightCompare(PathNode/a, PathNode/b)
|
||||
return b.f - a.f
|
||||
|
||||
//wrapper that returns an empty list if A* failed to find a path
|
||||
/proc/get_path_to(caller, end, dist, maxnodes, maxnodedepth = 30, mintargetdist, adjacent = /turf/proc/reachableAdjacentTurfs, id=null, turf/exclude=null, simulated_only = 1)
|
||||
var/list/path = AStar(caller, end, dist, maxnodes, maxnodedepth, mintargetdist, adjacent,id, exclude, simulated_only)
|
||||
if(!path)
|
||||
path = list()
|
||||
return path
|
||||
|
||||
//the actual algorithm
|
||||
/proc/AStar(caller, end, dist, maxnodes, maxnodedepth = 30, mintargetdist, adjacent = /turf/proc/reachableAdjacentTurfs, id=null, turf/exclude=null, simulated_only = 1)
|
||||
var/list/pnodelist = list()
|
||||
//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/HeapPathWeightCompare) //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
|
||||
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
|
||||
|
||||
//if too many steps, abandon that path
|
||||
if(maxnodedepth && (cur.nt > maxnodedepth))
|
||||
continue
|
||||
|
||||
//found the target turf (or close enough), let's create the path to it
|
||||
if(cur.source == end || closeenough)
|
||||
path = new()
|
||||
path.Add(cur.source)
|
||||
|
||||
while(cur.prevNode)
|
||||
cur = cur.prevNode
|
||||
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(T == exclude || (T in closed))
|
||||
continue
|
||||
|
||||
var/newg = cur.g + call(cur.source,dist)(T)
|
||||
|
||||
var/PathNode/P = pnodelist[T]
|
||||
if(!P)
|
||||
//is not already in open list, so add it
|
||||
var/PathNode/newnode = new /PathNode(T,cur,newg,call(T,dist)(end),cur.nt+1)
|
||||
open.Insert(newnode)
|
||||
pnodelist[T] = newnode
|
||||
else //is already in open list, check if it's a better way from the current turf
|
||||
if(newg < P.g)
|
||||
P.prevNode = cur
|
||||
P.g = (newg * L.len / 9)
|
||||
P.calc_f()
|
||||
P.nt = cur.nt + 1
|
||||
open.ReSort(P)//reorder the changed element in the list
|
||||
CHECK_TICK
|
||||
|
||||
|
||||
//cleaning after us
|
||||
pnodelist = null
|
||||
|
||||
//reverse the path to get it from start to finish
|
||||
if(path)
|
||||
for(var/i = 1; i <= path.len/2; i++)
|
||||
path.Swap(i,path.len-i+1)
|
||||
|
||||
return path
|
||||
|
||||
//Returns adjacent turfs in cardinal directions that are reachable
|
||||
//simulated_only controls whether only simulated turfs are considered or not
|
||||
/turf/proc/reachableAdjacentTurfs(caller, ID, simulated_only)
|
||||
var/list/L = new()
|
||||
var/turf/T
|
||||
|
||||
for(var/dir in GLOB.cardinal)
|
||||
T = get_step(src,dir)
|
||||
if(simulated_only && !istype(T))
|
||||
continue
|
||||
if(!T.density && !LinkBlockedWithAccess(T,caller, ID))
|
||||
L.Add(T)
|
||||
return L
|
||||
|
||||
//Returns adjacent turfs in cardinal directions that are reachable via atmos
|
||||
/turf/proc/reachableAdjacentAtmosTurfs()
|
||||
return atmos_adjacent_turfs
|
||||
|
||||
/turf/proc/LinkBlockedWithAccess(turf/T, caller, ID)
|
||||
var/adir = get_dir(src, T)
|
||||
var/rdir = get_dir(T, src)
|
||||
|
||||
for(var/obj/structure/window/W in src)
|
||||
if(!W.CanAStarPass(ID, adir))
|
||||
return 1
|
||||
for(var/obj/O in T)
|
||||
if(!O.CanAStarPass(ID, rdir, caller))
|
||||
return 1
|
||||
|
||||
return 0
|
||||
@@ -63,11 +63,11 @@ DBConnection/proc/Connect()
|
||||
if(failed_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to connect anymore.
|
||||
return FALSE
|
||||
|
||||
var/user = GLOB.sqlfdbklogin
|
||||
var/pass = GLOB.sqlfdbkpass
|
||||
var/db = GLOB.sqlfdbkdb
|
||||
var/address = GLOB.sqladdress
|
||||
var/port = GLOB.sqlport
|
||||
var/user = global.sqlfdbklogin
|
||||
var/pass = global.sqlfdbkpass
|
||||
var/db = global.sqlfdbkdb
|
||||
var/address = global.sqladdress
|
||||
var/port = global.sqlport
|
||||
|
||||
doConnect("dbi:mysql:[db]:[address]:[port]","[user]","[pass]")
|
||||
. = IsConnected()
|
||||
@@ -98,7 +98,7 @@ DBConnection/proc/ErrorMsg() return _dm_db_error_msg(_db_con)
|
||||
DBConnection/proc/SelectDB(database_name,dbi)
|
||||
if(IsConnected()) Disconnect()
|
||||
//return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[DB_SERVER]:[DB_PORT]"]",user,password)
|
||||
return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[GLOB.sqladdress]:[GLOB.sqlport]"]",user,password)
|
||||
return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[global.sqladdress]:[global.sqlport]"]",user,password)
|
||||
DBConnection/proc/NewQuery(sql_query,cursor_handler=src.default_cursor) return new/DBQuery(sql_query,src,cursor_handler)
|
||||
|
||||
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/proc/priority_announce(text, title = "", sound = 'sound/AI/attention.ogg', type)
|
||||
if(!text)
|
||||
return
|
||||
|
||||
var/announcement
|
||||
|
||||
if(type == "Priority")
|
||||
announcement += "<h1 class='alert'>Priority Announcement</h1>"
|
||||
if (title && length(title) > 0)
|
||||
announcement += "<br><h2 class='alert'>[html_encode(title)]</h2>"
|
||||
else if(type == "Captain")
|
||||
announcement += "<h1 class='alert'>Captain Announces</h1>"
|
||||
GLOB.news_network.SubmitArticle(text, "Captain's Announcement", "Station Announcements", null)
|
||||
|
||||
else
|
||||
announcement += "<h1 class='alert'>[command_name()] Update</h1>"
|
||||
if (title && length(title) > 0)
|
||||
announcement += "<br><h2 class='alert'>[html_encode(title)]</h2>"
|
||||
if(title == "")
|
||||
GLOB.news_network.SubmitArticle(text, "Central Command Update", "Station Announcements", null)
|
||||
else
|
||||
GLOB.news_network.SubmitArticle(title + "<br><br>" + text, "Central Command", "Station Announcements", null)
|
||||
|
||||
announcement += "<br><span class='alert'>[html_encode(text)]</span><br>"
|
||||
announcement += "<br>"
|
||||
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!isnewplayer(M) && !M.ear_deaf)
|
||||
to_chat(M, announcement)
|
||||
if(M.client.prefs.toggles & SOUND_ANNOUNCEMENTS)
|
||||
M << sound(sound)
|
||||
|
||||
/proc/print_command_report(text = "", title = null, announce=TRUE)
|
||||
if(!title)
|
||||
title = "Classified [command_name()] Update"
|
||||
|
||||
if(announce)
|
||||
priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", 'sound/AI/commandreport.ogg')
|
||||
|
||||
for(var/obj/machinery/computer/communications/C in GLOB.machines)
|
||||
if(!(C.stat & (BROKEN|NOPOWER)) && C.z == ZLEVEL_STATION)
|
||||
var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(C.loc)
|
||||
P.name = "paper - '[title]'"
|
||||
P.info = text
|
||||
C.messagetitle.Add("[title]")
|
||||
C.messagetext.Add(text)
|
||||
P.update_icon()
|
||||
|
||||
/proc/minor_announce(message, title = "Attention:", alert)
|
||||
if(!message)
|
||||
return
|
||||
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!isnewplayer(M) && !M.ear_deaf)
|
||||
to_chat(M, "<b><font size = 3><font color = red>[title]</font color><BR>[message]</font size></b><BR>")
|
||||
if(M.client.prefs.toggles & SOUND_ANNOUNCEMENTS)
|
||||
if(alert)
|
||||
M << sound('sound/misc/notice1.ogg')
|
||||
else
|
||||
M << sound('sound/misc/notice2.ogg')
|
||||
Reference in New Issue
Block a user