/proc/hex2num(hex) if (!( istext(hex) )) CRASH("hex2num not given a hexadecimal string argument (user error)") return var/num = 0 var/power = 0 var/i = null i = length(hex) while(i > 0) var/char = copytext(hex, i, i + 1) switch(char) if("0") //Apparently, switch works with empty statements, yay! If that doesn't work, blame me, though. -- Urist if("9", "8", "7", "6", "5", "4", "3", "2", "1") num += text2num(char) * 16 ** power if("a", "A") num += 16 ** power * 10 if("b", "B") num += 16 ** power * 11 if("c", "C") num += 16 ** power * 12 if("d", "D") num += 16 ** power * 13 if("e", "E") num += 16 ** power * 14 if("f", "F") num += 16 ** power * 15 else CRASH("hex2num given non-hexadecimal string (user error)") return power++ i-- return num /proc/num2hex(num, placeholder) if (placeholder == null) placeholder = 2 if (!( isnum(num) )) CRASH("num2hex not given a numeric argument (user error)") return if (!( num )) return "0" var/hex = "" var/i = 0 while(16 ** i < num) i++ var/power = null power = i - 1 while(power >= 0) var/val = round(num / 16 ** power) num -= val * 16 ** power switch(val) if(9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0) hex += text("[]", val) if(10.0) hex += "A" if(11.0) hex += "B" if(12.0) hex += "C" if(13.0) hex += "D" if(14.0) hex += "E" if(15.0) hex += "F" else power-- while(length(hex) < placeholder) hex = text("0[]", hex) return hex /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 /proc/shuffle(var/list/shufflelist) if(!shufflelist) return var/list/new_list = list() var/list/old_list = shufflelist.Copy() while(old_list.len) var/item = pick(old_list) new_list += item old_list -= item return new_list /proc/uniquelist(var/list/L) var/list/K = list() for(var/item in L) if(!(item in K)) K += item return K /proc/sanitize_simple(var/t,var/list/repl_chars = list("\n"="#","\t"="#","ÿ"="ß")) for(var/char in repl_chars) var/index = findtext(t, char) while(index) t = copytext(t, 1, index) + repl_chars[char] + copytext(t, index+1) index = findtext(t, char) return t /proc/strip_html_simple(var/t,var/limit=MAX_MESSAGE_LEN) var/list/strip_chars = list("<",">") t = copytext(t,1,limit) for(var/char in strip_chars) var/index = findtext(t, char) while(index) t = copytext(t, 1, index) + copytext(t, index+1) index = findtext(t, char) return t /proc/sanitize(var/t,var/list/repl_chars = null) return html_encode(sanitize_simple(t,repl_chars)) /proc/strip_html(var/t,var/limit=MAX_MESSAGE_LEN) return sanitize(strip_html_simple(t)) /proc/adminscrub(var/t,var/limit=MAX_MESSAGE_LEN) return html_encode(strip_html_simple(t)) /proc/add_zero(t, u) while (length(t) < u) t = "0[t]" return t /proc/add_lspace(t, u) while(length(t) < u) t = " [t]" return t /proc/add_tspace(t, u) while(length(t) < u) t = "[t] " return t /proc/trim_left(text) for (var/i = 1 to length(text)) if (text2ascii(text, i) > 32) return copytext(text, i) return "" /proc/trim_right(text) for (var/i = length(text), i > 0, i--) if (text2ascii(text, i) > 32) return copytext(text, 1, i + 1) return "" /proc/trim(text) return trim_left(trim_right(text)) /proc/capitalize(var/t as text) return uppertext(copytext(t, 1, 2)) + copytext(t, 2) /proc/sortList(var/list/L) if(L.len < 2) return L var/middle = L.len / 2 + 1 // Copy is first,second-1 return mergeLists(sortList(L.Copy(0,middle)), sortList(L.Copy(middle))) //second parameter null = to end of list /proc/sortNames(var/list/L) var/list/Q = new() for(var/atom/x in L) Q[x.name] = x return sortList(Q) /proc/mergeLists(var/list/L, var/list/R) var/Li=1 var/Ri=1 var/list/result = new() while(Li <= L.len && Ri <= R.len) if(sorttext(L[Li], R[Ri]) < 1) result += R[Ri++] else result += L[Li++] if(Li <= L.len) return (result + L.Copy(Li, 0)) return (result + R.Copy(Ri, 0)) /proc/dd_file2list(file_path, separator) var/file if(separator == null) separator = "\n" if(isfile(file_path)) file = file_path else file = file(file_path) return dd_text2list(file2text(file), separator) /proc/dd_range(var/low, var/high, var/num) return max(low,min(high,num)) /proc/dd_replacetext(text, search_string, replacement_string) if(!text || !istext(text) || !search_string || !istext(search_string) || !istext(replacement_string)) return null var/textList = dd_text2list(text, search_string) return dd_list2text(textList, replacement_string) /proc/dd_replaceText(text, search_string, replacement_string) var/textList = dd_text2List(text, search_string) return dd_list2text(textList, replacement_string) /proc/dd_hasprefix(text, prefix) var/start = 1 var/end = length(prefix) + 1 return findtext(text, prefix, start, end) /proc/dd_hasPrefix(text, prefix) var/start = 1 var/end = length(prefix) + 1 return findtext(text, prefix, start, end) //was findtextEx /proc/dd_hassuffix(text, suffix) var/start = length(text) - length(suffix) if(start) return findtext(text, suffix, start, null) return /proc/dd_hasSuffix(text, suffix) var/start = length(text) - length(suffix) if(start) return findtext(text, suffix, start, null) //was findtextEx /proc/dd_text2list(text, separator, var/list/withinList) var/textlength = length(text) var/separatorlength = length(separator) if(withinList && !withinList.len) withinList = null var/list/textList = new() var/searchPosition = 1 var/findPosition = 1 var/loops = 0 while(1) if(loops >= 1000) break loops++ findPosition = findtext(text, separator, searchPosition, 0) var/buggyText = copytext(text, searchPosition, findPosition) if(!withinList || (buggyText in withinList)) textList += "[buggyText]" if(!findPosition) return textList searchPosition = findPosition + separatorlength if(searchPosition > textlength) textList += "" return textList return /proc/dd_text2List(text, separator, var/list/withinList) var/textlength = length(text) var/separatorlength = length(separator) if(withinList && !withinList.len) withinList = null var/list/textList = new() var/searchPosition = 1 var/findPosition = 1 while(1) findPosition = findtext(text, separator, searchPosition, 0) //was findtextEx var/buggyText = copytext(text, searchPosition, findPosition) if(!withinList || (buggyText in withinList)) textList += "[buggyText]" if(!findPosition) return textList searchPosition = findPosition + separatorlength if(searchPosition > textlength) textList += "" return textList return /proc/dd_list2text(var/list/the_list, separator) var/total = the_list.len if(!total) return var/count = 2 var/newText = "[the_list[1]]" while(count <= total) if(separator) newText += separator newText += "[the_list[count]]" count++ return newText //slower then dd_list2text, but correctly processes associative lists. proc/tg_list2text(list/list, glue=",") if(!istype(list) || !list.len) return var/output for(var/i=1 to list.len) output += (i!=1? glue : null)+(!isnull(list["[list[i]]"])?"[list["[list[i]]"]]":"[list[i]]") return output //tg_text2list is faster then dd_text2list //not case sensitive version proc/tg_text2list(string, separator=",") if(!string) return var/list/output = new var/seplength = length(separator) var/strlength = length(string) var/prev = 1 var/index do index = findtext(string, separator, prev, 0) output += copytext(string, prev, index) if(!index) break prev = index+seplength if(prev>strlength) break while(index) return output //case sensitive version proc/tg_extext2list(string, separator=",") if(!string) return var/list/output = new var/seplength = length(separator) var/strlength = length(string) var/prev = 1 var/index do index = findtextEx(string, separator, prev, 0) output += copytext(string, prev, index) if(!index) break prev = index+seplength if(prev>strlength) break while(index) return output /proc/english_list(var/list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "," ) var/total = input.len if (!total) return "[nothing_text]" else if (total == 1) return "[input[1]]" else if (total == 2) return "[input[1]][and_text][input[2]]" else var/output = "" var/index = 1 while (index < total) if (index == total - 1) comma_text = final_comma_text output += "[input[index]][comma_text]" index++ return "[output][and_text][input[index]]" /proc/dd_centertext(message, length) var/new_message = message var/size = length(message) var/delta = length - size if(size == length) return new_message if(size > length) return copytext(new_message, 1, length + 1) if(delta == 1) return new_message + " " if(delta % 2) new_message = " " + new_message delta-- var/spaces = add_lspace("",delta/2-1) return spaces + new_message + spaces /proc/dd_limittext(message, length) var/size = length(message) if(size <= length) return message return copytext(message, 1, length + 1) /proc/angle2dir(var/degree) degree = ((degree+22.5)%365) if(degree < 45) return NORTH if(degree < 90) return NORTH|EAST if(degree < 135) return EAST if(degree < 180) return SOUTH|EAST if(degree < 225) return SOUTH if(degree < 270) return SOUTH|WEST if(degree < 315) return WEST return NORTH|WEST /proc/angle2text(var/degree) return dir2text(angle2dir(degree)) /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/text_input(var/Message, var/Title, var/Default, var/length=MAX_MESSAGE_LEN) return sanitize(input(Message, Title, Default) as text, length) /proc/scrub_input(var/Message, var/Title, var/Default, var/length=MAX_MESSAGE_LEN) return strip_html(input(Message,Title,Default) as text, length) /proc/InRange(var/A, var/lower, var/upper) if(A < lower) return 0 if(A > upper) return 0 return 1 /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) //Should get bonus points for being the most compact code in the world! return x!=0?x/abs(x):0 //((x<0)?-1:((x>0)?1:0)) /* //Kelson's version (doesn't work) /proc/getline(atom/M,atom/N) if(!M || !M.loc) return if(!N || !N.loc) return if(M.z != N.z) return var/line = new/list() var/dx = abs(M.x - N.x) var/dy = abs(M.y - N.y) var/cx = M.x < N.x ? 1 : -1 var/cy = M.y < N.y ? 1 : -1 var/slope = dy ? dx/dy : INFINITY var/tslope = slope var/turf/tloc = M.loc while(tloc != N.loc) if(tslope>0) --tslope tloc = locate(tloc.x+cx,tloc.y,tloc.z) else tslope += slope tloc = locate(tloc.x,tloc.y+cy,tloc.z) line += tloc return line */ /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 /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 /proc/pickweight(list/L) var/total = 0 var/item for (item in L) if (!L[item]) L[item] = 1 total += L[item] total = rand(1, total) for (item in L) total -=L [item] if (total <= 0) return item return null /proc/sanitize_frequency(var/f) f = round(f) f = max(1441, f) // 144.1 f = min(1489, f) // 148.9 if ((f % 2) == 0) f += 1 return f /proc/format_frequency(var/f) return "[round(f / 10)].[f % 10]" /proc/ainame(var/mob/M as mob) var/randomname = M.name var/time_passed = world.time//Pretty basic but it'll do. It's still possible to bypass this by return ainame(). var/newname = input(M,"You are the AI. Would you like to change your name to something else?", "Name change",randomname) if((world.time-time_passed)>200)//If more than 20 game seconds passed. M << "You took too long to decide. Default name selected." return if (length(newname) == 0) newname = randomname if (newname) if (newname == "Inactive AI")//Keeping this here to prevent dumb. M << "That name is reserved." return ainame(M) for (var/mob/living/silicon/ai/A in world) if (A.real_name == newname&&newname!=randomname) M << "There's already an AI with that name." return ainame(M) if (length(newname) >= 26) newname = copytext(newname, 1, 26) newname = dd_replacetext(newname, ">", "'") M.real_name = newname M.name = newname /proc/clname(var/mob/M as mob) //--All praise goes to NEO|Phyte, all blame goes to DH, and it was Cindi-Kate's idea var/randomname = pick(clown_names) var/newname = input(M,"You are the clown. Would you like to change your name to something else?", "Name change",randomname) var/oldname = M.real_name if (length(newname) == 0) newname = randomname if (newname) var/badname = 0 switch(newname) if("Unknown") badname = 1 if("floor") badname = 1 if("wall") badname = 1 if("r-wall") badname = 1 if("space") badname = 1 if("_") badname = 1 if(badname) M << "That name is reserved." return clname(M) for (var/mob/A in world) if(A.real_name == newname) M << "That name is reserved." return clname(M) if(length(newname) >= 26) newname = copytext(newname, 1, 26) newname = dd_replacetext(newname, ">", "'") M.real_name = newname M.name = newname for (var/obj/item/device/pda/pda in M.contents) if (pda.owner == oldname) pda.owner = newname pda.name = "PDA-[newname] ([pda.ownjob])" break for(var/obj/item/weapon/card/id/id in M.contents) if(id.registered == oldname) id.registered = newname id.name = "[id.registered]'s ID Card ([id.assignment])" break /proc/ionnum() return "[pick("!","@","#","$","%","^","&","*")][pick(pick("!","@","#","$","%","^","&","*"))][pick(pick("!","@","#","$","%","^","&","*"))][pick(pick("!","@","#","$","%","^","&","*"))]" /proc/freeborg() var/select = null var/list/names = list() var/list/borgs = list() var/list/namecounts = list() for (var/mob/living/silicon/robot/A in world) var/name = A.real_name if (A.stat == 2) continue if (A.connected_ai) continue else if(A.module) name += " ([A.module.name])" names.Add(name) namecounts[name] = 1 borgs[name] = A if (borgs.len) select = input("Unshackled borg signals detected:", "Borg selection", null, null) as null|anything in borgs return borgs[select] /proc/activeais() var/select = null var/list/names = list() var/list/ais = list() var/list/namecounts = list() for (var/mob/living/silicon/ai/A in world) var/name = A.real_name if (A.stat == 2) continue if (A.control_disabled == 1) continue else names.Add(name) namecounts[name] = 1 ais[name] = A if (ais.len) select = input("AI signals detected:", "AI selection") in ais return ais[select] /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/dead/observer/)) name += " \[ghost\]" else name += " \[dead\]" creatures[name] = M return creatures /proc/sortmobs() var/list/mob_list = list() for(var/mob/living/silicon/ai/M in world) mob_list.Add(M) for(var/mob/living/silicon/pai/M in world) mob_list.Add(M) for(var/mob/living/silicon/robot/M in world) mob_list.Add(M) for(var/mob/living/carbon/human/M in world) mob_list.Add(M) for(var/mob/living/carbon/brain/M in world) mob_list.Add(M) for(var/mob/living/carbon/alien/M in world) mob_list.Add(M) for(var/mob/dead/observer/M in world) mob_list.Add(M) for(var/mob/new_player/M in world) mob_list.Add(M) for(var/mob/living/carbon/monkey/M in world) mob_list.Add(M) for(var/mob/living/carbon/metroid/M in world) mob_list.Add(M) for(var/mob/living/simple_animal/M in world) mob_list.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 mob_list /proc/convert2energy(var/M) var/E = M*(SPEED_OF_LIGHT_SQ) return E /proc/convert2mass(var/E) var/M = E/(SPEED_OF_LIGHT_SQ) return M /proc/modulus(var/M) if(M >= 0) return M if(M < 0) return -M /proc/key_name(var/whom, var/include_link = null, var/include_name = 1) var/mob/the_mob = null var/client/the_client = null var/the_key = "" if (isnull(whom)) return "*null*" else if (istype(whom, /client)) the_client = whom the_mob = the_client.mob the_key = the_client.key else if (ismob(whom)) the_mob = whom the_client = the_mob.client the_key = the_mob.key else if (istype(whom, /datum)) var/datum/the_datum = whom return "*invalid:[the_datum.type]*" else return "*invalid*" var/text = "" if (!the_key) text += "*no client*" else var/linked = 1 if (include_link && !isnull(the_mob)) if (istext(include_link)) text += "" else if(ismob(include_link)) var/mob/MM = include_link if(MM.client) text += "" else linked = 0 else if (istype(include_link, /client)) text += "" else linked = 0 if (the_client && the_client.holder && the_client.stealth && !include_name) text += "Administrator" else text += "[the_key]" if (!isnull(include_link) && !isnull(the_mob)) if(linked) text += "" else text += " (DC)" if (include_name && !isnull(the_mob)) if (the_mob.real_name) text += "/([the_mob.real_name])" else if (the_mob.name) text += "/([the_mob.name])" return text /proc/key_name_admin(var/whom, var/include_name = 1) return key_name(whom, "%admin_ref%", include_name) // Registers the on-close verb for a browse window (client/verb/.windowclose) // this will be called when the close-button of a window is pressed. // // This is usually only needed for devices that regularly update the browse window, // e.g. canisters, timers, etc. // // windowid should be the specified window name // e.g. code is : user << browse(text, "window=fred") // then use : onclose(user, "fred") // // Optionally, specify the "ref" parameter as the controlled atom (usually src) // to pass a "close=1" parameter to the atom's Topic() proc for special handling. // Otherwise, the user mob's machine var will be reset directly. // /proc/onclose(mob/user, windowid, var/atom/ref=null) if(!user.client) return var/param = "null" if(ref) param = "\ref[ref]" winset(user, windowid, "on-close=\".windowclose [param]\"") //world << "OnClose [user]: [windowid] : ["on-close=\".windowclose [param]\""]" // the on-close client verb // called when a browser popup window is closed after registering with proc/onclose() // if a valid atom reference is supplied, call the atom's Topic() with "close=1" // otherwise, just reset the client mob's machine var. // /client/verb/windowclose(var/atomref as text) set hidden = 1 // hide this verb from the user's panel set name = ".windowclose" // no autocomplete on cmd line //world << "windowclose: [atomref]" if(atomref!="null") // if passed a real atomref var/hsrc = locate(atomref) // find the reffed atom var/href = "close=1" if(hsrc) //world << "[src] Topic [href] [hsrc]" usr = src.mob src.Topic(href, params2list(href), hsrc) // this will direct to the atom's return // Topic() proc via client.Topic() // no atomref specified (or not found) // so just reset the user mob's machine var if(src && src.mob) //world << "[src] was [src.mob.machine], setting to null" src.mob.machine = null return /proc/reverselist(var/list/input) var/list/output = new/list() for(var/A in input) output += A return output /proc/get_turf_loc(var/atom/movable/M) //gets the location of the turf that the atom is on, or what the atom is in is on, etc //in case they're in a closet or sleeper or something var/atom/loc = M.loc while(!istype(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(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) /* /proc/dir2text(var/d) var/dir switch(d) if(1) dir = "NORTH" if(2) dir = "SOUTH" if(4) dir = "EAST" if(8) dir = "WEST" if(5) dir = "NORTHEAST" if(6) dir = "SOUTHEAST" if(9) dir = "NORTHWEST" if(10) dir = "SOUTHWEST" else dir = null return dir */ //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) proc/arctan(x) var/y=arcsin(x/sqrt(1+x*x)) return y //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) proc/anim(turf/location as turf,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)) del(animation) //returns list element or null. Should prevent "index out of bounds" error. proc/listgetindex(var/list/list,index) if(istype(list) && list.len) if(isnum(index)) if(InRange(index,1,list.len)) return list[index] else if(index in list) return list[index] return proc/islist(list/list) if(istype(list)) return 1 return 0 proc/isemptylist(list/list) if(!list.len) return 1 return 0 proc/clearlist(list/list) if(istype(list)) list.len = 0 return proc/listclearnulls(list/list) if(istype(list)) while(null in list) list -= null return /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 //WIP /* * Returns list containing all the entries present in both lists * If either of arguments is not a list, returns null */ /proc/intersectlist(var/list/first, var/list/second) if(!islist(first) || !islist(second)) return return first & second /* * Returns list containing all the entries from first list that are not present in second. * If skiprep = 1, repeated elements are treated as one. * If either of arguments is not a list, returns null */ /proc/difflist(var/list/first, var/list/second, var/skiprep=0) if(!islist(first) || !islist(second)) return var/list/result = new if(skiprep) for(var/e in first) if(!(e in result) && !(e in second)) result += e else result = first - second return result /* * Returns list containing entries that are in either list but not both. * If skipref = 1, repeated elements are treated as one. * If either of arguments is not a list, returns null */ /proc/uniquemergelist(var/list/first, var/list/second, var/skiprep=0) if(!islist(first) || !islist(second)) return var/list/result = new if(skiprep) result = difflist(first, second, skiprep)+difflist(second, first, skiprep) else result = first ^ second return result /proc/pick_n_take(list/listfrom) if (listfrom.len > 0) var/picked = pick(listfrom) listfrom -= picked return picked return null /proc/pop(list/listfrom) if (listfrom.len > 0) var/picked = listfrom[listfrom.len] listfrom.len-- return picked return null /proc/can_see(var/atom/source, var/atom/target, var/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 = 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 /mob/proc/get_equipped_items() var/list/items = new/list() if(hasvar(src,"back")) if(src:back) items += src:back if(hasvar(src,"belt")) if(src:belt) items += src:belt if(hasvar(src,"ears")) if(src:ears) items += src:ears if(hasvar(src,"glasses")) if(src:glasses) items += src:glasses if(hasvar(src,"gloves")) if(src:gloves) items += src:gloves if(hasvar(src,"head")) if(src:head) items += src:head if(hasvar(src,"shoes")) if(src:shoes) items += src:shoes if(hasvar(src,"wear_id")) if(src:wear_id) items += src:wear_id if(hasvar(src,"wear_mask")) if(src:wear_mask) items += src:wear_mask if(hasvar(src,"wear_suit")) if(src:wear_suit) items += src:wear_suit // if(hasvar(src,"w_radio")) if(src:w_radio) items += src:w_radio commenting this out since headsets go on your ears now PLEASE DON'T BE MAD KEELIN if(hasvar(src,"w_uniform")) if(src:w_uniform) items += src:w_uniform //if(hasvar(src,"l_hand")) if(src:l_hand) items += src:l_hand //if(hasvar(src,"r_hand")) if(src:r_hand) items += src:r_hand return items /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) /proc/do_mob(var/mob/user , var/mob/target, var/time = 30) //This is quite an ugly solution but i refuse to use the old request system. if(!user || !target) return 0 var/user_loc = user.loc var/target_loc = target.loc var/holding = user.equipped() sleep(time) if ( user.loc == user_loc && target.loc == target_loc && user.equipped() == holding && !( user.stat ) && ( !user.stunned && !user.weakened && !user.paralysis && !user.lying ) ) return 1 else return 0 /proc/do_after(mob/M as mob, time as num) if(!M) return 0 var/turf/T = M.loc var/holding = M.equipped() for(var/i=0, i