Files
Polaris/code/_helpers/unsorted.dm
Neerti 88398773b8 Master to ai electric boogaloo (#5682)
* Ports the supermatter grenade, supporting code

* May or may not make movement seem smoother

* Fixes the Sleepy Ring

* Partially ports the GLOB system

* Fixes the bug(s) that allow meat bodies to have metal brains

* ports VOREStation/VOREStation#4165 - i forgot to check if advanced who was a thing here

* Optimizes supply UI

* Transfer shuttle grammar fixes

* Fixes borked E and W fish sprites

* Fixes incorrect ETA in crew transfer announcement

* Ports descriptors from Bay

* Add files via upload

* Removes Noble Defines

* Mech Mini 'Revamp'. Will need playtesting. (#5480)

* Exosuits are now capable of holding more equipment, of specific types.

* Tweaks regarding feedback in staffside thread, other concerns.

* Tweak to be more consistent. Why did the Odysseus have two universals. Tweak to weapon restriction on Med - > Odyss

* Weapons only fit in universal combat slots.

* Adds smart magazine, magazine functionality

* Adds a new subset of grenades that shoot projectiles

* Low alpha now makes HUDs and tooltips not show up on you

* Fixes a UI bug with emptying currently-open bags into smartfridges...hopefully. (#5515)

* Update smartfridge.dm

* actually indicates which line solves the bug

* Adds a whole bunch of Exosuit weapons and other miscellaneous parts.

* Minifrags now use the small fragments mainly as they should.

* Iced beer no longer freezes you to 3 degrees C, which is enough to seriously burn a Skrell. Seriously, that's weird.

* Touch stuff in reference to responses.

* NanoUI now processes again

* Initial Work: Manifest, Newsfeed

* Adds newscast viewing, manifest

* Cartridge devices

* Template progress

* Med records, Sec records, Emp records

* Cartridge work part 1

* Cartridge work: part 2

 * Power monitoring console
 * Cartridges have persistent, internal data
 * Code to load element-specific data upon request, instead of serving all relevant data at once
 * Janitorial Supply Locator

* Refactor crew manifest to a separate file

* GPS cartridge

* Reorganize GPS to proper organization, important comments

* Supply cartridge

* Status display access

* Merc blast door controller

* Appeases travis (Round 1)

* Appeases travis (Round 2)

* Headset sprites are now on the default ear, which is left

* Cleave changes, attack code cleanup

* Catching is no longer guaranteed, accuracy code is more general

* Adds a Neural implant for future implementation. Promethean brains have been updated to fit it.

* changelog

* Robots can attack things again

* Might help with air subsystem lag

* Ports the spinny throwing animation from Bay

* Cult heal modifier no longer does Shit-Tons of agony. Does mediocre agony on non-cultists.

* Defines.

* Headset sprite tweaks

* Shield Drone no longer auto-fails with Energy Relays.

* I'm an idiot.

* PoIs can be rotated in increments of 90 degrees

* Might fix the server startup error_handler runtime

* Cult Girders are back to being proper.

* Submaps can now be rotated to any cardinal direction (South is default)

* Should fix another runtime with tools

* Buffs the Vox

* Removes debug code (Yes, I'm an idiot)

* Ready for merge

* Fixes some bugs tangentially related to Vox code

* Ports /vg/ instrument frame work, adds client based sound pref

Also shifts sound files which is 98% of the bulk here.

* Helmets now show only certain hairstyles

* fixes the trailing tag, I think

* Scrubbers no longer automatically scrub phoron (#5512)

* adds manual changelog

* Adds new set of cyborg sprites for medical/science/default/security/combat (#5546)

* Refactor cargo trains, they're just normal trains now. Adds the Quad, and re-enables/fixes the Space Bike!

* communicator_header.tmpl now correctly includes Body

* Adds tails to Unathi rig suit sprites (#5551)

* supplycom/control drops the correct circuit

* Emags have an effect on cargo consoles

* The cybersuit is now a space suit.

* Map Bugfixes

-	Fix for mislabeled c_tag cameras, first deck
-	Fix for mislabeled c_tag cameras, second deck
-	Fix for poi crashed containment shuttle mapping issues (terrain generation)
-	Fixed wrong floor type on skipjack
-	Fix for scrubbers pipe, central substation
-	Fix for air supply pipe, chapel
-	Fixed scrubber pipe, Engineering Drone Fab
-	Fix for air supply pipe, Prison Wing
-	Removed redundant supply and scrubber pipe, Security Auxiliary Dock
-	Fix, Fore Aux Dock airlock pipe.
-	Fix air supply pipe, library
-	Fix, scrubber pipe, coffee shop
-	Pipe fix, Medical maint
-	Fix, supply pipe medical secondary storage
-	Removal, redundant supply pipe, cargo maint
-	Fix, virology scrubbers pipes
-	Fix Xenobio and Xenoflora missing atmos connection to the main outpost
-	Fix, missing atmos connections between Main outpost telecoms and main outpost atmos
-	Fix for missing power wires, HoS Office, Warden Office, Heads of Staff Meeting Room
-	New, random mouse spawner
-	New, random mouse spawners added throughout maintenance on the station (maybe too many, maus station 13)
-	New, 30 sheets of lead added to engineering
-	Fix, POIs should now be rad protected and characters won’t be affected by the radiation event

* Fixes Lead Walls (#5562)

A material's ``radiation_resistance`` was never considered for calculating a wall's cached resistance to radiation. This fixes it. There is another issue involving r-walls not being better at stopping radiation than their normal-wall counterparts made of the same material but fixing that involves a lot of number adjusting to avoid the SM engine from getting twice as protective.

* Yet Another Circuit Update (#5549)

* Circuit updates, adds new components, improves printer, new assemblies.

* Finishes powernet circuit.

* Adds wearable assemblies.

* Finialization before merging with GLOB port.

* Finishes circuit update, hopefully.

* Forgot to undo map.

* Removes debug output.

* Readds size traits

* Signal pistol can be reloaded (#5566)

* Makes Blobs more useful.

* Rig and Spacesuit additions

- Added the 'military' Rigsuit from Bay.
- Added 'pmc' rigsuits
- Added exploration and pilot voidsuits along with alternate sprites (alternate sprites done by Naidh)
- Addition of suit cyclers for exploration and pilot voidsuits

None of these suits are currently accessible in game outside of admin bus. Currently only the pilot voidsuits have other species sprites. Exploration suits are missing sprites for Teshari (Naidh made some for their alternates but I have to add them) and the rig suits are human only. This is to be fixed in the near future, just wanted to get the make workload actually in the game first.

* Dermal implant doesn't cover hair

* Fixes a couple of tool related oversight/runtimes

* Fixes hand and leg cuffs

* Technically adds the Ore Redemption Machine

* Update combat.dm

* Boot knives fit in boots

* Adds tails to Unathi rigsuits (again)

* PoI fix

* Skrell names no longer contain spaces

* Descriptors now properly respect species differences

* Make the Statue NOT entirely immortal.

* Psychiatric Medication Fix (#5588)

* Psychiatric medications are faster when ingested

* Psychiatric med fix

* Updates changelog

* Tweaks emitters and Pacman

* Adds the Biopsy Scanner to the Surgery Kit (#5589)

* Adds the Biopsy Scanner to the Surgery Kit

Since it's actually used in a surgical operation, it should proooobably be in the kit. Iunno if the kit is really used here aside from antag shuttles, but they might as well have it.

* Added a missing comma

Missed a comma, might be what's causing issues. Iunno. It worked flawlessly in dream-maker.

* Adds some Holy drinks, and Promethean-safe drinks / acclimators. (#5574)

* Adds some Holy drinks, and Promethean-safe drinks / acclimators.

* Carbon + Water + Oil = Sludge

* TRUEFALSE & * removed

* Be Smart about damage things.

* Don't spawn things in Null please.

* Adds a generic proc to the mining vendor to add custom / blank entries.

* Keys now actually exist again.

* Species item slowdown changes

* Pose now shows up under descriptors

* Fixes Circuitry Glasses.

Button in HUD should work now.

* Phase rifle size correction

* Should fix the new bugs with webslinger spiders (#5612)

* Hyposprays can now have different sounds

* admin helps, but working this time.

* handle issue, GLOB staffwho

* admin list seems bork'd cleans up feedback messages

* Fixes grabs breaking defined mob pixel offsets.

Yeah.

* Custom RIG Framework (#5613)

* Framework for Custom RIG sprites.

* Fixfix

* line ending

* Text for handheld plushies when poked

Plushies now make sounds when poked. Squeak!

Ported from https://github.com/VOREStation/VOREStation/pull/4231

* Shotgun cycling animation framework
This adds the possiblity for empty sprites on all shotgun/pump/thing and for cycling animations.
https://cdn.discordapp.com/attachments/407267031562453032/488751327531368481/2018-09-10_18-43-05.gif
This particular weapon was made by a friend so i'll wait for their permission before porting it in.

* Add an animated rifle.
Nothing is particularly impressive except the animation.

* Fixes some bloodloss bugs

* Move almost everythign food related into the kitchen module.
Not moving reagents and tools.

* Minor issues fix.

* Remplace sprite hammer with pickaxe
This particular hammer had been sitting 'waiting for sprites' for 4 years at least. Could be a lot more really.

Fixeshttps://github.com/VOREStation/VOREStation/issues/4183

* Fix mislabelled posters.
https://github.com/VOREStation/VOREStation/pull/4310
https://github.com/VOREStation/VOREStation/issues/3597

* Remove kobold.dm
This file has no sprites and is used nowhere. It does have some kinda cute emotes but without sprites it's useless and has been since 2017 and maybe much longer. I haven't found any references of it's origin either.
~~maybe virgo will do sprites i dunno~~

* Fix yes emote not working correctly.
It's a lazy fix but it works.

* Fixes chem master dumping reagents.
Previously, if you used a bluespace beaker and transferred all of it's contents, the chem master buffer would silently drop all of those chemicals without warning.

* Fixed smes terminal construction requiring more cable than used.

* Fixes laptop blocking grown adults.

* Fixes several typos with oxygen_pump.dm.

* Fix the condimaster not working.
Previously, you simply couldn't make any condiment using this machine. Now you can. There was just missing template which is back in with this PR. (Thanks aronai.)
This means you should consider remplacing it in your kitchens.

* Remove intensity from chemistry machines.

* Add a noise for mining scanners.
This should affects all devices using it too.

* Prevents people from HREF exploiting around the R&D console.

* Lock has a check already, so remove that.

* reeeeeeeee

* Fixes missing sprites when excavating rocks

* Xenoflora and Xenobio House Move

- Moves Xenoflora and Xenobio stationside, on first deck. Leaves the old labs still up planetside for the time being.
- Minor bug fixes, missing lights, mislabeled lockers in robotics, floor decals.

* Changes << to to_chat at request.

* wax staxs

* Fix plastic ashtrays only holding one butt. Now they hold 4butts.
jeez bill.

* Move surgery caps into their own selection.

* Fixes maploading

Imagine you're on the last iteration of this loop, you've done the final column of X coordinates and you're going to set maxx.
Would you want to set it to where you are now, the final X column... or would you want to add ONE MORE beyond the template size for some reason then set it to that?

This bug causes all templates that are the size of normal maps to fail to initialize any atoms if your template is the size of your normal maps, because it tries to obtain a square of size minx, miny, minz, maxx, maxy, maxz to initialize, however maxx is nonextant because it exists outside the bounds of the world. It also causes all submaps to initialize an additional column of atoms twice, or not initialize any if they spawn against the right edge of the map.

* Graves (#5622)

* Adds support for closets storing closets, and graves

* More Grave Things

* Chnglog

* Polaris Vision Tweaks

* Fix a couple of ticket bugs

Don't show admin character names when they reply, and this proc appears to take different options on tg, so was fixed here.

* Prevent people from removing papers from any distances.

* Removes maintenance access from cleanbots

This should stop them from wandering into maintenance never to be seen or heard from again.

* Remove very annoying midi tools

* Magazines improvements (#5666)

* Give sounds to emptying magazines

* Clear some trash in the saber magazines

* The magazine NOW behaves correctly.

* The second half and more casing noises.

* Fixes map and makes everything compile.
2018-10-20 14:05:50 -07:00

1441 lines
42 KiB
Plaintext

//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;j++)//It'll take dxabs steps to get there
y+=dyabs
if(y>=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;j++)
x+=dxabs
if(x>=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!
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
//world << "<b>[newname] is the AI!</b>"
//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_animal/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)
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)
//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)
//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
//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(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/closet/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 "<a href='?src=\ref[D];[arglist]'>[content]</a>"
/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
// 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