//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 /* * A large number of misc global procs. */ //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, 2) textg = num2hex(255 - g, 2) textb = num2hex(255 - b, 2) return text("#[][][]", textr, textg, textb) return /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) 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) return if(destination.x>world.maxx || destination.x<1) return if(destination.y>world.maxy || destination.y<1) return else return return destination /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 //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, ch, len = length(key) for (i = 7, i <= len, ++i) ch = text2ascii(key, i) if (ch < 48 || ch > 57) return 0 return 1 //Generalised helper proc for letting mobs rename themselves. Used to be clname() and ainame() /mob/proc/rename_self(role) var/oldname = real_name var/newname var/loop = 1 var/safety = 0 while(loop && safety < 5) if(client && client.prefs.custom_names[role] && !safety) newname = client.prefs.custom_names[role] else switch(role) if("clown") newname = pick(clown_names) if("mime") newname = pick(mime_names) if("ai") newname = pick(ai_names) if("deity") newname = pick(clown_names|ai_names|mime_names) //pick any old name else return for(var/mob/living/M in player_list) if(M == src) continue if(!newname || M.real_name == newname) newname = null loop++ // name is already taken so we roll again break loop-- safety++ if(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("!","@","#","$","%","^","&")][pick("!","@","#","$","%","^","&","*")][pick("!","@","#","$","%","^","&","*")][pick("!","@","#","$","%","^","&","*")]" //Returns a list of unslaved cyborgs /proc/active_free_borgs() . = list() for(var/mob/living/silicon/robot/R in living_mob_list) if(R.connected_ai) continue if(R.stat == DEAD) continue if(R.emagged || R.scrambledcodes || R.syndicate) continue . += R //Returns a list of AI's /proc/active_ais(check_mind=0) . = list() for(var/mob/living/silicon/ai/A in living_mob_list) if(A.stat == DEAD) continue if(A.control_disabled == 1) continue if(check_mind) if(!A.mind) 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_free_borg(mob/user) var/list/borgs = active_free_borgs() if(borgs.len) if(user) . = input(user,"Unshackled cyborg signals detected:", "Cyborg Selection", borgs[1]) in borgs else . = pick(borgs) return . /proc/select_active_ai(mob/user) var/list/ais = active_ais() if(ais.len) if(user) . = input(user,"AI signals detected:", "AI Selection", ais[1]) in ais else . = pick(ais) return . //Returns a list of all items of interest with their name /proc/getpois(mobs_only=0,skip_mindless=0) var/list/mobs = sortmobs() var/list/names = list() var/list/pois = list() var/list/namecounts = list() for(var/mob/M in mobs) if(skip_mindless && (!M.mind && !M.ckey)) if(!isbot(M) && !istype(M, /mob/camera/)) continue if(M.client && M.client.holder && M.client.holder.fakekey) //stealthmins continue 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/dead/observer/)) name += " \[ghost\]" else name += " \[dead\]" pois[name] = M if(!mobs_only) for(var/atom/A in poi_list) if(!A || !A.loc) continue var/name = A.name if (names.Find(name)) namecounts[name]++ name = "[name] ([namecounts[name]])" else names.Add(name) namecounts[name] = 1 pois[name] = A return pois //Orders mobs by type then by name /proc/sortmobs() var/list/moblist = list() var/list/sortmob = sortNames(mob_list) for(var/mob/living/silicon/ai/M in sortmob) moblist.Add(M) for(var/mob/camera/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/dead/observer/M in sortmob) moblist.Add(M) for(var/mob/new_player/M in sortmob) moblist.Add(M) for(var/mob/living/carbon/monkey/M in sortmob) moblist.Add(M) for(var/mob/living/simple_animal/slime/M in sortmob) moblist.Add(M) for(var/mob/living/simple_animal/M in sortmob) moblist.Add(M) // for(var/mob/living/silicon/hivebot/M in world) // mob_list.Add(M) // for(var/mob/living/silicon/hive_mainframe/M in world) // mob_list.Add(M) return moblist //E = MC^2 /proc/convert2energy(M) var/E = M*(SPEED_OF_LIGHT_SQ) return E //M = E/C^2 /proc/convert2mass(E) var/M = E/(SPEED_OF_LIGHT_SQ) return M /proc/key_name(whom, include_link = null, include_name = 1) var/mob/M var/client/C var/key var/ckey if(!whom) return "*null*" if(istype(whom, /client)) C = whom M = C.mob key = C.key ckey = C.ckey else if(ismob(whom)) M = whom C = M.client key = M.key ckey = M.ckey else if(istext(whom)) key = whom ckey = ckey(whom) C = directory[ckey] if(C) M = C.mob else return "*invalid*" . = "" if(!ckey) include_link = 0 if(key) if(C && C.holder && C.holder.fakekey && !include_name) if(include_link) . += "" . += "Administrator" else if(include_link) . += "" . += key if(!C) . += "\[DC\]" if(include_link) . += "" else . += "*no key*" if(include_name && M) if(M.real_name) . += "/([M.real_name])" else if(M.name) . += "/([M.name])" return . /proc/key_name_admin(whom, include_name = 1) return key_name(whom, 1, include_name) /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 // Returns the atom sitting on the turf. // For example, using this on a disk, which is in a bag, on a mob, will return the mob because it's on the turf. /proc/get_atom_on_turf(atom/movable/M) var/atom/loc = M while(loc && loc.loc && !istype(loc.loc, /turf/)) loc = loc.loc return loc // returns the turf located at the map edge in the specified direction relative to A // used for mass driver /proc/get_edge_target_turf(atom/A, 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(atom/A, direction, 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(atom/A, dx, 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) /proc/arctan(x) var/y=arcsin(x/sqrt(1+x*x)) return y /proc/anim(turf/location,target as mob|obj,a_icon,a_icon_state as text,flick_anim as text,sleeptime = 0,direction as num) //This proc throws up either an icon or an animation for a specified amount of time. //The variables should be apparent enough. var/atom/movable/overlay/animation = new(location) if(direction) animation.dir = direction animation.icon = a_icon animation.layer = target:layer+1 if(a_icon_state) animation.icon_state = a_icon_state else animation.icon_state = "blank" animation.master = target flick(flick_anim, animation) sleep(max(sleeptime, 15)) qdel(animation) /atom/proc/GetAllContents() var/list/processing_list = list(src) var/list/assembled = list() while(processing_list.len) var/atom/A = processing_list[1] processing_list -= A for(var/atom/a in A) if(!(a in assembled)) processing_list |= a assembled |= A return assembled //Step-towards method of determining whether one atom can see another. Similar to viewers() /proc/can_see(atom/source, atom/target, length=5) // I couldnt 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 = 1 if(current != target_turf) current = get_step_towards(current, target_turf) 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(turf/T) if(T.density) return 1 for(var/i in T) var/atom/A = i if(A.density) return 1 return 0 /proc/is_anchored_dense_turf(turf/T) //like the older version of the above, fails only if also anchored if(T.density) return 1 for(var/i in T) var/atom/movable/A = i if(A.density && A.anchored) return 1 return 0 /proc/get_step_towards2(atom/ref , 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(datum/A, varname) if(A.vars.Find(lowertext(varname))) return 1 else return 0 //Repopulates sortedAreas list /proc/SortAreas() sortedAreas = list() for(var/area/A in world) sortedAreas.Add(A) sortTim(sortedAreas, /proc/cmp_name_asc) /area/proc/addSorted() sortedAreas.Add(src) sortTim(sortedAreas, /proc/cmp_name_asc) //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(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 world) 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(areatype, target_z = 0) 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 world) if(istype(N, areatype)) for(var/turf/T in N) if(target_z == 0 || target_z == T.z) 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(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 world) if(istype(N, areatype)) for(var/atom/A in N) atoms += A return atoms /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/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 return zone //Gets the turf this atom inhabits /proc/get_turf(atom/A) if (!istype(A)) return for(A, A && !isturf(A), A=A.loc); //semicolon is for the empty statement return A /* Gets the turf this atom's *ICON* appears to inhabit It takes into account: * Pixel_x/y * Matrix x/y NOTE: if your atom has non-standard bounds then this proc will handle it, but: * if the bounds are even, then there are an even amount of "middle" turfs, the one to the EAST, NORTH, or BOTH is picked (this may seem bad, but you're atleast as close to the center of the atom as possible, better than byond's default loc being all the way off) * if the bounds are odd, the true middle turf of the atom is returned */ /proc/get_turf_pixel(atom/movable/AM) if(!istype(AM)) return //Find AM's matrix so we can use it's X/Y pixel shifts var/matrix/M = matrix(AM.transform) var/pixel_x_offset = AM.pixel_x + M.get_x_shift() var/pixel_y_offset = AM.pixel_y + M.get_y_shift() //Irregular objects if(AM.bound_height != world.icon_size || AM.bound_width != world.icon_size) var/icon/AMicon = icon(AM.icon, AM.icon_state) pixel_x_offset += ((AMicon.Width()/world.icon_size)-1)*(world.icon_size*0.5) pixel_y_offset += ((AMicon.Height()/world.icon_size)-1)*(world.icon_size*0.5) qdel(AMicon) //DY and DX var/rough_x = round(round(pixel_x_offset,world.icon_size)/world.icon_size) var/rough_y = round(round(pixel_y_offset,world.icon_size)/world.icon_size) //Find coordinates var/turf/T = get_turf(AM) //use AM's turfs, as it's coords are the same as AM's AND AM's coords are lost if it is inside another atom var/final_x = T.x + rough_x var/final_y = T.y + rough_y if(final_x || final_y) return locate(final_x, final_y, T.z) //Finds the distance between two atoms, in pixels //centered = 0 counts from turf edge to edge //centered = 1 counts from turf center to turf center //of course mathematically this is just adding world.icon_size on again /proc/getPixelDistance(atom/A, atom/B, centered = 1) if(!istype(A)||!istype(B)) return 0 . = bounds_dist(A, B) + sqrt((((A.pixel_x+B.pixel_x)**2) + ((A.pixel_y+B.pixel_y)**2))) if(centered) . += world.icon_size /proc/get(atom/loc, type) while(loc) if(istype(loc, type)) return loc loc = loc.loc return null //Quick type checks for some tools var/global/list/common_tools = list( /obj/item/stack/cable_coil, /obj/item/weapon/wrench, /obj/item/weapon/weldingtool, /obj/item/weapon/screwdriver, /obj/item/weapon/wirecutters, /obj/item/device/multitool, /obj/item/weapon/crowbar) /proc/istool(O) if(O && is_type_in_list(O, common_tools)) return 1 return 0 /proc/is_pointed(obj/item/W) if(istype(W, /obj/item/weapon/pen)) return 1 if(istype(W, /obj/item/weapon/screwdriver)) return 1 if(istype(W, /obj/item/weapon/reagent_containers/syringe)) return 1 if(istype(W, /obj/item/weapon/kitchen/fork)) return 1 else return 0 //For objects that should embed, but make no sense being is_sharp or is_pointed() //e.g: rods /proc/can_embed(obj/item/W) if(W.is_sharp()) return 1 if(is_pointed(W)) return 1 var/list/embed_items = list(\ /obj/item/stack/rods,\ ) if(is_type_in_list(W, embed_items)) return 1 /* Checks if that loc and dir has a item on the wall */ var/list/WALLITEMS = list( /obj/machinery/power/apc, /obj/machinery/airalarm, /obj/item/device/radio/intercom, /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, /obj/machinery/computer/security/telescreen, /obj/machinery/embedded_controller/radio/simple_vent_controller, /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 ) var/list/WALLITEMS_EXTERNAL = list( /obj/machinery/camera, /obj/machinery/camera_assembly, /obj/machinery/light_construct, /obj/machinery/light) var/list/WALLITEMS_INVERSE = list( /obj/machinery/light_construct, /obj/machinery/light) /proc/gotwallitem(loc, dir, var/check_external = 0) var/locdir = get_step(loc, dir) for(var/obj/O in loc) if(is_type_in_list(O, WALLITEMS) && check_external != 2) //Direction works sometimes if(is_type_in_list(O, WALLITEMS_INVERSE)) if(O.dir == turn(dir, 180)) return 1 else if(O.dir == dir) return 1 //Some stuff doesn't use dir properly, so we need to check pixel instead //That's exactly what get_turf_pixel() does if(get_turf_pixel(O) == locdir) return 1 if(is_type_in_list(O, WALLITEMS_EXTERNAL) && check_external) if(is_type_in_list(O, WALLITEMS_INVERSE)) if(O.dir == turn(dir, 180)) return 1 else if(O.dir == dir) return 1 //Some stuff is placed directly on the wallturf (signs) for(var/obj/O in locdir) if(is_type_in_list(O, WALLITEMS) && check_external != 2) if(O.pixel_x == 0 && O.pixel_y == 0) return 1 return 0 /proc/format_text(text) return replacetext(replacetext(text,"\proper ",""),"\improper ","") /obj/proc/atmosanalyzer_scan(datum/gas_mixture/air_contents, mob/user, obj/target = src) var/obj/icon = target user.visible_message("[user] has used the analyzer on \icon[icon] [target].", "You use the analyzer on \icon[icon] [target].") var/pressure = air_contents.return_pressure() var/total_moles = air_contents.total_moles() user << "Results of analysis of \icon[icon] [target]." if(total_moles>0) user << "Pressure: [round(pressure,0.1)] kPa" var/list/cached_gases = air_contents.gases for(var/id in cached_gases) var/gas_concentration = cached_gases[id][MOLES]/total_moles if(id in hardcoded_gases || gas_concentration > 0.01) //ensures the four primary gases are always shown. user << "[cached_gases[id][GAS_META][META_GAS_NAME]]: [round(gas_concentration*100)] %" user << "Temperature: [round(air_contents.temperature-T0C)] °C" else user << "[target] is empty!" return /proc/check_target_facings(mob/living/initator, mob/living/target) /*This can be used to add additional effects on interactions between mobs depending on how the mobs are facing each other, such as adding a crit damage to blows to the back of a guy's head. Given how click code currently works (Nov '13), the initiating mob will be facing the target mob most of the time That said, this proc should not be used if the change facing proc of the click code is overriden at the same time*/ if(!ismob(target) || target.lying) //Make sure we are not doing this for things that can't have a logical direction to the players given that the target would be on their side return FACING_FAILED if(initator.dir == target.dir) //mobs are facing the same direction return FACING_SAME_DIR if(is_A_facing_B(initator,target) && is_A_facing_B(target,initator)) //mobs are facing each other return FACING_EACHOTHER if(initator.dir + 2 == target.dir || initator.dir - 2 == target.dir || initator.dir + 6 == target.dir || initator.dir - 6 == target.dir) //Initating mob is looking at the target, while the target mob is looking in a direction perpendicular to the 1st return FACING_INIT_FACING_TARGET_TARGET_FACING_PERPENDICULAR /proc/random_step(atom/movable/AM, steps, chance) var/initial_chance = chance while(steps > 0) if(prob(chance)) step(AM, pick(alldirs)) chance = max(chance - (initial_chance / steps), 0) steps-- /proc/living_player_count() var/living_player_count = 0 for(var/mob in player_list) if(mob in living_mob_list) living_player_count += 1 return living_player_count /proc/randomColor(mode = 0) //if 1 it doesn't pick white, black or gray switch(mode) if(0) return pick("white","black","gray","red","green","blue","brown","yellow","orange","darkred", "crimson","lime","darkgreen","cyan","navy","teal","purple","indigo") if(1) return pick("red","green","blue","brown","yellow","orange","darkred","crimson", "lime","darkgreen","cyan","navy","teal","purple","indigo") else return "white" /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) /proc/IsValidSrc(A) if(istype(A, /datum)) var/datum/B = A return !B.gc_destroyed if(istype(A, /client)) return 1 return 0 //Get the dir to the RIGHT of dir if they were on a clock //NORTH --> NORTHEAST /proc/get_clockwise_dir(dir) . = angle2dir(dir2angle(dir)+45) //Get the dir to the LEFT of dir if they were on a clock //NORTH --> NORTHWEST /proc/get_anticlockwise_dir(dir) . = angle2dir(dir2angle(dir)-45) //Compare A's dir, the clockwise dir of A and the anticlockwise dir of A //To the opposite dir of the dir returned by get_dir(B,A) //If one of them is a match, then A is facing B /proc/is_A_facing_B(atom/A,atom/B) if(!istype(A) || !istype(B)) return 0 if(istype(A, /mob/living)) var/mob/living/LA = A if(LA.lying) return 0 var/goal_dir = angle2dir(dir2angle(get_dir(B,A)+180)) var/clockwise_A_dir = get_clockwise_dir(A.dir) var/anticlockwise_A_dir = get_anticlockwise_dir(B.dir) if(A.dir == goal_dir || clockwise_A_dir == goal_dir || anticlockwise_A_dir == goal_dir) return 1 return 0 /* rough example of the "cone" made by the 3 dirs checked B \ \ > < \ \ B --><-- A / / < > / / B */ //This is just so you can stop an orbit. //orbit() can run without it (swap orbiting for A) //but then you can never stop it and that's just silly. /atom/movable/var/atom/orbiting = null //A: atom to orbit //radius: range to orbit at, radius of the circle formed by orbiting //clockwise: whether you orbit clockwise or anti clockwise //rotation_speed: how fast to rotate //rotation_segments: the resolution of the orbit circle, less = a more block circle, this can be used to produce hexagons (6 segments) triangles (3 segments), and so on, 36 is the best default. //pre_rotation: Chooses to rotate src 90 degress towards the orbit dir (clockwise/anticlockwise), useful for things to go "head first" like ghosts //lockinorbit: Forces src to always be on A's turf, otherwise the orbit cancels when src gets too far away (eg: ghosts) /atom/movable/proc/orbit(atom/A, radius = 10, clockwise = FALSE, rotation_speed = 20, rotation_segments = 36, pre_rotation = TRUE, lockinorbit = FALSE) if(!istype(A)) return if(orbiting) stop_orbit() orbiting = A var/matrix/initial_transform = matrix(transform) var/lastloc = loc //Head first! if(pre_rotation) var/matrix/M = matrix(transform) var/pre_rot = 90 if(!clockwise) pre_rot = -90 M.Turn(pre_rot) transform = M var/matrix/shift = matrix(transform) shift.Translate(0,radius) transform = shift SpinAnimation(rotation_speed, -1, clockwise, rotation_segments) //we stack the orbits up client side, so we can assign this back to normal server side without it breaking the orbit transform = initial_transform while(orbiting && orbiting == A && A.loc) var/targetloc = get_turf(A) if(!lockinorbit && loc != lastloc && loc != targetloc) break loc = targetloc lastloc = loc sleep(0.6) if (orbiting == A) //make sure we haven't started orbiting something else. orbiting = null SpinAnimation(0,0) /atom/movable/proc/stop_orbit() orbiting = null //Center's an image. //Requires: //The Image //The x dimension of the icon file used in the image //The y dimension of the icon file used in the image // eg: center_image(I, 32,32) // eg2: center_image(I, 96,96) /proc/center_image(var/image/I, x_dimension = 0, y_dimension = 0) if(!I) return if(!x_dimension || !y_dimension) return if((x_dimension == world.icon_size) && (y_dimension == world.icon_size)) return I //Offset the image so that it's bottom left corner is shifted this many pixels //This makes it infinitely easier to draw larger inhands/images larger than world.iconsize //but still use them in game var/x_offset = -((x_dimension/world.icon_size)-1)*(world.icon_size*0.5) var/y_offset = -((y_dimension/world.icon_size)-1)*(world.icon_size*0.5) //Correct values under world.icon_size if(x_dimension < world.icon_size) x_offset *= -1 if(y_dimension < world.icon_size) y_offset *= -1 I.pixel_x = x_offset I.pixel_y = y_offset return I //similar function to range(), but with no limitations on the distance; will search spiralling outwards from the center /proc/ultra_range(dist=0, center=usr, orange=0) if(!dist) if(!orange) return list(center) else return list() var/turf/t_center = get_turf(center) if(!t_center) return list() var/list/L = list() var/turf/T var/y var/x var/c_dist = 1 if(!orange) L += t_center L += t_center.contents while( c_dist <= dist ) y = t_center.y + c_dist x = t_center.x - c_dist + 1 for(x in x to t_center.x+c_dist) T = locate(x,y,t_center.z) if(T) L += T L += T.contents y = t_center.y + c_dist - 1 x = t_center.x + c_dist for(y in t_center.y-c_dist to y) T = locate(x,y,t_center.z) if(T) L += T L += T.contents y = t_center.y - c_dist x = t_center.x + c_dist - 1 for(x in t_center.x-c_dist to x) T = locate(x,y,t_center.z) if(T) L += T L += T.contents y = t_center.y - c_dist + 1 x = t_center.x - c_dist for(y in y to t_center.y+c_dist) T = locate(x,y,t_center.z) if(T) L += T L += T.contents c_dist++ return L /atom/proc/contains(var/atom/A) if(!A) return 0 for(var/atom/location = A.loc, location, location = location.loc) if(location == src) return 1 proc/add_to_proximity_list(atom/A, range) var/turf/T = get_turf(A) var/list/L = block(locate(T.x - range, T.y - range, T.z), locate(T.x + range, T.y + range, T.z)) for(var/B in L) var/turf/C = B C.proximity_checkers |= A return L proc/remove_from_proximity_list(atom/A, range) var/turf/T = get_turf(A) var/list/L = block(locate(T.x - range, T.y - range, T.z), locate(T.x + range, T.y + range, T.z)) for(var/B in L) var/turf/C = B C.proximity_checkers.Remove(A) proc/shift_proximity(atom/checker, atom/A, range, atom/B, newrange) var/turf/T = get_turf(A) var/turf/Q = get_turf(B) if(T == Q && range == newrange) return 0 var/list/L = block(locate(T.x - range, T.y - range, T.z), locate(T.x + range, T.y + range, T.z)) var/list/M = block(locate(Q.x - newrange, Q.y - newrange, Q.z), locate(Q.x + newrange, Q.y + newrange, Q.z)) var/list/N = L - M var/list/O = M - L for(var/C in N) var/turf/D = C D.proximity_checkers.Remove(checker) for(var/E in O) var/turf/F = E F.proximity_checkers |= checker return 1