diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index daee66b1063..ae218f750ec 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -1,4 +1,3 @@ -<<<<<<< HEAD //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 /* @@ -1588,1588 +1587,3 @@ var/mob/dview/dview_mob = new // Third one is the text that will be clickable. /proc/href(href_src, list/href_params, href_text) return "[href_text]" -======= -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 - -/* - * A large number of misc global procs. - */ - -//Checks if all high bits in req_mask are set in bitfield -#define BIT_TEST_ALL(bitfield, req_mask) ((~(bitfield) & (req_mask)) == 0) - -//supposedly the fastest way to do this according to https://gist.github.com/Giacom/be635398926bb463b42a -#define RANGE_TURFS(RADIUS, CENTER) \ - block( \ - locate(max(CENTER.x-(RADIUS),1), max(CENTER.y-(RADIUS),1), CENTER.z), \ - locate(min(CENTER.x+(RADIUS),world.maxx), min(CENTER.y+(RADIUS),world.maxy), CENTER.z) \ - ) - -//Inverts the colour of an HTML string -/proc/invertHTML(HTMLstring) - - if (!( istext(HTMLstring) )) - CRASH("Given non-text argument!") - return - else - if (length(HTMLstring) != 7) - CRASH("Given non-HTML argument!") - return - var/textr = copytext(HTMLstring, 2, 4) - var/textg = copytext(HTMLstring, 4, 6) - var/textb = copytext(HTMLstring, 6, 8) - var/r = hex2num(textr) - var/g = hex2num(textg) - var/b = hex2num(textb) - textr = num2hex(255 - r) - textg = num2hex(255 - g) - textb = num2hex(255 - b) - if (length(textr) < 2) - textr = text("0[]", textr) - if (length(textg) < 2) - textr = text("0[]", textg) - if (length(textb) < 2) - textr = text("0[]", textb) - return text("#[][][]", textr, textg, textb) - return - -//Returns the middle-most value -/proc/dd_range(var/low, var/high, var/num) - return max(low,min(high,num)) - -//Returns whether or not A is the middle most value -/proc/InRange(var/A, var/lower, var/upper) - if(A < lower) return 0 - if(A > upper) return 0 - return 1 - - -/proc/Get_Angle(atom/movable/start,atom/movable/end)//For beams. - if(!start || !end) return 0 - var/dy - var/dx - dy=(32*end.y+end.pixel_y)-(32*start.y+start.pixel_y) - dx=(32*end.x+end.pixel_x)-(32*start.x+start.pixel_x) - if(!dy) - return (dx>=0)?90:270 - .=arctan(dx/dy) - if(dy<0) - .+=180 - else if(dx<0) - .+=360 - -//Returns location. Returns null if no location was found. -/proc/get_teleport_loc(turf/location,mob/target,distance = 1, density = 0, errorx = 0, errory = 0, eoffsetx = 0, eoffsety = 0) -/* -Location where the teleport begins, target that will teleport, distance to go, density checking 0/1(yes/no). -Random error in tile placement x, error in tile placement y, and block offset. -Block offset tells the proc how to place the box. Behind teleport location, relative to starting location, forward, etc. -Negative values for offset are accepted, think of it in relation to North, -x is west, -y is south. Error defaults to positive. -Turf and target are seperate in case you want to teleport some distance from a turf the target is not standing on or something. -*/ - - var/dirx = 0//Generic location finding variable. - var/diry = 0 - - var/xoffset = 0//Generic counter for offset location. - var/yoffset = 0 - - var/b1xerror = 0//Generic placing for point A in box. The lower left. - var/b1yerror = 0 - var/b2xerror = 0//Generic placing for point B in box. The upper right. - var/b2yerror = 0 - - errorx = abs(errorx)//Error should never be negative. - errory = abs(errory) - //var/errorxy = round((errorx+errory)/2)//Used for diagonal boxes. - - switch(target.dir)//This can be done through equations but switch is the simpler method. And works fast to boot. - //Directs on what values need modifying. - if(1)//North - diry+=distance - yoffset+=eoffsety - xoffset+=eoffsetx - b1xerror-=errorx - b1yerror-=errory - b2xerror+=errorx - b2yerror+=errory - if(2)//South - diry-=distance - yoffset-=eoffsety - xoffset+=eoffsetx - b1xerror-=errorx - b1yerror-=errory - b2xerror+=errorx - b2yerror+=errory - if(4)//East - dirx+=distance - yoffset+=eoffsetx//Flipped. - xoffset+=eoffsety - b1xerror-=errory//Flipped. - b1yerror-=errorx - b2xerror+=errory - b2yerror+=errorx - if(8)//West - dirx-=distance - yoffset-=eoffsetx//Flipped. - xoffset+=eoffsety - b1xerror-=errory//Flipped. - b1yerror-=errorx - b2xerror+=errory - b2yerror+=errorx - - var/turf/destination=locate(location.x+dirx,location.y+diry,location.z) - - if(destination)//If there is a destination. - if(errorx||errory)//If errorx or y were specified. - var/destination_list[] = list()//To add turfs to list. - //destination_list = new() - /*This will draw a block around the target turf, given what the error is. - Specifying the values above will basically draw a different sort of block. - If the values are the same, it will be a square. If they are different, it will be a rectengle. - In either case, it will center based on offset. Offset is position from center. - Offset always calculates in relation to direction faced. In other words, depending on the direction of the teleport, - the offset should remain positioned in relation to destination.*/ - - var/turf/center = locate((destination.x+xoffset),(destination.y+yoffset),location.z)//So now, find the new center. - - //Now to find a box from center location and make that our destination. - for(var/turf/T in block(locate(center.x+b1xerror,center.y+b1yerror,location.z), locate(center.x+b2xerror,center.y+b2yerror,location.z) )) - if(density&&(T.density||T.contains_dense_objects())) continue//If density was specified. - if(T.x>world.maxx || T.x<1) continue//Don't want them to teleport off the map. - if(T.y>world.maxy || T.y<1) continue - destination_list += T - if(destination_list.len) - destination = pick(destination_list) - else return - - else//Same deal here. - if(density&&(destination.density||destination.contains_dense_objects())) return - if(destination.x>world.maxx || destination.x<1) return - if(destination.y>world.maxy || destination.y<1) return - else return - - return destination - - - -/proc/LinkBlocked(turf/A, turf/B) - if(A == null || B == null) return 1 - var/adir = get_dir(A,B) - var/rdir = get_dir(B,A) - if((adir & (NORTH|SOUTH)) && (adir & (EAST|WEST))) // diagonal - var/iStep = get_step(A,adir&(NORTH|SOUTH)) - if(!LinkBlocked(A,iStep) && !LinkBlocked(iStep,B)) return 0 - - var/pStep = get_step(A,adir&(EAST|WEST)) - if(!LinkBlocked(A,pStep) && !LinkBlocked(pStep,B)) return 0 - return 1 - - if(DirBlocked(A,adir)) return 1 - if(DirBlocked(B,rdir)) return 1 - return 0 - - -/proc/DirBlocked(turf/loc,var/dir) - for(var/obj/structure/window/D in loc) - if(!D.density) continue - if(D.dir == SOUTHWEST) return 1 - if(D.dir == dir) return 1 - - for(var/obj/machinery/door/D in loc) - if(!D.density) continue - if(istype(D, /obj/machinery/door/window)) - if((dir & SOUTH) && (D.dir & (EAST|WEST))) return 1 - if((dir & EAST ) && (D.dir & (NORTH|SOUTH))) return 1 - else return 1 // it's a real, air blocking door - return 0 - -/proc/TurfBlockedNonWindow(turf/loc) - for(var/obj/O in loc) - if(O.density && !istype(O, /obj/structure/window)) - return 1 - return 0 - -/proc/sign(x) - return x!=0?x/abs(x):0 - -/proc/getline(atom/M,atom/N)//Ultra-Fast Bresenham Line-Drawing Algorithm - var/px=M.x //starting x - var/py=M.y - var/line[] = list(locate(px,py,M.z)) - var/dx=N.x-px //x distance - var/dy=N.y-py - var/dxabs=abs(dx)//Absolute value of x distance - var/dyabs=abs(dy) - var/sdx=sign(dx) //Sign of x distance (+ or -) - var/sdy=sign(dy) - var/x=dxabs>>1 //Counters for steps taken, setting to distance/2 - var/y=dyabs>>1 //Bit-shifting makes me l33t. It also makes getline() unnessecarrily fast. - var/j //Generic integer for counting - if(dxabs>=dyabs) //x distance is greater than y - for(j=0;j=dxabs) //Every dyabs steps, step once in y direction - y-=dxabs - py+=sdy - px+=sdx //Step on in x direction - line+=locate(px,py,M.z)//Add the turf to the list - else - for(j=0;j=dyabs) - x-=dyabs - px+=sdx - py+=sdy - line+=locate(px,py,M.z) - return line - -#define LOCATE_COORDS(X, Y, Z) locate(between(1, X, world.maxx), between(1, Y, world.maxy), Z) -/proc/getcircle(turf/center, var/radius) //Uses a fast Bresenham rasterization algorithm to return the turfs in a thin circle. - if(!radius) return list(center) - - var/x = 0 - var/y = radius - var/p = 3 - 2 * radius - - . = list() - while(y >= x) // only formulate 1/8 of circle - - . += LOCATE_COORDS(center.x - x, center.y - y, center.z) //upper left left - . += LOCATE_COORDS(center.x - y, center.y - x, center.z) //upper upper left - . += LOCATE_COORDS(center.x + y, center.y - x, center.z) //upper upper right - . += LOCATE_COORDS(center.x + x, center.y - y, center.z) //upper right right - . += LOCATE_COORDS(center.x - x, center.y + y, center.z) //lower left left - . += LOCATE_COORDS(center.x - y, center.y + x, center.z) //lower lower left - . += LOCATE_COORDS(center.x + y, center.y + x, center.z) //lower lower right - . += LOCATE_COORDS(center.x + x, center.y + y, center.z) //lower right right - - if(p < 0) - p += 4*x++ + 6; - else - p += 4*(x++ - y--) + 10; - -#undef LOCATE_COORDS - -//Returns whether or not a player is a guest using their ckey as an input -/proc/IsGuestKey(key) - if (findtext(key, "Guest-", 1, 7) != 1) //was findtextEx - return 0 - - var/i = 7, ch, len = length(key) - - if(copytext(key, 7, 8) == "W") //webclient - i++ - - for (, i <= len, ++i) - ch = text2ascii(key, i) - if (ch < 48 || ch > 57) - return 0 - return 1 - -//Ensure the frequency is within bounds of what it should be sending/recieving at -/proc/sanitize_frequency(var/f, var/low = PUBLIC_LOW_FREQ, var/high = PUBLIC_HIGH_FREQ) - f = round(f) - f = max(low, f) - f = min(high, f) - if ((f % 2) == 0) //Ensure the last digit is an odd number - f += 1 - return f - -//Turns 1479 into 147.9 -/proc/format_frequency(var/f) - return "[round(f / 10)].[f % 10]" - - - -//This will update a mob's name, real_name, mind.name, data_core records, pda and id -//Calling this proc without an oldname will only update the mob and skip updating the pda, id and records ~Carn -/mob/proc/fully_replace_character_name(var/oldname,var/newname) - if(!newname) return 0 - real_name = newname - name = newname - if(mind) - mind.name = newname - if(dna) - dna.real_name = real_name - - if(oldname) - //update the datacore records! This is goig to be a bit costly. - for(var/list/L in list(data_core.general,data_core.medical,data_core.security,data_core.locked)) - for(var/datum/data/record/R in L) - if(R.fields["name"] == oldname) - R.fields["name"] = newname - break - - //update our pda and id if we have them on our person - var/list/searching = GetAllContents(searchDepth = 3) - var/search_id = 1 - var/search_pda = 1 - - for(var/A in searching) - if( search_id && istype(A,/obj/item/weapon/card/id) ) - var/obj/item/weapon/card/id/ID = A - if(ID.registered_name == oldname) - ID.registered_name = newname - ID.name = "[newname]'s ID Card ([ID.assignment])" - if(!search_pda) break - search_id = 0 - - else if( search_pda && istype(A,/obj/item/device/pda) ) - var/obj/item/device/pda/PDA = A - if(PDA.owner == oldname) - PDA.owner = newname - PDA.name = "PDA-[newname] ([PDA.ownjob])" - if(!search_id) break - search_pda = 0 - return 1 - - - -//Generalised helper proc for letting mobs rename themselves. Used to be clname() and ainame() -//Last modified by Carn -/mob/proc/rename_self(var/role, var/allow_numbers=0) - spawn(0) - var/oldname = real_name - - var/time_passed = world.time - var/newname - - for(var/i=1,i<=3,i++) //we get 3 attempts to pick a suitable name. - newname = input(src,"You are \a [role]. Would you like to change your name to something else?", "Name change",oldname) as text - if((world.time-time_passed)>3000) - return //took too long - newname = sanitizeName(newname, ,allow_numbers) //returns null if the name doesn't meet some basic requirements. Tidies up a few other things like bad-characters. - - for(var/mob/living/M in player_list) - if(M == src) - continue - if(!newname || M.real_name == newname) - newname = null - break - if(newname) - break //That's a suitable name! - to_chat(src, "Sorry, that [role]-name wasn't appropriate, please try another. It's possibly too long/short, has bad characters or is already taken.") - - if(!newname) //we'll stick with the oldname then - return - - if(cmptext("ai",role)) - if(isAI(src)) - var/mob/living/silicon/ai/A = src - oldname = null//don't bother with the records update crap - //to_world("[newname] is the AI!") - //world << sound('sound/AI/newAI.ogg') - // Set eyeobj name - A.SetName(newname) - - - fully_replace_character_name(oldname,newname) - - - -//Picks a string of symbols to display as the law number for hacked or ion laws -/proc/ionnum() - return "[pick("1","2","3","4","5","6","7","8","9","0")][pick("!","@","#","$","%","^","&","*")][pick("!","@","#","$","%","^","&","*")][pick("!","@","#","$","%","^","&","*")]" - -//When an AI is activated, it can choose from a list of non-slaved borgs to have as a slave. -/proc/freeborg() - var/select = null - var/list/borgs = list() - for (var/mob/living/silicon/robot/A in player_list) - if (A.stat == 2 || A.connected_ai || A.scrambledcodes || istype(A,/mob/living/silicon/robot/drone)) - continue - var/name = "[A.real_name] ([A.modtype] [A.braintype])" - borgs[name] = A - - if (borgs.len) - select = input("Unshackled borg signals detected:", "Borg selection", null, null) as null|anything in borgs - return borgs[select] - -//When a borg is activated, it can choose which AI it wants to be slaved to -/proc/active_ais() - . = list() - for(var/mob/living/silicon/ai/A in living_mob_list) - if(A.stat == DEAD) - continue - if(A.control_disabled == 1) - continue - . += A - return . - -//Find an active ai with the least borgs. VERBOSE PROCNAME HUH! -/proc/select_active_ai_with_fewest_borgs() - var/mob/living/silicon/ai/selected - var/list/active = active_ais() - for(var/mob/living/silicon/ai/A in active) - if(!selected || (selected.connected_robots.len > A.connected_robots.len)) - selected = A - - return selected - -/proc/select_active_ai(var/mob/user) - var/list/ais = active_ais() - if(ais.len) - if(user) . = input(usr,"AI signals detected:", "AI selection") in ais - else . = pick(ais) - return . - -/proc/get_sorted_mobs() - var/list/old_list = getmobs() - var/list/AI_list = list() - var/list/Dead_list = list() - var/list/keyclient_list = list() - var/list/key_list = list() - var/list/logged_list = list() - for(var/named in old_list) - var/mob/M = old_list[named] - if(issilicon(M)) - AI_list |= M - else if(isobserver(M) || M.stat == 2) - Dead_list |= M - else if(M.key && M.client) - keyclient_list |= M - else if(M.key) - key_list |= M - else - logged_list |= M - old_list.Remove(named) - var/list/new_list = list() - new_list += AI_list - new_list += keyclient_list - new_list += key_list - new_list += logged_list - new_list += Dead_list - return new_list - -//Returns a list of all mobs with their name -/proc/getmobs() - - var/list/mobs = sortmobs() - var/list/names = list() - var/list/creatures = list() - var/list/namecounts = list() - for(var/mob/M in mobs) - var/name = M.name - if (name in names) - namecounts[name]++ - name = "[name] ([namecounts[name]])" - else - names.Add(name) - namecounts[name] = 1 - if (M.real_name && M.real_name != M.name) - name += " \[[M.real_name]\]" - if (M.stat == 2) - if(istype(M, /mob/observer/dead/)) - name += " \[ghost\]" - else - name += " \[dead\]" - creatures[name] = M - - return creatures - -//Orders mobs by type then by name -/proc/sortmobs() - var/list/moblist = list() - var/list/sortmob = sortAtom(mob_list) - for(var/mob/observer/eye/M in sortmob) - moblist.Add(M) - for(var/mob/observer/blob/M in sortmob) - moblist.Add(M) - for(var/mob/living/silicon/ai/M in sortmob) - moblist.Add(M) - for(var/mob/living/silicon/pai/M in sortmob) - moblist.Add(M) - for(var/mob/living/silicon/robot/M in sortmob) - moblist.Add(M) - for(var/mob/living/carbon/human/M in sortmob) - moblist.Add(M) - for(var/mob/living/carbon/brain/M in sortmob) - moblist.Add(M) - for(var/mob/living/carbon/alien/M in sortmob) - moblist.Add(M) - for(var/mob/observer/dead/M in sortmob) - moblist.Add(M) - for(var/mob/new_player/M in sortmob) - moblist.Add(M) - for(var/mob/living/simple_mob/M in sortmob) - moblist.Add(M) -// for(var/mob/living/silicon/hivebot/M in sortmob) -// mob_list.Add(M) -// for(var/mob/living/silicon/hive_mainframe/M in sortmob) -// mob_list.Add(M) - return moblist - -// Format a power value in W, kW, MW, or GW. -/proc/DisplayPower(powerused) - if(powerused < 1000) //Less than a kW - return "[powerused] W" - else if(powerused < 1000000) //Less than a MW - return "[round((powerused * 0.001),0.01)] kW" - else if(powerused < 1000000000) //Less than a GW - return "[round((powerused * 0.000001),0.001)] MW" - return "[round((powerused * 0.000000001),0.0001)] GW" - -/proc/get_mob_by_ckey(key) - if(!key) - return - var/list/mobs = sortmobs() - for(var/mob/M in mobs) - if(M.ckey == key) - return M - -//Forces a variable to be posative -/proc/modulus(var/M) - if(M >= 0) - return M - if(M < 0) - return -M - -// returns the turf located at the map edge in the specified direction relative to A -// used for mass driver -/proc/get_edge_target_turf(var/atom/A, var/direction) - - var/turf/target = locate(A.x, A.y, A.z) - if(!A || !target) - return 0 - //since NORTHEAST == NORTH & EAST, etc, doing it this way allows for diagonal mass drivers in the future - //and isn't really any more complicated - - // Note diagonal directions won't usually be accurate - if(direction & NORTH) - target = locate(target.x, world.maxy, target.z) - if(direction & SOUTH) - target = locate(target.x, 1, target.z) - if(direction & EAST) - target = locate(world.maxx, target.y, target.z) - if(direction & WEST) - target = locate(1, target.y, target.z) - - return target - -// returns turf relative to A in given direction at set range -// result is bounded to map size -// note range is non-pythagorean -// used for disposal system -/proc/get_ranged_target_turf(var/atom/A, var/direction, var/range) - - var/x = A.x - var/y = A.y - if(direction & NORTH) - y = min(world.maxy, y + range) - if(direction & SOUTH) - y = max(1, y - range) - if(direction & EAST) - x = min(world.maxx, x + range) - if(direction & WEST) - x = max(1, x - range) - - return locate(x,y,A.z) - - -// returns turf relative to A offset in dx and dy tiles -// bound to map limits -/proc/get_offset_target_turf(var/atom/A, var/dx, var/dy) - var/x = min(world.maxx, max(1, A.x + dx)) - var/y = min(world.maxy, max(1, A.y + dy)) - return locate(x,y,A.z) - -//Makes sure MIDDLE is between LOW and HIGH. If not, it adjusts it. Returns the adjusted value. -/proc/between(var/low, var/middle, var/high) - return max(min(middle, high), low) - -//returns random gauss number -proc/GaussRand(var/sigma) - var/x,y,rsq - do - x=2*rand()-1 - y=2*rand()-1 - rsq=x*x+y*y - while(rsq>1 || !rsq) - return sigma*y*sqrt(-2*log(rsq)/rsq) - -//returns random gauss number, rounded to 'roundto' -proc/GaussRandRound(var/sigma,var/roundto) - return round(GaussRand(sigma),roundto) - -//Will return the contents of an atom recursivly to a depth of 'searchDepth' -/atom/proc/GetAllContents(searchDepth = 5) - var/list/toReturn = list() - - for(var/atom/part in contents) - toReturn += part - if(part.contents.len && searchDepth) - toReturn += part.GetAllContents(searchDepth - 1) - - return toReturn - -//Step-towards method of determining whether one atom can see another. Similar to viewers() -/proc/can_see(var/atom/source, var/atom/target, var/length=5) // I couldn't be arsed to do actual raycasting :I This is horribly inaccurate. - var/turf/current = get_turf(source) - var/turf/target_turf = get_turf(target) - var/steps = 0 - - if(!current || !target_turf) - return 0 - - while(current != target_turf) - if(steps > length) return 0 - if(current.opacity) return 0 - for(var/atom/A in current) - if(A.opacity) return 0 - current = get_step_towards(current, target_turf) - steps++ - - return 1 - -/proc/is_blocked_turf(var/turf/T) - var/cant_pass = 0 - if(T.density) cant_pass = 1 - for(var/atom/A in T) - if(A.density)//&&A.anchored - cant_pass = 1 - return cant_pass - -/proc/get_step_towards2(var/atom/ref , var/atom/trg) - var/base_dir = get_dir(ref, get_step_towards(ref,trg)) - var/turf/temp = get_step_towards(ref,trg) - - if(is_blocked_turf(temp)) - var/dir_alt1 = turn(base_dir, 90) - var/dir_alt2 = turn(base_dir, -90) - var/turf/turf_last1 = temp - var/turf/turf_last2 = temp - var/free_tile = null - var/breakpoint = 0 - - while(!free_tile && breakpoint < 10) - if(!is_blocked_turf(turf_last1)) - free_tile = turf_last1 - break - if(!is_blocked_turf(turf_last2)) - free_tile = turf_last2 - break - turf_last1 = get_step(turf_last1,dir_alt1) - turf_last2 = get_step(turf_last2,dir_alt2) - breakpoint++ - - if(!free_tile) return get_step(ref, base_dir) - else return get_step_towards(ref,free_tile) - - else return get_step(ref, base_dir) - -//Takes: Anything that could possibly have variables and a varname to check. -//Returns: 1 if found, 0 if not. -/proc/hasvar(var/datum/A, var/varname) - if(A.vars.Find(lowertext(varname))) return 1 - else return 0 - -//Returns: all the areas in the world -/proc/return_areas() - var/list/area/areas = list() - for(var/area/A in all_areas) - areas += A - return areas - -//Returns: all the areas in the world, sorted. -/proc/return_sorted_areas() - return sortAtom(return_areas()) - -//Takes: Area type as text string or as typepath OR an instance of the area. -//Returns: A list of all areas of that type in the world. -/proc/get_areas(var/areatype) - if(!areatype) return null - if(istext(areatype)) areatype = text2path(areatype) - if(isarea(areatype)) - var/area/areatemp = areatype - areatype = areatemp.type - - var/list/areas = new/list() - for(var/area/N in all_areas) - if(istype(N, areatype)) areas += N - return areas - -//Takes: Area type as text string or as typepath OR an instance of the area. -//Returns: A list of all turfs in areas of that type of that type in the world. -/proc/get_area_turfs(var/areatype) - if(!areatype) return null - if(istext(areatype)) areatype = text2path(areatype) - if(isarea(areatype)) - var/area/areatemp = areatype - areatype = areatemp.type - - var/list/turfs = new/list() - for(var/area/N in all_areas) - if(istype(N, areatype)) - for(var/turf/T in N) turfs += T - return turfs - -//Takes: Area type as text string or as typepath OR an instance of the area. -//Returns: A list of all atoms (objs, turfs, mobs) in areas of that type of that type in the world. -/proc/get_area_all_atoms(var/areatype) - if(!areatype) return null - if(istext(areatype)) areatype = text2path(areatype) - if(isarea(areatype)) - var/area/areatemp = areatype - areatype = areatemp.type - - var/list/atoms = new/list() - for(var/area/N in all_areas) - if(istype(N, areatype)) - for(var/atom/A in N) - atoms += A - return atoms - -/datum/coords //Simple datum for storing coordinates. - var/x_pos = null - var/y_pos = null - var/z_pos = null - -/area/proc/move_contents_to(var/area/A, var/turftoleave=null, var/direction = null) - //Takes: Area. Optional: turf type to leave behind. - //Returns: Nothing. - //Notes: Attempts to move the contents of one area to another area. - // Movement based on lower left corner. Tiles that do not fit - // into the new area will not be moved. - - if(!A || !src) return 0 - - var/list/turfs_src = get_area_turfs(src.type) - var/list/turfs_trg = get_area_turfs(A.type) - - var/src_min_x = 0 - var/src_min_y = 0 - for (var/turf/T in turfs_src) - if(T.x < src_min_x || !src_min_x) src_min_x = T.x - if(T.y < src_min_y || !src_min_y) src_min_y = T.y - - var/trg_min_x = 0 - var/trg_min_y = 0 - for (var/turf/T in turfs_trg) - if(T.x < trg_min_x || !trg_min_x) trg_min_x = T.x - if(T.y < trg_min_y || !trg_min_y) trg_min_y = T.y - - var/list/refined_src = new/list() - for(var/turf/T in turfs_src) - refined_src += T - refined_src[T] = new/datum/coords - var/datum/coords/C = refined_src[T] - C.x_pos = (T.x - src_min_x) - C.y_pos = (T.y - src_min_y) - - var/list/refined_trg = new/list() - for(var/turf/T in turfs_trg) - refined_trg += T - refined_trg[T] = new/datum/coords - var/datum/coords/C = refined_trg[T] - C.x_pos = (T.x - trg_min_x) - C.y_pos = (T.y - trg_min_y) - - moving: - for (var/turf/T in refined_src) - var/datum/coords/C_src = refined_src[T] - for (var/turf/B in refined_trg) - var/datum/coords/C_trg = refined_trg[B] - if(C_src.x_pos == C_trg.x_pos && C_src.y_pos == C_trg.y_pos) - - //You can stay, though. - if(istype(T,/turf/space)) - refined_src -= T - refined_trg -= B - continue moving - - var/turf/X //New Destination Turf - - //Are we doing shuttlework? Just to save another type check later. - var/shuttlework = 0 - - //Shuttle turfs handle their own fancy moving. - if(istype(T,/turf/simulated/shuttle)) - shuttlework = 1 - var/turf/simulated/shuttle/SS = T - if(!SS.landed_holder) SS.landed_holder = new(turf = SS) - X = SS.landed_holder.land_on(B) - - //Generic non-shuttle turf move. - else - var/old_dir1 = T.dir - var/old_icon_state1 = T.icon_state - var/old_icon1 = T.icon - var/old_underlays = T.underlays.Copy() - var/old_decals = T.decals ? T.decals.Copy() : null - - X = B.ChangeTurf(T.type) - X.set_dir(old_dir1) - X.icon_state = old_icon_state1 - X.icon = old_icon1 - X.copy_overlays(T, TRUE) - X.underlays = old_underlays - X.decals = old_decals - - //Move the air from source to dest - var/turf/simulated/ST = T - if(istype(ST) && ST.zone) - var/turf/simulated/SX = X - if(!SX.air) - SX.make_air() - SX.air.copy_from(ST.zone.air) - ST.zone.remove(ST) - - var/z_level_change = FALSE - if(T.z != X.z) - z_level_change = TRUE - - //Move the objects. Not forceMove because the object isn't "moving" really, it's supposed to be on the "same" turf. - for(var/obj/O in T) - O.loc = X - O.update_light() - if(z_level_change) // The objects still need to know if their z-level changed. - O.onTransitZ(T.z, X.z) - - //Move the mobs unless it's an AI eye or other eye type. - for(var/mob/M in T) - if(istype(M, /mob/observer/eye)) continue // If we need to check for more mobs, I'll add a variable - M.loc = X - - if(z_level_change) // Same goes for mobs. - M.onTransitZ(T.z, X.z) - - if(istype(M, /mob/living)) - var/mob/living/LM = M - LM.check_shadow() // Need to check their Z-shadow, which is normally done in forceMove(). - - if(shuttlework) - var/turf/simulated/shuttle/SS = T - SS.landed_holder.leave_turf() - else if(turftoleave) - T.ChangeTurf(turftoleave) - else - T.ChangeTurf(get_base_turf_by_area(T)) - - refined_src -= T - refined_trg -= B - continue moving - -proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0) - if(!original) - return null - - var/obj/O = null - - if(sameloc) - O=new original.type(original.loc) - else - O=new original.type(locate(0,0,0)) - - if(perfectcopy) - if((O) && (original)) - for(var/V in original.vars) - if(!(V in list("type","loc","locs","vars", "parent", "parent_type","verbs","ckey","key"))) - O.vars[V] = original.vars[V] - return O - - -/area/proc/copy_contents_to(var/area/A , var/platingRequired = 0 ) - //Takes: Area. Optional: If it should copy to areas that don't have plating - //Returns: Nothing. - //Notes: Attempts to move the contents of one area to another area. - // Movement based on lower left corner. Tiles that do not fit - // into the new area will not be moved. - - // Does *not* affect gases etc; copied turfs will be changed via ChangeTurf, and the dir, icon, and icon_state copied. All other vars will remain default. - - if(!A || !src) return 0 - - var/list/turfs_src = get_area_turfs(src.type) - var/list/turfs_trg = get_area_turfs(A.type) - - var/src_min_x = 0 - var/src_min_y = 0 - for (var/turf/T in turfs_src) - if(T.x < src_min_x || !src_min_x) src_min_x = T.x - if(T.y < src_min_y || !src_min_y) src_min_y = T.y - - var/trg_min_x = 0 - var/trg_min_y = 0 - for (var/turf/T in turfs_trg) - if(T.x < trg_min_x || !trg_min_x) trg_min_x = T.x - if(T.y < trg_min_y || !trg_min_y) trg_min_y = T.y - - var/list/refined_src = new/list() - for(var/turf/T in turfs_src) - refined_src += T - refined_src[T] = new/datum/coords - var/datum/coords/C = refined_src[T] - C.x_pos = (T.x - src_min_x) - C.y_pos = (T.y - src_min_y) - - var/list/refined_trg = new/list() - for(var/turf/T in turfs_trg) - refined_trg += T - refined_trg[T] = new/datum/coords - var/datum/coords/C = refined_trg[T] - C.x_pos = (T.x - trg_min_x) - C.y_pos = (T.y - trg_min_y) - - var/list/toupdate = new/list() - - var/copiedobjs = list() - - - moving: - for (var/turf/T in refined_src) - var/datum/coords/C_src = refined_src[T] - for (var/turf/B in refined_trg) - var/datum/coords/C_trg = refined_trg[B] - if(C_src.x_pos == C_trg.x_pos && C_src.y_pos == C_trg.y_pos) - - var/old_dir1 = T.dir - var/old_icon_state1 = T.icon_state - var/old_icon1 = T.icon - var/old_overlays = T.overlays.Copy() - var/old_underlays = T.underlays.Copy() - - if(platingRequired) - if(istype(B, get_base_turf_by_area(B))) - continue moving - - var/turf/X = B - X.ChangeTurf(T.type) - X.set_dir(old_dir1) - X.icon_state = old_icon_state1 - X.icon = old_icon1 //Shuttle floors are in shuttle.dmi while the defaults are floors.dmi - X.overlays = old_overlays - X.underlays = old_underlays - - var/list/objs = new/list() - var/list/newobjs = new/list() - var/list/mobs = new/list() - var/list/newmobs = new/list() - - for(var/obj/O in T) - - if(!istype(O,/obj)) - continue - - objs += O - - - for(var/obj/O in objs) - newobjs += DuplicateObject(O , 1) - - - for(var/obj/O in newobjs) - O.loc = X - - for(var/mob/M in T) - - if(!istype(M,/mob) || istype(M, /mob/observer/eye)) continue // If we need to check for more mobs, I'll add a variable - mobs += M - - for(var/mob/M in mobs) - newmobs += DuplicateObject(M , 1) - - for(var/mob/M in newmobs) - M.loc = X - - copiedobjs += newobjs - copiedobjs += newmobs - -// var/area/AR = X.loc - -// if(AR.dynamic_lighting) -// X.opacity = !X.opacity -// X.sd_SetOpacity(!X.opacity) //TODO: rewrite this code so it's not messed by lighting ~Carn - - toupdate += X - - refined_src -= T - refined_trg -= B - continue moving - - - - - if(toupdate.len) - for(var/turf/simulated/T1 in toupdate) - air_master.mark_for_update(T1) - - return copiedobjs - - - -proc/get_cardinal_dir(atom/A, atom/B) - var/dx = abs(B.x - A.x) - var/dy = abs(B.y - A.y) - return get_dir(A, B) & (rand() * (dx+dy) < dy ? 3 : 12) - -//chances are 1:value. anyprob(1) will always return true -proc/anyprob(value) - return (rand(1,value)==value) - -proc/view_or_range(distance = world.view , center = usr , type) - switch(type) - if("view") - . = view(distance,center) - if("range") - . = range(distance,center) - return - -proc/oview_or_orange(distance = world.view , center = usr , type) - switch(type) - if("view") - . = oview(distance,center) - if("range") - . = orange(distance,center) - return - -proc/get_mob_with_client_list() - var/list/mobs = list() - for(var/mob/M in mob_list) - if (M.client) - mobs += M - return mobs - - -/proc/parse_zone(zone) - if(zone == "r_hand") return "right hand" - else if (zone == "l_hand") return "left hand" - else if (zone == "l_arm") return "left arm" - else if (zone == "r_arm") return "right arm" - else if (zone == "l_leg") return "left leg" - else if (zone == "r_leg") return "right leg" - else if (zone == "l_foot") return "left foot" - else if (zone == "r_foot") return "right foot" - else if (zone == "l_hand") return "left hand" - else if (zone == "r_hand") return "right hand" - else if (zone == "l_foot") return "left foot" - else if (zone == "r_foot") return "right foot" - else return zone - -/proc/get(atom/loc, type) - while(loc) - if(istype(loc, type)) - return loc - loc = loc.loc - return null - -/proc/get_turf_or_move(turf/location) - return get_turf(location) - - -//Quick type checks for some tools -var/global/list/common_tools = list( -/obj/item/stack/cable_coil, -/obj/item/weapon/tool/wrench, -/obj/item/weapon/weldingtool, -/obj/item/weapon/tool/screwdriver, -/obj/item/weapon/tool/wirecutters, -/obj/item/device/multitool, -/obj/item/weapon/tool/crowbar) - -/proc/istool(O) - if(O && is_type_in_list(O, common_tools)) - return 1 - return 0 - - -/proc/is_wire_tool(obj/item/I) - if(istype(I, /obj/item/device/multitool) || I.is_wirecutter()) - return TRUE - if(istype(I, /obj/item/device/assembly/signaler)) - return TRUE - return - -proc/is_hot(obj/item/W as obj) - switch(W.type) - if(/obj/item/weapon/weldingtool) - var/obj/item/weapon/weldingtool/WT = W - if(WT.isOn()) - return 3800 - else - return 0 - if(/obj/item/weapon/flame/lighter) - if(W:lit) - return 1500 - else - return 0 - if(/obj/item/weapon/flame/match) - if(W:lit) - return 1000 - else - return 0 - if(/obj/item/clothing/mask/smokable/cigarette) - if(W:lit) - return 1000 - else - return 0 - if(/obj/item/weapon/pickaxe/plasmacutter) - return 3800 - if(/obj/item/weapon/melee/energy) - return 3500 - else - return 0 - - return 0 - -//Whether or not the given item counts as sharp in terms of dealing damage -/proc/is_sharp(obj/O as obj) - if(!O) - return FALSE - if(O.sharp) - return TRUE - if(O.edge) - return TRUE - return FALSE - -//Whether or not the given item counts as cutting with an edge in terms of removing limbs -/proc/has_edge(obj/O as obj) - if(!O) - return FALSE - if(O.edge) - return TRUE - return FALSE - -//Returns 1 if the given item is capable of popping things like balloons, inflatable barriers, or cutting police tape. -/proc/can_puncture(obj/item/W as obj) // For the record, WHAT THE HELL IS THIS METHOD OF DOING IT? - if(!W) - return FALSE - if(W.sharp) - return TRUE - return ( \ - W.is_screwdriver() || \ - istype(W, /obj/item/weapon/pen) || \ - istype(W, /obj/item/weapon/weldingtool) || \ - istype(W, /obj/item/weapon/flame/lighter/zippo) || \ - istype(W, /obj/item/weapon/flame/match) || \ - istype(W, /obj/item/clothing/mask/smokable/cigarette) || \ - istype(W, /obj/item/weapon/shovel) \ - ) - -/proc/is_surgery_tool(obj/item/W as obj) - return ( \ - istype(W, /obj/item/weapon/surgical/scalpel) || \ - istype(W, /obj/item/weapon/surgical/hemostat) || \ - istype(W, /obj/item/weapon/surgical/retractor) || \ - istype(W, /obj/item/weapon/surgical/cautery) || \ - istype(W, /obj/item/weapon/surgical/bonegel) || \ - istype(W, /obj/item/weapon/surgical/bonesetter) - ) - -// check if mob is lying down on something we can operate him on. -// The RNG with table/rollerbeds comes into play in do_surgery() so that fail_step() can be used instead. -/proc/can_operate(mob/living/carbon/M) - return M.lying - -// Returns an instance of a valid surgery surface. -/mob/living/proc/get_surgery_surface() - if(!lying) - return null // Not lying down means no surface. - var/obj/surface = null - for(var/obj/O in loc) // Looks for the best surface. - if(O.surgery_odds) - if(!surface || surface.surgery_odds < O) - surface = O - if(surface) - return surface - -/proc/reverse_direction(var/dir) - switch(dir) - if(NORTH) - return SOUTH - if(NORTHEAST) - return SOUTHWEST - if(EAST) - return WEST - if(SOUTHEAST) - return NORTHWEST - if(SOUTH) - return NORTH - if(SOUTHWEST) - return NORTHEAST - if(WEST) - return EAST - if(NORTHWEST) - return SOUTHEAST - -/* -Checks if that loc and dir has a item on the wall -TODO - Fix this ancient list of wall items. Preferably make it dynamically populated. ~Leshana -*/ -var/list/WALLITEMS = list( - /obj/machinery/power/apc, /obj/machinery/alarm, /obj/item/device/radio/intercom, /obj/structure/frame, - /obj/structure/extinguisher_cabinet, /obj/structure/reagent_dispensers/peppertank, - /obj/machinery/status_display, /obj/machinery/requests_console, /obj/machinery/light_switch, /obj/structure/sign, - /obj/machinery/newscaster, /obj/machinery/firealarm, /obj/structure/noticeboard, /obj/machinery/button/remote, - /obj/machinery/computer/security/telescreen, /obj/machinery/embedded_controller/radio, - /obj/item/weapon/storage/secure/safe, /obj/machinery/door_timer, /obj/machinery/flasher, /obj/machinery/keycard_auth, - /obj/structure/mirror, /obj/structure/fireaxecabinet, /obj/machinery/computer/security/telescreen/entertainment - ) -/proc/gotwallitem(loc, dir) - for(var/obj/O in loc) - for(var/item in WALLITEMS) - if(istype(O, item)) - //Direction works sometimes - if(O.dir == dir) - return 1 - - //Some stuff doesn't use dir properly, so we need to check pixel instead - switch(dir) - if(SOUTH) - if(O.pixel_y > 10) - return 1 - if(NORTH) - if(O.pixel_y < -10) - return 1 - if(WEST) - if(O.pixel_x > 10) - return 1 - if(EAST) - if(O.pixel_x < -10) - return 1 - - - //Some stuff is placed directly on the wallturf (signs) - for(var/obj/O in get_step(loc, dir)) - for(var/item in WALLITEMS) - if(istype(O, item)) - if(O.pixel_x == 0 && O.pixel_y == 0) - return 1 - return 0 - -/proc/format_text(text) - return replacetext(replacetext(text,"\proper ",""),"\improper ","") - -/proc/topic_link(var/datum/D, var/arglist, var/content) - if(istype(arglist,/list)) - arglist = list2params(arglist) - return "[content]" - -/proc/get_random_colour(var/simple, var/lower=0, var/upper=255) - var/colour - if(simple) - colour = pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF")) - else - for(var/i=1;i<=3;i++) - var/temp_col = "[num2hex(rand(lower,upper))]" - if(length(temp_col )<2) - temp_col = "0[temp_col]" - colour += temp_col - return colour - -var/mob/dview/dview_mob = new - -//Version of view() which ignores darkness, because BYOND doesn't have it. -/proc/dview(var/range = world.view, var/center, var/invis_flags = 0) - if(!center) - return - - dview_mob.loc = center - - dview_mob.see_invisible = invis_flags - - . = view(range, dview_mob) - dview_mob.loc = null - -/mob/dview - invisibility = 101 - density = 0 - - anchored = 1 - simulated = 0 - - see_in_dark = 1e6 - -/atom/proc/get_light_and_color(var/atom/origin) - if(origin) - color = origin.color - set_light(origin.light_range, origin.light_power, origin.light_color) - -/mob/dview/New() - ..() - // We don't want to be in any mob lists; we're a dummy not a mob. - mob_list -= src - if(stat == DEAD) - dead_mob_list -= src - else - living_mob_list -= src - -/mob/dview/Destroy(var/force) - crash_with("Attempt to delete the dview_mob: [log_info_line(src)]") - if (!force) - return QDEL_HINT_LETMELIVE - global.dview_mob = new - return ..() - -// call to generate a stack trace and print to runtime logs -/proc/crash_with(msg) - CRASH(msg) - -/proc/screen_loc2turf(scr_loc, turf/origin) - var/tX = splittext(scr_loc, ",") - var/tY = splittext(tX[2], ":") - var/tZ = origin.z - tY = tY[1] - tX = splittext(tX[1], ":") - tX = tX[1] - tX = max(1, min(world.maxx, origin.x + (text2num(tX) - (world.view + 1)))) - tY = max(1, min(world.maxy, origin.y + (text2num(tY) - (world.view + 1)))) - return locate(tX, tY, tZ) - -// Displays something as commonly used (non-submultiples) SI units. -/proc/format_SI(var/number, var/symbol) - switch(round(abs(number))) - if(0 to 1000-1) - return "[number] [symbol]" - if(1e3 to 1e6-1) - return "[round(number / 1000, 0.1)] k[symbol]" // kilo - if(1e6 to 1e9-1) - return "[round(number / 1e6, 0.1)] M[symbol]" // mega - if(1e9 to 1e12-1) // Probably not needed but why not be complete? - return "[round(number / 1e9, 0.1)] G[symbol]" // giga - if(1e12 to 1e15-1) - return "[round(number / 1e12, 0.1)] T[symbol]" // tera - - - -//ultra range (no limitations on distance, faster than range for distances > 8); including areas drastically decreases performance -/proc/urange(dist=0, atom/center=usr, orange=0, areas=0) - if(!dist) - if(!orange) - return list(center) - else - return list() - - var/list/turfs = RANGE_TURFS(dist, center) - if(orange) - turfs -= get_turf(center) - . = list() - for(var/V in turfs) - var/turf/T = V - . += T - . += T.contents - if(areas) - . |= T.loc - -#define NOT_FLAG(flag) (!(flag & use_flags)) -#define HAS_FLAG(flag) (flag & use_flags) - -// Checks if user can use this object. Set use_flags to customize what checks are done. -// Returns 0 if they can use it, a value representing why they can't if not. -// Flags are in `code/__defines/misc.dm` -/atom/proc/use_check(mob/user, use_flags = 0, show_messages = FALSE) - . = 0 - if (NOT_FLAG(USE_ALLOW_NONLIVING) && !isliving(user)) - // No message for ghosts. - return USE_FAIL_NONLIVING - - if (NOT_FLAG(USE_ALLOW_NON_ADJACENT) && !Adjacent(user)) - if (show_messages) - to_chat(user, span("notice","You're too far away from [src] to do that.")) - return USE_FAIL_NON_ADJACENT - - if (NOT_FLAG(USE_ALLOW_DEAD) && user.stat == DEAD) - if (show_messages) - to_chat(user, span("notice","You can't do that when you're dead.")) - return USE_FAIL_DEAD - - if (NOT_FLAG(USE_ALLOW_INCAPACITATED) && (user.incapacitated())) - if (show_messages) - to_chat(user, span("notice","You cannot do that in your current state.")) - return USE_FAIL_INCAPACITATED - - if (NOT_FLAG(USE_ALLOW_NON_ADV_TOOL_USR) && !user.IsAdvancedToolUser()) - if (show_messages) - to_chat(user, span("notice","You don't know how to operate [src].")) - return USE_FAIL_NON_ADV_TOOL_USR - - if (HAS_FLAG(USE_DISALLOW_SILICONS) && issilicon(user)) - if (show_messages) - to_chat(user, span("notice","You need hands for that.")) - return USE_FAIL_IS_SILICON - - if (HAS_FLAG(USE_FORCE_SRC_IN_USER) && !(src in user)) - if (show_messages) - to_chat(user, span("notice","You need to be holding [src] to do that.")) - return USE_FAIL_NOT_IN_USER - -#undef NOT_FLAG -#undef HAS_FLAG - -//datum may be null, but it does need to be a typed var -#define NAMEOF(datum, X) (#X || ##datum.##X) - -#define VARSET_LIST_CALLBACK(target, var_name, var_value) CALLBACK(GLOBAL_PROC, /proc/___callbackvarset, ##target, ##var_name, ##var_value) -//dupe code because dm can't handle 3 level deep macros -#define VARSET_CALLBACK(datum, var, var_value) CALLBACK(GLOBAL_PROC, /proc/___callbackvarset, ##datum, NAMEOF(##datum, ##var), ##var_value) -//we'll see about those 3-level deep macros -#define VARSET_IN(datum, var, var_value, time) addtimer(VARSET_CALLBACK(datum, var, var_value), time) - -/proc/___callbackvarset(list_or_datum, var_name, var_value) - if(length(list_or_datum)) - list_or_datum[var_name] = var_value - return - var/datum/D = list_or_datum - D.vars[var_name] = var_value - -// Returns direction-string, rounded to multiples of 22.5, from the first parameter to the second -// N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW -/proc/get_adir(var/turf/A, var/turf/B) - var/degree = Get_Angle(A, B) - switch(round(degree%360, 22.5)) - if(0) - return "North" - if(22.5) - return "North-Northeast" - if(45) - return "Northeast" - if(67.5) - return "East-Northeast" - if(90) - return "East" - if(112.5) - return "East-Southeast" - if(135) - return "Southeast" - if(157.5) - return "South-Southeast" - if(180) - return "South" - if(202.5) - return "South-Southwest" - if(225) - return "Southwest" - if(247.5) - return "West-Southwest" - if(270) - return "West" - if(292.5) - return "West-Northwest" - if(315) - return "Northwest" - if(337.5) - return "North-Northwest" - -/proc/pass() - return - -#define NAMEOF(datum, X) (#X || ##datum.##X) - -/proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types()) - if (value == FALSE) //nothing should be calling us with a number, so this is safe - value = input("Enter type to find (blank for all, cancel to cancel)", "Search for type") as null|text - if (isnull(value)) - return - value = trim(value) - if(!isnull(value) && value != "") - matches = filter_fancy_list(matches, value) - - if(matches.len==0) - return - - var/chosen - if(matches.len==1) - chosen = matches[1] - else - chosen = input("Select a type", "Pick Type", matches[1]) as null|anything in matches - if(!chosen) - return - chosen = matches[chosen] - return chosen - -/proc/get_fancy_list_of_atom_types() - var/static/list/pre_generated_list - if (!pre_generated_list) //init - pre_generated_list = make_types_fancy(typesof(/atom)) - return pre_generated_list - -/proc/get_fancy_list_of_datum_types() - var/static/list/pre_generated_list - if (!pre_generated_list) //init - pre_generated_list = make_types_fancy(sortList(typesof(/datum) - typesof(/atom))) - return pre_generated_list - -/proc/filter_fancy_list(list/L, filter as text) - var/list/matches = new - for(var/key in L) - var/value = L[key] - if(findtext("[key]", filter) || findtext("[value]", filter)) - matches[key] = value - return matches - -/proc/make_types_fancy(var/list/types) - if (ispath(types)) - types = list(types) - . = list() - for(var/type in types) - var/typename = "[type]" - var/static/list/TYPES_SHORTCUTS = list( - /obj/effect/decal/cleanable = "CLEANABLE", - /obj/item/device/radio/headset = "HEADSET", - /obj/item/clothing/head/helmet/space = "SPESSHELMET", - /obj/item/weapon/book/manual = "MANUAL", - /obj/item/weapon/reagent_containers/food/drinks = "DRINK", - /obj/item/weapon/reagent_containers/food = "FOOD", - /obj/item/weapon/reagent_containers = "REAGENT_CONTAINERS", - /obj/machinery/atmospherics = "ATMOS_MECH", - /obj/machinery/portable_atmospherics = "PORT_ATMOS", - /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack = "MECHA_MISSILE_RACK", - /obj/item/mecha_parts/mecha_equipment = "MECHA_EQUIP", - /obj/item/organ = "ORGAN", - /obj/item = "ITEM", - /obj/machinery = "MACHINERY", - /obj/effect = "EFFECT", - /obj = "O", - /datum = "D", - /turf/simulated/wall = "S-WALL", - /turf/simulated/floor = "S-FLOOR", - /turf/simulated = "SIMULATED", - /turf/unsimulated/wall = "US-WALL", - /turf/unsimulated/floor = "US-FLOOR", - /turf/unsimulated = "UNSIMULATED", - /turf = "T", - /mob/living/carbon = "CARBON", - /mob/living/simple_mob = "SIMPLE", - /mob/living = "LIVING", - /mob = "M" - ) - for (var/tn in TYPES_SHORTCUTS) - if (copytext(typename,1, length("[tn]/")+1)=="[tn]/" /*findtextEx(typename,"[tn]/",1,2)*/ ) - typename = TYPES_SHORTCUTS[tn]+copytext(typename,length("[tn]/")) - break - .[typename] = type - -/proc/IsValidSrc(datum/D) - if(istype(D)) - return !QDELETED(D) - return FALSE - -//gives us the stack trace from CRASH() without ending the current proc. -/proc/stack_trace(msg) - CRASH(msg) - -/datum/proc/stack_trace(msg) - CRASH(msg) - -// \ref behaviour got changed in 512 so this is necesary to replicate old behaviour. -// If it ever becomes necesary to get a more performant REF(), this lies here in wait -// #define REF(thing) (thing && istype(thing, /datum) && (thing:datum_flags & DF_USE_TAG) && thing:tag ? "[thing:tag]" : "\ref[thing]") -/proc/REF(input) - if(istype(input, /datum)) - var/datum/thing = input - if(thing.datum_flags & DF_USE_TAG) - if(!thing.tag) - thing.datum_flags &= ~DF_USE_TAG - stack_trace("A ref was requested of an object with DF_USE_TAG set but no tag: [thing]") - else - return "\[[url_encode(thing.tag)]\]" - return "\ref[input]" - -// Painlessly creates an element. -// First argument is where to send the Topic call to when clicked. Should be a reference to an object. This is generally src, but not always. -// Second one is for all the params that will be sent. Uses an assoc list (e.g. "value" = "5"). -// Note that object refs will be converted to text, as if \ref[thing] was done. To get the ref back on Topic() side, you will need to use locate(). -// Third one is the text that will be clickable. -/proc/href(href_src, list/href_params, href_text) - return "[href_text]" ->>>>>>> 6d8cd17... Merge pull request #6939 from VOREStation/pol-assemblies