//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) 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) 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/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 //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 //Ensure the frequency is within bounds of what it should be sending/recieving at /proc/sanitize_frequency(var/f) f = round(f) f = max(1441, f) // 144.1 f = min(1489, f) // 148.9 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]" //Handles giving an AI its name /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 var/iterations = 0 while(!newname) switch(iterations) if(0) if(1 to 5) M << "Invalid name. Your name should be at least 4 alphanumeric characters but under [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, 0-9, -, ' and ." else break newname = reject_bad_name(input(M,"You are the AI. Would you like to change your name to something else?", "Name change",randomname),1) iterations++ if((world.time-time_passed)>300)//If more than 20 game seconds passed. M << "You took too long to decide. Default name selected." return if(newname) if( newname == "Inactive AI" || findtext(newname,"cyborg") ) //To prevent common meta-gaming name-choices M << "That name is reserved." return for (var/mob/living/silicon/ai/A in player_list) if (A.real_name == newname && newname!=randomname) M << "There's already an AI with that name." return M.real_name = newname M.name = newname M.mind.name = newname //Handles givving the Clown his/her name /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 = copytext(sanitize(input(M,"You are the clown. Would you like to change your name to something else?", "Name change",randomname)),1,MAX_NAME_LEN) var/oldname = M.real_name if (!newname) newname = randomname else var/badname = 0 newname = trim_right(trim_left(newname)) // " Abe Butts " becomes "Abe Butts" 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 player_list) if(A.real_name == newname) M << "That name is reserved." return clname(M) M.real_name = newname M.name = newname M.mind.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_name == oldname) id.registered_name = newname id.name = "[id.registered_name]'s ID Card ([id.assignment])" break //Picks a string of symbols to display as the law number for hacked or ion laws /proc/ionnum() return "[pick("!","@","#","$","%","^","&","*")][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/names = list() var/list/borgs = list() var/list/namecounts = list() for (var/mob/living/silicon/robot/A in player_list) 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] //When a borg is activated, it can choose which AI it wants to be slaved to /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 player_list) 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] //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/dead/observer/)) name += " \[ghost\]" else name += " \[dead\]" creatures[name] = M return creatures //Orders mobs by type /proc/sortmobs() var/list/moblist = list() for(var/mob/living/silicon/ai/M in mob_list) moblist.Add(M) for(var/mob/living/silicon/pai/M in mob_list) moblist.Add(M) for(var/mob/living/silicon/robot/M in mob_list) moblist.Add(M) for(var/mob/living/carbon/human/M in mob_list) moblist.Add(M) for(var/mob/living/carbon/brain/M in mob_list) moblist.Add(M) for(var/mob/living/carbon/alien/M in mob_list) moblist.Add(M) for(var/mob/dead/observer/M in mob_list) moblist.Add(M) for(var/mob/new_player/M in mob_list) moblist.Add(M) for(var/mob/living/carbon/monkey/M in mob_list) moblist.Add(M) for(var/mob/living/carbon/metroid/M in mob_list) moblist.Add(M) for(var/mob/living/simple_animal/M in mob_list) 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(var/M) var/E = M*(SPEED_OF_LIGHT_SQ) return E //M = E/C^2 /proc/convert2mass(var/E) var/M = E/(SPEED_OF_LIGHT_SQ) return M //Forces a variable to be posative /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 //Will return the location of the turf an atom is ultimatly sitting on /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) //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) //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 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 /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.get_active_hand() sleep(time) if(!user || !target) return 0 if ( user.loc == user_loc && target.loc == target_loc && user.get_active_hand() == holding && !( user.stat ) && ( !user.stunned && !user.weakened && !user.paralysis && !user.lying ) ) return 1 else return 0 /proc/do_after(var/mob/user as mob, delay as num, var/numticks = 5, var/needhand = 1) if(!user || isnull(user)) return 0 if(numticks == 0) return 0 var/delayfraction = round(delay/numticks) var/turf/T = user.loc var/holding = user.get_active_hand() for(var/i = 0, i