[MIRROR] Fixes language code ignoring holder restrictions (#858)

* Fixes language code ignoring holder restrictions

* resolve .rej file.
This commit is contained in:
CitadelStationBot
2017-05-18 04:13:57 -05:00
committed by Poojawa
parent e84191b5c3
commit 8bcaa54cbe
30 changed files with 7396 additions and 7396 deletions
+240 -240
View File
@@ -1,240 +1,240 @@
GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation)
/obj/machinery/gateway
name = "gateway"
desc = "A mysterious gateway built by unknown hands, it allows for faster than light travel to far-flung locations."
icon = 'icons/obj/machines/gateway.dmi'
icon_state = "off"
density = 1
anchored = 1
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/active = 0
var/checkparts = TRUE
var/list/obj/effect/landmark/randomspawns = list()
var/calibrated = TRUE
var/list/linked = list()
var/can_link = FALSE //Is this the centerpiece?
/obj/machinery/gateway/Initialize()
randomspawns = GLOB.awaydestinations
update_icon()
if(!istype(src, /obj/machinery/gateway/centerstation) && !istype(src, /obj/machinery/gateway/centeraway))
switch(dir)
if(SOUTH,SOUTHEAST,SOUTHWEST)
density = 0
..()
/obj/machinery/gateway/proc/toggleoff()
for(var/obj/machinery/gateway/G in linked)
G.active = 0
G.update_icon()
active = 0
update_icon()
/obj/machinery/gateway/proc/detect()
if(!can_link)
return FALSE
linked = list() //clear the list
var/turf/T = loc
var/ready = FALSE
for(var/i in GLOB.alldirs)
T = get_step(loc, i)
var/obj/machinery/gateway/G = locate(/obj/machinery/gateway) in T
if(G)
linked.Add(G)
continue
//this is only done if we fail to find a part
ready = FALSE
toggleoff()
break
if((linked.len == 8) || !checkparts)
ready = TRUE
return ready
/obj/machinery/gateway/update_icon()
if(active)
icon_state = "on"
return
icon_state = "off"
//prevents shuttles attempting to rotate this since it messes up sprites
/obj/machinery/gateway/shuttleRotate()
return
/obj/machinery/gateway/attack_hand(mob/user)
if(!detect())
return
if(!active)
toggleon(user)
return
toggleoff()
/obj/machinery/gateway/proc/toggleon(mob/user)
return FALSE
/obj/machinery/gateway/centerstation/New()
..()
if(!GLOB.the_gateway)
GLOB.the_gateway = src
/obj/machinery/gateway/centerstation/Destroy()
if(GLOB.the_gateway == src)
GLOB.the_gateway = null
return ..()
//this is da important part wot makes things go
/obj/machinery/gateway/centerstation
density = TRUE
icon_state = "offcenter"
use_power = TRUE
//warping vars
var/wait = 0 //this just grabs world.time at world start
var/obj/machinery/gateway/centeraway/awaygate = null
can_link = TRUE
/obj/machinery/gateway/centerstation/Initialize()
..()
update_icon()
wait = world.time + config.gateway_delay //+ thirty minutes default
awaygate = locate(/obj/machinery/gateway/centeraway)
/obj/machinery/gateway/centerstation/update_icon()
if(active)
icon_state = "oncenter"
return
icon_state = "offcenter"
/obj/machinery/gateway/centerstation/process()
if((stat & (NOPOWER)) && use_power)
if(active)
toggleoff()
return
if(active)
use_power(5000)
/obj/machinery/gateway/centerstation/toggleon(mob/user)
if(!detect())
return
if(!powered())
return
if(!awaygate)
to_chat(user, "<span class='notice'>Error: No destination found.</span>")
return
if(world.time < wait)
to_chat(user, "<span class='notice'>Error: Warpspace triangulation in progress. Estimated time to completion: [round(((wait - world.time) / 10) / 60)] minutes.</span>")
return
for(var/obj/machinery/gateway/G in linked)
G.active = 1
G.update_icon()
active = 1
update_icon()
//okay, here's the good teleporting stuff
/obj/machinery/gateway/centerstation/Bumped(atom/movable/AM)
if(!active)
return
if(!detect())
return
if(!awaygate || QDELETED(awaygate))
return
if(awaygate.calibrated)
AM.forceMove(get_step(awaygate.loc, SOUTH))
AM.setDir(SOUTH)
if (ismob(AM))
var/mob/M = AM
if (M.client)
M.client.move_delay = max(world.time + 5, M.client.move_delay)
return
else
var/obj/effect/landmark/dest = pick(randomspawns)
if(dest)
AM.forceMove(get_turf(dest))
AM.setDir(SOUTH)
use_power(5000)
return
/obj/machinery/gateway/centeraway/attackby(obj/item/device/W, mob/user, params)
if(istype(W,/obj/item/device/multitool))
if(calibrated)
to_chat(user, "\black The gate is already calibrated, there is no work for you to do here.")
return
else
to_chat(user, "<span class='boldnotice'>Recalibration successful!</span>: \black This gate's systems have been fine tuned. Travel to this gate will now be on target.")
calibrated = TRUE
return
/////////////////////////////////////Away////////////////////////
/obj/machinery/gateway/centeraway
density = TRUE
icon_state = "offcenter"
use_power = FALSE
var/obj/machinery/gateway/centeraway/stationgate = null
can_link = TRUE
/obj/machinery/gateway/centeraway/Initialize()
..()
update_icon()
stationgate = locate(/obj/machinery/gateway/centerstation)
/obj/machinery/gateway/centeraway/update_icon()
if(active)
icon_state = "oncenter"
return
icon_state = "offcenter"
/obj/machinery/gateway/centeraway/toggleon(mob/user)
if(!detect())
return
if(!stationgate)
to_chat(user, "<span class='notice'>Error: No destination found.</span>")
return
for(var/obj/machinery/gateway/G in linked)
G.active = 1
G.update_icon()
active = 1
update_icon()
/obj/machinery/gateway/centeraway/proc/check_exile_implant(mob/living/carbon/C)
for(var/obj/item/weapon/implant/exile/E in C.implants)//Checking that there is an exile implant
to_chat(C, "\black The station gate has detected your exile implant and is blocking your entry.")
return TRUE
return FALSE
/obj/machinery/gateway/centeraway/Bumped(atom/movable/AM)
if(!detect())
return
if(!active)
return
if(!stationgate || QDELETED(stationgate))
return
if(istype(AM, /mob/living/carbon))
if(check_exile_implant(AM))
return
else
for(var/mob/living/carbon/C in AM.contents)
if(check_exile_implant(C))
say("Rejecting [AM]: Exile implant detected in contained lifeform.")
return
if(AM.has_buckled_mobs())
for(var/mob/living/carbon/C in AM.buckled_mobs)
if(check_exile_implant(C))
say("Rejecting [AM]: Exile implant detected in close proximity lifeform.")
return
AM.forceMove(get_step(stationgate.loc, SOUTH))
AM.setDir(SOUTH)
if (ismob(AM))
var/mob/M = AM
if (M.client)
M.client.move_delay = max(world.time + 5, M.client.move_delay)
GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation)
/obj/machinery/gateway
name = "gateway"
desc = "A mysterious gateway built by unknown hands, it allows for faster than light travel to far-flung locations."
icon = 'icons/obj/machines/gateway.dmi'
icon_state = "off"
density = 1
anchored = 1
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/active = 0
var/checkparts = TRUE
var/list/obj/effect/landmark/randomspawns = list()
var/calibrated = TRUE
var/list/linked = list()
var/can_link = FALSE //Is this the centerpiece?
/obj/machinery/gateway/Initialize()
randomspawns = GLOB.awaydestinations
update_icon()
if(!istype(src, /obj/machinery/gateway/centerstation) && !istype(src, /obj/machinery/gateway/centeraway))
switch(dir)
if(SOUTH,SOUTHEAST,SOUTHWEST)
density = 0
..()
/obj/machinery/gateway/proc/toggleoff()
for(var/obj/machinery/gateway/G in linked)
G.active = 0
G.update_icon()
active = 0
update_icon()
/obj/machinery/gateway/proc/detect()
if(!can_link)
return FALSE
linked = list() //clear the list
var/turf/T = loc
var/ready = FALSE
for(var/i in GLOB.alldirs)
T = get_step(loc, i)
var/obj/machinery/gateway/G = locate(/obj/machinery/gateway) in T
if(G)
linked.Add(G)
continue
//this is only done if we fail to find a part
ready = FALSE
toggleoff()
break
if((linked.len == 8) || !checkparts)
ready = TRUE
return ready
/obj/machinery/gateway/update_icon()
if(active)
icon_state = "on"
return
icon_state = "off"
//prevents shuttles attempting to rotate this since it messes up sprites
/obj/machinery/gateway/shuttleRotate()
return
/obj/machinery/gateway/attack_hand(mob/user)
if(!detect())
return
if(!active)
toggleon(user)
return
toggleoff()
/obj/machinery/gateway/proc/toggleon(mob/user)
return FALSE
/obj/machinery/gateway/centerstation/New()
..()
if(!GLOB.the_gateway)
GLOB.the_gateway = src
/obj/machinery/gateway/centerstation/Destroy()
if(GLOB.the_gateway == src)
GLOB.the_gateway = null
return ..()
//this is da important part wot makes things go
/obj/machinery/gateway/centerstation
density = TRUE
icon_state = "offcenter"
use_power = TRUE
//warping vars
var/wait = 0 //this just grabs world.time at world start
var/obj/machinery/gateway/centeraway/awaygate = null
can_link = TRUE
/obj/machinery/gateway/centerstation/Initialize()
..()
update_icon()
wait = world.time + config.gateway_delay //+ thirty minutes default
awaygate = locate(/obj/machinery/gateway/centeraway)
/obj/machinery/gateway/centerstation/update_icon()
if(active)
icon_state = "oncenter"
return
icon_state = "offcenter"
/obj/machinery/gateway/centerstation/process()
if((stat & (NOPOWER)) && use_power)
if(active)
toggleoff()
return
if(active)
use_power(5000)
/obj/machinery/gateway/centerstation/toggleon(mob/user)
if(!detect())
return
if(!powered())
return
if(!awaygate)
to_chat(user, "<span class='notice'>Error: No destination found.</span>")
return
if(world.time < wait)
to_chat(user, "<span class='notice'>Error: Warpspace triangulation in progress. Estimated time to completion: [round(((wait - world.time) / 10) / 60)] minutes.</span>")
return
for(var/obj/machinery/gateway/G in linked)
G.active = 1
G.update_icon()
active = 1
update_icon()
//okay, here's the good teleporting stuff
/obj/machinery/gateway/centerstation/Bumped(atom/movable/AM)
if(!active)
return
if(!detect())
return
if(!awaygate || QDELETED(awaygate))
return
if(awaygate.calibrated)
AM.forceMove(get_step(awaygate.loc, SOUTH))
AM.setDir(SOUTH)
if (ismob(AM))
var/mob/M = AM
if (M.client)
M.client.move_delay = max(world.time + 5, M.client.move_delay)
return
else
var/obj/effect/landmark/dest = pick(randomspawns)
if(dest)
AM.forceMove(get_turf(dest))
AM.setDir(SOUTH)
use_power(5000)
return
/obj/machinery/gateway/centeraway/attackby(obj/item/device/W, mob/user, params)
if(istype(W,/obj/item/device/multitool))
if(calibrated)
to_chat(user, "\black The gate is already calibrated, there is no work for you to do here.")
return
else
to_chat(user, "<span class='boldnotice'>Recalibration successful!</span>: \black This gate's systems have been fine tuned. Travel to this gate will now be on target.")
calibrated = TRUE
return
/////////////////////////////////////Away////////////////////////
/obj/machinery/gateway/centeraway
density = TRUE
icon_state = "offcenter"
use_power = FALSE
var/obj/machinery/gateway/centeraway/stationgate = null
can_link = TRUE
/obj/machinery/gateway/centeraway/Initialize()
..()
update_icon()
stationgate = locate(/obj/machinery/gateway/centerstation)
/obj/machinery/gateway/centeraway/update_icon()
if(active)
icon_state = "oncenter"
return
icon_state = "offcenter"
/obj/machinery/gateway/centeraway/toggleon(mob/user)
if(!detect())
return
if(!stationgate)
to_chat(user, "<span class='notice'>Error: No destination found.</span>")
return
for(var/obj/machinery/gateway/G in linked)
G.active = 1
G.update_icon()
active = 1
update_icon()
/obj/machinery/gateway/centeraway/proc/check_exile_implant(mob/living/carbon/C)
for(var/obj/item/weapon/implant/exile/E in C.implants)//Checking that there is an exile implant
to_chat(C, "\black The station gate has detected your exile implant and is blocking your entry.")
return TRUE
return FALSE
/obj/machinery/gateway/centeraway/Bumped(atom/movable/AM)
if(!detect())
return
if(!active)
return
if(!stationgate || QDELETED(stationgate))
return
if(istype(AM, /mob/living/carbon))
if(check_exile_implant(AM))
return
else
for(var/mob/living/carbon/C in AM.contents)
if(check_exile_implant(C))
say("Rejecting [AM]: Exile implant detected in contained lifeform.")
return
if(AM.has_buckled_mobs())
for(var/mob/living/carbon/C in AM.buckled_mobs)
if(check_exile_implant(C))
say("Rejecting [AM]: Exile implant detected in close proximity lifeform.")
return
AM.forceMove(get_step(stationgate.loc, SOUTH))
AM.setDir(SOUTH)
if (ismob(AM))
var/mob/M = AM
if (M.client)
M.client.move_delay = max(world.time + 5, M.client.move_delay)
+147 -147
View File
@@ -1,147 +1,147 @@
//Hat Station 13
/obj/item/clothing/head/collectable
name = "collectable hat"
desc = "A rare collectable hat."
/obj/item/clothing/head/collectable/petehat
name = "ultra rare Pete's hat!"
desc = "It smells faintly of plasma."
icon_state = "petehat"
/obj/item/clothing/head/collectable/slime
name = "collectable slime cap!"
desc = "It just latches right in place!"
icon_state = "slime"
/obj/item/clothing/head/collectable/xenom
name = "collectable xenomorph helmet!"
desc = "Hiss hiss hiss!"
icon_state = "xenom"
/obj/item/clothing/head/collectable/chef
name = "collectable chef's hat"
desc = "A rare chef's hat meant for hat collectors!"
icon_state = "chef"
item_state = "chef"
dog_fashion = /datum/dog_fashion/head/chef
/obj/item/clothing/head/collectable/paper
name = "collectable paper hat"
desc = "What looks like an ordinary paper hat is actually a rare and valuable collector's edition paper hat. Keep away from water, fire, and Curators."
icon_state = "paper"
dog_fashion = /datum/dog_fashion/head
/obj/item/clothing/head/collectable/tophat
name = "collectable top hat"
desc = "A top hat worn by only the most prestigious hat collectors."
icon_state = "tophat"
item_state = "that"
/obj/item/clothing/head/collectable/captain
name = "collectable captain's hat"
desc = "A collectable hat that'll make you look just like a real comdom!"
icon_state = "captain"
item_state = "caphat"
dog_fashion = /datum/dog_fashion/head/captain
/obj/item/clothing/head/collectable/police
name = "collectable police officer's hat"
desc = "A collectable police officer's Hat. This hat emphasizes that you are THE LAW."
icon_state = "policehelm"
dog_fashion = /datum/dog_fashion/head/warden
/obj/item/clothing/head/collectable/beret
name = "collectable beret"
desc = "A collectable red beret. It smells faintly of garlic."
icon_state = "beret"
dog_fashion = /datum/dog_fashion/head/beret
/obj/item/clothing/head/collectable/welding
name = "collectable welding helmet"
desc = "A collectable welding helmet. Now with 80% less lead! Not for actual welding. Any welding done while wearing this helmet is done so at the owner's own risk!"
icon_state = "welding"
item_state = "welding"
resistance_flags = 0
/obj/item/clothing/head/collectable/slime
name = "collectable slime hat"
desc = "Just like a real brain slug!"
icon_state = "headslime"
item_state = "headslime"
/obj/item/clothing/head/collectable/flatcap
name = "collectable flat cap"
desc = "A collectible farmer's flat cap!"
icon_state = "flat_cap"
item_state = "detective"
/obj/item/clothing/head/collectable/pirate
name = "collectable pirate hat"
desc = "You'd make a great Dread Syndie Roberts!"
icon_state = "pirate"
item_state = "pirate"
dog_fashion = /datum/dog_fashion/head/pirate
/obj/item/clothing/head/collectable/kitty
name = "collectable kitty ears"
desc = "The fur feels... a bit too realistic."
icon_state = "kitty"
item_state = "kitty"
dog_fashion = /datum/dog_fashion/head/kitty
/obj/item/clothing/head/collectable/rabbitears
name = "collectable rabbit ears"
desc = "Not as lucky as the feet!"
icon_state = "bunny"
item_state = "bunny"
dog_fashion = /datum/dog_fashion/head/rabbit
/obj/item/clothing/head/collectable/wizard
name = "collectable wizard's hat"
desc = "NOTE: Any magical powers gained from wearing this hat are purely coincidental."
icon_state = "wizard"
dog_fashion = /datum/dog_fashion/head/blue_wizard
/obj/item/clothing/head/collectable/hardhat
name = "collectable hard hat"
desc = "WARNING! Offers no real protection, or luminosity, but damn, is it fancy!"
icon_state = "hardhat0_yellow"
item_state = "hardhat0_yellow"
dog_fashion = /datum/dog_fashion/head
/obj/item/clothing/head/collectable/HoS
name = "collectable HoS hat"
desc = "Now you too can beat prisoners, set silly sentences, and arrest for no reason!"
icon_state = "hoscap"
/obj/item/clothing/head/collectable/HoP
name = "collectable HoP hat"
desc = "It's your turn to demand excessive paperwork, signatures, stamps, and hire more clowns! Papers, please!"
icon_state = "hopcap"
dog_fashion = /datum/dog_fashion/head/hop
/obj/item/clothing/head/collectable/thunderdome
name = "collectable Thunderdome helmet"
desc = "Go Red! I mean Green! I mean Red! No Green!"
icon_state = "thunderdome"
item_state = "thunderdome"
resistance_flags = 0
/obj/item/clothing/head/collectable/swat
name = "collectable SWAT helmet"
desc = "That's not real blood. That's red paint." //Reference to the actual description
icon_state = "swat"
item_state = "swat"
resistance_flags = 0
//Hat Station 13
/obj/item/clothing/head/collectable
name = "collectable hat"
desc = "A rare collectable hat."
/obj/item/clothing/head/collectable/petehat
name = "ultra rare Pete's hat!"
desc = "It smells faintly of plasma."
icon_state = "petehat"
/obj/item/clothing/head/collectable/slime
name = "collectable slime cap!"
desc = "It just latches right in place!"
icon_state = "slime"
/obj/item/clothing/head/collectable/xenom
name = "collectable xenomorph helmet!"
desc = "Hiss hiss hiss!"
icon_state = "xenom"
/obj/item/clothing/head/collectable/chef
name = "collectable chef's hat"
desc = "A rare chef's hat meant for hat collectors!"
icon_state = "chef"
item_state = "chef"
dog_fashion = /datum/dog_fashion/head/chef
/obj/item/clothing/head/collectable/paper
name = "collectable paper hat"
desc = "What looks like an ordinary paper hat is actually a rare and valuable collector's edition paper hat. Keep away from water, fire, and Curators."
icon_state = "paper"
dog_fashion = /datum/dog_fashion/head
/obj/item/clothing/head/collectable/tophat
name = "collectable top hat"
desc = "A top hat worn by only the most prestigious hat collectors."
icon_state = "tophat"
item_state = "that"
/obj/item/clothing/head/collectable/captain
name = "collectable captain's hat"
desc = "A collectable hat that'll make you look just like a real comdom!"
icon_state = "captain"
item_state = "caphat"
dog_fashion = /datum/dog_fashion/head/captain
/obj/item/clothing/head/collectable/police
name = "collectable police officer's hat"
desc = "A collectable police officer's Hat. This hat emphasizes that you are THE LAW."
icon_state = "policehelm"
dog_fashion = /datum/dog_fashion/head/warden
/obj/item/clothing/head/collectable/beret
name = "collectable beret"
desc = "A collectable red beret. It smells faintly of garlic."
icon_state = "beret"
dog_fashion = /datum/dog_fashion/head/beret
/obj/item/clothing/head/collectable/welding
name = "collectable welding helmet"
desc = "A collectable welding helmet. Now with 80% less lead! Not for actual welding. Any welding done while wearing this helmet is done so at the owner's own risk!"
icon_state = "welding"
item_state = "welding"
resistance_flags = 0
/obj/item/clothing/head/collectable/slime
name = "collectable slime hat"
desc = "Just like a real brain slug!"
icon_state = "headslime"
item_state = "headslime"
/obj/item/clothing/head/collectable/flatcap
name = "collectable flat cap"
desc = "A collectible farmer's flat cap!"
icon_state = "flat_cap"
item_state = "detective"
/obj/item/clothing/head/collectable/pirate
name = "collectable pirate hat"
desc = "You'd make a great Dread Syndie Roberts!"
icon_state = "pirate"
item_state = "pirate"
dog_fashion = /datum/dog_fashion/head/pirate
/obj/item/clothing/head/collectable/kitty
name = "collectable kitty ears"
desc = "The fur feels... a bit too realistic."
icon_state = "kitty"
item_state = "kitty"
dog_fashion = /datum/dog_fashion/head/kitty
/obj/item/clothing/head/collectable/rabbitears
name = "collectable rabbit ears"
desc = "Not as lucky as the feet!"
icon_state = "bunny"
item_state = "bunny"
dog_fashion = /datum/dog_fashion/head/rabbit
/obj/item/clothing/head/collectable/wizard
name = "collectable wizard's hat"
desc = "NOTE: Any magical powers gained from wearing this hat are purely coincidental."
icon_state = "wizard"
dog_fashion = /datum/dog_fashion/head/blue_wizard
/obj/item/clothing/head/collectable/hardhat
name = "collectable hard hat"
desc = "WARNING! Offers no real protection, or luminosity, but damn, is it fancy!"
icon_state = "hardhat0_yellow"
item_state = "hardhat0_yellow"
dog_fashion = /datum/dog_fashion/head
/obj/item/clothing/head/collectable/HoS
name = "collectable HoS hat"
desc = "Now you too can beat prisoners, set silly sentences, and arrest for no reason!"
icon_state = "hoscap"
/obj/item/clothing/head/collectable/HoP
name = "collectable HoP hat"
desc = "It's your turn to demand excessive paperwork, signatures, stamps, and hire more clowns! Papers, please!"
icon_state = "hopcap"
dog_fashion = /datum/dog_fashion/head/hop
/obj/item/clothing/head/collectable/thunderdome
name = "collectable Thunderdome helmet"
desc = "Go Red! I mean Green! I mean Red! No Green!"
icon_state = "thunderdome"
item_state = "thunderdome"
resistance_flags = 0
/obj/item/clothing/head/collectable/swat
name = "collectable SWAT helmet"
desc = "That's not real blood. That's red paint." //Reference to the actual description
icon_state = "swat"
item_state = "swat"
resistance_flags = 0
+172 -172
View File
@@ -1,172 +1,172 @@
//CONTAINS: Detective's Scanner
// TODO: Split everything into easy to manage procs.
/obj/item/device/detective_scanner
name = "forensic scanner"
desc = "Used to remotely scan objects and biomass for DNA and fingerprints. Can print a report of the findings."
icon_state = "forensicnew"
w_class = WEIGHT_CLASS_SMALL
item_state = "electronic"
flags = CONDUCT | NOBLUDGEON
slot_flags = SLOT_BELT
var/scanning = 0
var/list/log = list()
origin_tech = "engineering=4;biotech=2;programming=5"
var/range = 8
var/view_check = TRUE
/obj/item/device/detective_scanner/attack_self(mob/user)
if(log.len && !scanning)
scanning = 1
to_chat(user, "<span class='notice'>Printing report, please wait...</span>")
addtimer(CALLBACK(src, .proc/PrintReport), 100)
else
to_chat(user, "<span class='notice'>The scanner has no logs or is in use.</span>")
/obj/item/device/detective_scanner/attack(mob/living/M, mob/user)
return
/obj/item/device/detective_scanner/proc/PrintReport()
// Create our paper
var/obj/item/weapon/paper/P = new(get_turf(src))
P.name = "paper- 'Scanner Report'"
P.info = "<center><font size='6'><B>Scanner Report</B></font></center><HR><BR>"
P.info += jointext(log, "<BR>")
P.info += "<HR><B>Notes:</B><BR>"
P.info_links = P.info
if(ismob(loc))
var/mob/M = loc
M.put_in_hands(P)
to_chat(M, "<span class='notice'>Report printed. Log cleared.<span>")
// Clear the logs
log = list()
scanning = 0
/obj/item/device/detective_scanner/afterattack(atom/A, mob/user, params)
scan(A, user)
return FALSE
/obj/item/device/detective_scanner/proc/scan(atom/A, mob/user)
set waitfor = 0
if(!scanning)
// Can remotely scan objects and mobs.
if((get_dist(A, user) > range) || (!(A in view(range, user)) && view_check) || (loc != user))
return
scanning = 1
user.visible_message("\The [user] points the [src.name] at \the [A] and performs a forensic scan.")
to_chat(user, "<span class='notice'>You scan \the [A]. The scanner is now analysing the results...</span>")
// GATHER INFORMATION
//Make our lists
var/list/fingerprints = list()
var/list/blood = list()
var/list/fibers = list()
var/list/reagents = list()
var/target_name = A.name
// Start gathering
if(A.blood_DNA && A.blood_DNA.len)
blood = A.blood_DNA.Copy()
if(A.suit_fibers && A.suit_fibers.len)
fibers = A.suit_fibers.Copy()
if(ishuman(A))
var/mob/living/carbon/human/H = A
if(!H.gloves)
fingerprints += md5(H.dna.uni_identity)
else if(!ismob(A))
if(A.fingerprints && A.fingerprints.len)
fingerprints = A.fingerprints.Copy()
// Only get reagents from non-mobs.
if(A.reagents && A.reagents.reagent_list.len)
for(var/datum/reagent/R in A.reagents.reagent_list)
reagents[R.name] = R.volume
// Get blood data from the blood reagent.
if(istype(R, /datum/reagent/blood))
if(R.data["blood_DNA"] && R.data["blood_type"])
var/blood_DNA = R.data["blood_DNA"]
var/blood_type = R.data["blood_type"]
blood[blood_DNA] = blood_type
// We gathered everything. Create a fork and slowly display the results to the holder of the scanner.
var/found_something = 0
add_log("<B>[worldtime2text()][get_timestamp()] - [target_name]</B>", 0)
// Fingerprints
if(fingerprints && fingerprints.len)
sleep(30)
add_log("<span class='info'><B>Prints:</B></span>")
for(var/finger in fingerprints)
add_log("[finger]")
found_something = 1
// Blood
if (blood && blood.len)
sleep(30)
add_log("<span class='info'><B>Blood:</B></span>")
found_something = 1
for(var/B in blood)
add_log("Type: <font color='red'>[blood[B]]</font> DNA: <font color='red'>[B]</font>")
//Fibers
if(fibers && fibers.len)
sleep(30)
add_log("<span class='info'><B>Fibers:</B></span>")
for(var/fiber in fibers)
add_log("[fiber]")
found_something = 1
//Reagents
if(reagents && reagents.len)
sleep(30)
add_log("<span class='info'><B>Reagents:</B></span>")
for(var/R in reagents)
add_log("Reagent: <font color='red'>[R]</font> Volume: <font color='red'>[reagents[R]]</font>")
found_something = 1
// Get a new user
var/mob/holder = null
if(ismob(src.loc))
holder = src.loc
if(!found_something)
add_log("<I># No forensic traces found #</I>", 0) // Don't display this to the holder user
if(holder)
to_chat(holder, "<span class='warning'>Unable to locate any fingerprints, materials, fibers, or blood on \the [target_name]!</span>")
else
if(holder)
to_chat(holder, "<span class='notice'>You finish scanning \the [target_name].</span>")
add_log("---------------------------------------------------------", 0)
scanning = 0
return
/obj/item/device/detective_scanner/proc/add_log(msg, broadcast = 1)
if(scanning)
if(broadcast && ismob(loc))
var/mob/M = loc
to_chat(M, msg)
log += "&nbsp;&nbsp;[msg]"
else
CRASH("[src] \ref[src] is adding a log when it was never put in scanning mode!")
/proc/get_timestamp()
return time2text(world.time + 432000, ":ss")
//CONTAINS: Detective's Scanner
// TODO: Split everything into easy to manage procs.
/obj/item/device/detective_scanner
name = "forensic scanner"
desc = "Used to remotely scan objects and biomass for DNA and fingerprints. Can print a report of the findings."
icon_state = "forensicnew"
w_class = WEIGHT_CLASS_SMALL
item_state = "electronic"
flags = CONDUCT | NOBLUDGEON
slot_flags = SLOT_BELT
var/scanning = 0
var/list/log = list()
origin_tech = "engineering=4;biotech=2;programming=5"
var/range = 8
var/view_check = TRUE
/obj/item/device/detective_scanner/attack_self(mob/user)
if(log.len && !scanning)
scanning = 1
to_chat(user, "<span class='notice'>Printing report, please wait...</span>")
addtimer(CALLBACK(src, .proc/PrintReport), 100)
else
to_chat(user, "<span class='notice'>The scanner has no logs or is in use.</span>")
/obj/item/device/detective_scanner/attack(mob/living/M, mob/user)
return
/obj/item/device/detective_scanner/proc/PrintReport()
// Create our paper
var/obj/item/weapon/paper/P = new(get_turf(src))
P.name = "paper- 'Scanner Report'"
P.info = "<center><font size='6'><B>Scanner Report</B></font></center><HR><BR>"
P.info += jointext(log, "<BR>")
P.info += "<HR><B>Notes:</B><BR>"
P.info_links = P.info
if(ismob(loc))
var/mob/M = loc
M.put_in_hands(P)
to_chat(M, "<span class='notice'>Report printed. Log cleared.<span>")
// Clear the logs
log = list()
scanning = 0
/obj/item/device/detective_scanner/afterattack(atom/A, mob/user, params)
scan(A, user)
return FALSE
/obj/item/device/detective_scanner/proc/scan(atom/A, mob/user)
set waitfor = 0
if(!scanning)
// Can remotely scan objects and mobs.
if((get_dist(A, user) > range) || (!(A in view(range, user)) && view_check) || (loc != user))
return
scanning = 1
user.visible_message("\The [user] points the [src.name] at \the [A] and performs a forensic scan.")
to_chat(user, "<span class='notice'>You scan \the [A]. The scanner is now analysing the results...</span>")
// GATHER INFORMATION
//Make our lists
var/list/fingerprints = list()
var/list/blood = list()
var/list/fibers = list()
var/list/reagents = list()
var/target_name = A.name
// Start gathering
if(A.blood_DNA && A.blood_DNA.len)
blood = A.blood_DNA.Copy()
if(A.suit_fibers && A.suit_fibers.len)
fibers = A.suit_fibers.Copy()
if(ishuman(A))
var/mob/living/carbon/human/H = A
if(!H.gloves)
fingerprints += md5(H.dna.uni_identity)
else if(!ismob(A))
if(A.fingerprints && A.fingerprints.len)
fingerprints = A.fingerprints.Copy()
// Only get reagents from non-mobs.
if(A.reagents && A.reagents.reagent_list.len)
for(var/datum/reagent/R in A.reagents.reagent_list)
reagents[R.name] = R.volume
// Get blood data from the blood reagent.
if(istype(R, /datum/reagent/blood))
if(R.data["blood_DNA"] && R.data["blood_type"])
var/blood_DNA = R.data["blood_DNA"]
var/blood_type = R.data["blood_type"]
blood[blood_DNA] = blood_type
// We gathered everything. Create a fork and slowly display the results to the holder of the scanner.
var/found_something = 0
add_log("<B>[worldtime2text()][get_timestamp()] - [target_name]</B>", 0)
// Fingerprints
if(fingerprints && fingerprints.len)
sleep(30)
add_log("<span class='info'><B>Prints:</B></span>")
for(var/finger in fingerprints)
add_log("[finger]")
found_something = 1
// Blood
if (blood && blood.len)
sleep(30)
add_log("<span class='info'><B>Blood:</B></span>")
found_something = 1
for(var/B in blood)
add_log("Type: <font color='red'>[blood[B]]</font> DNA: <font color='red'>[B]</font>")
//Fibers
if(fibers && fibers.len)
sleep(30)
add_log("<span class='info'><B>Fibers:</B></span>")
for(var/fiber in fibers)
add_log("[fiber]")
found_something = 1
//Reagents
if(reagents && reagents.len)
sleep(30)
add_log("<span class='info'><B>Reagents:</B></span>")
for(var/R in reagents)
add_log("Reagent: <font color='red'>[R]</font> Volume: <font color='red'>[reagents[R]]</font>")
found_something = 1
// Get a new user
var/mob/holder = null
if(ismob(src.loc))
holder = src.loc
if(!found_something)
add_log("<I># No forensic traces found #</I>", 0) // Don't display this to the holder user
if(holder)
to_chat(holder, "<span class='warning'>Unable to locate any fingerprints, materials, fibers, or blood on \the [target_name]!</span>")
else
if(holder)
to_chat(holder, "<span class='notice'>You finish scanning \the [target_name].</span>")
add_log("---------------------------------------------------------", 0)
scanning = 0
return
/obj/item/device/detective_scanner/proc/add_log(msg, broadcast = 1)
if(scanning)
if(broadcast && ismob(loc))
var/mob/M = loc
to_chat(M, msg)
log += "&nbsp;&nbsp;[msg]"
else
CRASH("[src] \ref[src] is adding a log when it was never put in scanning mode!")
/proc/get_timestamp()
return time2text(world.time + 432000, ":ss")
+481 -481
View File
@@ -1,481 +1,481 @@
GLOBAL_VAR_CONST(access_security, 1) // Security equipment
GLOBAL_VAR_CONST(access_brig, 2) // Brig timers and permabrig
GLOBAL_VAR_CONST(access_armory, 3)
GLOBAL_VAR_CONST(access_forensics_lockers, 4)
GLOBAL_VAR_CONST(access_medical, 5)
GLOBAL_VAR_CONST(access_morgue, 6)
GLOBAL_VAR_CONST(access_tox, 7)
GLOBAL_VAR_CONST(access_tox_storage, 8)
GLOBAL_VAR_CONST(access_genetics, 9)
GLOBAL_VAR_CONST(access_engine, 10)
GLOBAL_VAR_CONST(access_engine_equip, 11)
GLOBAL_VAR_CONST(access_maint_tunnels, 12)
GLOBAL_VAR_CONST(access_external_airlocks, 13)
GLOBAL_VAR_CONST(access_emergency_storage, 14)
GLOBAL_VAR_CONST(access_change_ids, 15)
GLOBAL_VAR_CONST(access_ai_upload, 16)
GLOBAL_VAR_CONST(access_teleporter, 17)
GLOBAL_VAR_CONST(access_eva, 18)
GLOBAL_VAR_CONST(access_heads, 19)
GLOBAL_VAR_CONST(access_captain, 20)
GLOBAL_VAR_CONST(access_all_personal_lockers, 21)
GLOBAL_VAR_CONST(access_chapel_office, 22)
GLOBAL_VAR_CONST(access_tech_storage, 23)
GLOBAL_VAR_CONST(access_atmospherics, 24)
GLOBAL_VAR_CONST(access_bar, 25)
GLOBAL_VAR_CONST(access_janitor, 26)
GLOBAL_VAR_CONST(access_crematorium, 27)
GLOBAL_VAR_CONST(access_kitchen, 28)
GLOBAL_VAR_CONST(access_robotics, 29)
GLOBAL_VAR_CONST(access_rd, 30)
GLOBAL_VAR_CONST(access_cargo, 31)
GLOBAL_VAR_CONST(access_construction, 32)
GLOBAL_VAR_CONST(access_chemistry, 33)
GLOBAL_VAR_CONST(access_cargo_bot, 34)
GLOBAL_VAR_CONST(access_hydroponics, 35)
GLOBAL_VAR_CONST(access_manufacturing, 36)
GLOBAL_VAR_CONST(access_library, 37)
GLOBAL_VAR_CONST(access_lawyer, 38)
GLOBAL_VAR_CONST(access_virology, 39)
GLOBAL_VAR_CONST(access_cmo, 40)
GLOBAL_VAR_CONST(access_qm, 41)
GLOBAL_VAR_CONST(access_court, 42)
GLOBAL_VAR_CONST(access_surgery, 45)
GLOBAL_VAR_CONST(access_theatre, 46)
GLOBAL_VAR_CONST(access_research, 47)
GLOBAL_VAR_CONST(access_mining, 48)
GLOBAL_VAR_CONST(access_mining_office, 49) //not in use
GLOBAL_VAR_CONST(access_mailsorting, 50)
GLOBAL_VAR_CONST(access_mint, 51)
GLOBAL_VAR_CONST(access_mint_vault, 52)
GLOBAL_VAR_CONST(access_heads_vault, 53)
GLOBAL_VAR_CONST(access_mining_station, 54)
GLOBAL_VAR_CONST(access_xenobiology, 55)
GLOBAL_VAR_CONST(access_ce, 56)
GLOBAL_VAR_CONST(access_hop, 57)
GLOBAL_VAR_CONST(access_hos, 58)
GLOBAL_VAR_CONST(access_RC_announce, 59) //Request console announcements
GLOBAL_VAR_CONST(access_keycard_auth, 60) //Used for events which require at least two people to confirm them
GLOBAL_VAR_CONST(access_tcomsat, 61) // has access to the entire telecomms satellite / machinery
GLOBAL_VAR_CONST(access_gateway, 62)
GLOBAL_VAR_CONST(access_sec_doors, 63) // Security front doors
GLOBAL_VAR_CONST(access_mineral_storeroom, 64)
GLOBAL_VAR_CONST(access_minisat, 65)
GLOBAL_VAR_CONST(access_weapons, 66) //Weapon authorization for secbots
GLOBAL_VAR_CONST(access_network, 67)
GLOBAL_VAR_CONST(access_cloning, 68) //Cloning room
//BEGIN CENTCOM ACCESS
/*Should leave plenty of room if we need to add more access levels.
Mostly for admin fun times.*/
GLOBAL_VAR_CONST(access_cent_general, 101)//General facilities.
GLOBAL_VAR_CONST(access_cent_thunder, 102)//Thunderdome.
GLOBAL_VAR_CONST(access_cent_specops, 103)//Special Ops.
GLOBAL_VAR_CONST(access_cent_medical, 104)//Medical/Research
GLOBAL_VAR_CONST(access_cent_living, 105)//Living quarters.
GLOBAL_VAR_CONST(access_cent_storage, 106)//Generic storage areas.
GLOBAL_VAR_CONST(access_cent_teleporter, 107)//Teleporter.
GLOBAL_VAR_CONST(access_cent_captain, 109)//Captain's office/ID comp/AI.
GLOBAL_VAR_CONST(access_cent_bar, 110) // The non-existent Centcom Bar
//The Syndicate
GLOBAL_VAR_CONST(access_syndicate, 150)//General Syndicate Access
GLOBAL_VAR_CONST(access_syndicate_leader, 151)//Nuke Op Leader Access
//Away Missions or Ruins
/*For generic away-mission/ruin access. Why would normal crew have access to a long-abandoned derelict
or a 2000 year-old temple? */
GLOBAL_VAR_CONST(access_away_general, 200)//General facilities.
GLOBAL_VAR_CONST(access_away_maint, 201)//Away maintenance
GLOBAL_VAR_CONST(access_away_med, 202)//Away medical
GLOBAL_VAR_CONST(access_away_sec, 203)//Away security
GLOBAL_VAR_CONST(access_away_engine, 204)//Away engineering
GLOBAL_VAR_CONST(access_away_generic1, 205)//Away generic access
GLOBAL_VAR_CONST(access_away_generic2, 206)
GLOBAL_VAR_CONST(access_away_generic3, 207)
GLOBAL_VAR_CONST(access_away_generic4, 208)
/obj/var/list/req_access = null
/obj/var/req_access_txt = "0"
/obj/var/list/req_one_access = null
/obj/var/req_one_access_txt = "0"
//returns 1 if this mob has sufficient access to use this object
/obj/proc/allowed(mob/M)
//check if it doesn't require any access at all
if(src.check_access(null))
return TRUE
if(issilicon(M))
if(ispAI(M))
return FALSE
return TRUE //AI can do whatever it wants
if(IsAdminGhost(M))
//Access can't stop the abuse
return TRUE
else if(ishuman(M))
var/mob/living/carbon/human/H = M
//if they are holding or wearing a card that has access, that works
if(check_access(H.get_active_held_item()) || src.check_access(H.wear_id))
return TRUE
else if(ismonkey(M) || isalienadult(M))
var/mob/living/carbon/george = M
//they can only hold things :(
if(check_access(george.get_active_held_item()))
return TRUE
else if(isanimal(M))
var/mob/living/simple_animal/A = M
if(check_access(A.get_active_held_item()) || check_access(A.access_card))
return TRUE
return FALSE
/obj/item/proc/GetAccess()
return list()
/obj/item/proc/GetID()
return null
//Call this before using req_access or req_one_access directly
/obj/proc/gen_access()
//These generations have been moved out of /obj/New() because they were slowing down the creation of objects that never even used the access system.
if(!src.req_access)
src.req_access = list()
if(src.req_access_txt)
var/list/req_access_str = splittext(req_access_txt,";")
for(var/x in req_access_str)
var/n = text2num(x)
if(n)
req_access += n
if(!src.req_one_access)
src.req_one_access = list()
if(src.req_one_access_txt)
var/list/req_one_access_str = splittext(req_one_access_txt,";")
for(var/x in req_one_access_str)
var/n = text2num(x)
if(n)
req_one_access += n
/obj/proc/check_access(obj/item/I)
gen_access()
if(!istype(src.req_access, /list)) //something's very wrong
return TRUE
var/list/L = src.req_access
if(!L.len && (!src.req_one_access || !src.req_one_access.len)) //no requirements
return TRUE
if(!I)
return FALSE
for(var/req in src.req_access)
if(!(req in I.GetAccess())) //doesn't have this access
return FALSE
if(src.req_one_access && src.req_one_access.len)
for(var/req in src.req_one_access)
if(req in I.GetAccess()) //has an access from the single access list
return TRUE
return FALSE
return TRUE
/obj/proc/check_access_list(list/L)
if(!src.req_access && !src.req_one_access)
return TRUE
if(!istype(src.req_access, /list))
return TRUE
if(!src.req_access.len && (!src.req_one_access || !src.req_one_access.len))
return TRUE
if(!L)
return FALSE
if(!istype(L, /list))
return FALSE
for(var/req in src.req_access)
if(!(req in L)) //doesn't have this access
return FALSE
if(src.req_one_access && src.req_one_access.len)
for(var/req in src.req_one_access)
if(req in L) //has an access from the single access list
return TRUE
return FALSE
return TRUE
/proc/get_centcom_access(job)
switch(job)
if("VIP Guest")
return list(GLOB.access_cent_general)
if("Custodian")
return list(GLOB.access_cent_general, GLOB.access_cent_living, GLOB.access_cent_storage)
if("Thunderdome Overseer")
return list(GLOB.access_cent_general, GLOB.access_cent_thunder)
if("Centcom Official")
return list(GLOB.access_cent_general, GLOB.access_cent_living)
if("Medical Officer")
return list(GLOB.access_cent_general, GLOB.access_cent_living, GLOB.access_cent_medical)
if("Death Commando")
return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_living, GLOB.access_cent_storage)
if("Research Officer")
return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_medical, GLOB.access_cent_teleporter, GLOB.access_cent_storage)
if("Special Ops Officer")
return list(GLOB.access_cent_general, GLOB.access_cent_thunder, GLOB.access_cent_specops, GLOB.access_cent_living, GLOB.access_cent_storage)
if("Admiral")
return get_all_centcom_access()
if("Centcom Commander")
return get_all_centcom_access()
if("Emergency Response Team Commander")
return get_ert_access("commander")
if("Security Response Officer")
return get_ert_access("sec")
if("Engineer Response Officer")
return get_ert_access("eng")
if("Medical Response Officer")
return get_ert_access("med")
if("Centcom Bartender")
return list(GLOB.access_cent_general, GLOB.access_cent_living, GLOB.access_cent_bar)
/proc/get_all_accesses()
return list(GLOB.access_security, GLOB.access_sec_doors, GLOB.access_brig, GLOB.access_armory, GLOB.access_forensics_lockers, GLOB.access_court,
GLOB.access_medical, GLOB.access_genetics, GLOB.access_morgue, GLOB.access_rd,
GLOB.access_tox, GLOB.access_tox_storage, GLOB.access_chemistry, GLOB.access_engine, GLOB.access_engine_equip, GLOB.access_maint_tunnels,
GLOB.access_external_airlocks, GLOB.access_change_ids, GLOB.access_ai_upload,
GLOB.access_teleporter, GLOB.access_eva, GLOB.access_heads, GLOB.access_captain, GLOB.access_all_personal_lockers,
GLOB.access_tech_storage, GLOB.access_chapel_office, GLOB.access_atmospherics, GLOB.access_kitchen,
GLOB.access_bar, GLOB.access_janitor, GLOB.access_crematorium, GLOB.access_robotics, GLOB.access_cargo, GLOB.access_construction,
GLOB.access_hydroponics, GLOB.access_library, GLOB.access_lawyer, GLOB.access_virology, GLOB.access_cmo, GLOB.access_qm, GLOB.access_surgery,
GLOB.access_theatre, GLOB.access_research, GLOB.access_mining, GLOB.access_mailsorting, GLOB.access_weapons,
GLOB.access_heads_vault, GLOB.access_mining_station, GLOB.access_xenobiology, GLOB.access_ce, GLOB.access_hop, GLOB.access_hos, GLOB.access_RC_announce,
GLOB.access_keycard_auth, GLOB.access_tcomsat, GLOB.access_gateway, GLOB.access_mineral_storeroom, GLOB.access_minisat, GLOB.access_network, GLOB.access_cloning)
/proc/get_all_centcom_access()
return list(GLOB.access_cent_general, GLOB.access_cent_thunder, GLOB.access_cent_specops, GLOB.access_cent_medical, GLOB.access_cent_living, GLOB.access_cent_storage, GLOB.access_cent_teleporter, GLOB.access_cent_captain)
/proc/get_ert_access(class)
switch(class)
if("commander")
return get_all_centcom_access()
if("sec")
return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_living)
if("eng")
return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_living, GLOB.access_cent_storage)
if("med")
return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_medical, GLOB.access_cent_living)
/proc/get_all_syndicate_access()
return list(GLOB.access_syndicate, GLOB.access_syndicate)
/proc/get_region_accesses(code)
switch(code)
if(0)
return get_all_accesses()
if(1) //station general
return list(GLOB.access_kitchen,GLOB.access_bar, GLOB.access_hydroponics, GLOB.access_janitor, GLOB.access_chapel_office, GLOB.access_crematorium, GLOB.access_library, GLOB.access_theatre, GLOB.access_lawyer)
if(2) //security
return list(GLOB.access_sec_doors, GLOB.access_weapons, GLOB.access_security, GLOB.access_brig, GLOB.access_armory, GLOB.access_forensics_lockers, GLOB.access_court, GLOB.access_hos)
if(3) //medbay
return list(GLOB.access_medical, GLOB.access_genetics, GLOB.access_cloning, GLOB.access_morgue, GLOB.access_chemistry, GLOB.access_virology, GLOB.access_surgery, GLOB.access_cmo)
if(4) //research
return list(GLOB.access_research, GLOB.access_tox, GLOB.access_tox_storage, GLOB.access_genetics, GLOB.access_robotics, GLOB.access_xenobiology, GLOB.access_minisat, GLOB.access_rd, GLOB.access_network)
if(5) //engineering and maintenance
return list(GLOB.access_construction, GLOB.access_maint_tunnels, GLOB.access_engine, GLOB.access_engine_equip, GLOB.access_external_airlocks, GLOB.access_tech_storage, GLOB.access_atmospherics, GLOB.access_tcomsat, GLOB.access_minisat, GLOB.access_ce)
if(6) //supply
return list(GLOB.access_mailsorting, GLOB.access_mining, GLOB.access_mining_station, GLOB.access_mineral_storeroom, GLOB.access_cargo, GLOB.access_qm)
if(7) //command
return list(GLOB.access_heads, GLOB.access_RC_announce, GLOB.access_keycard_auth, GLOB.access_change_ids, GLOB.access_ai_upload, GLOB.access_teleporter, GLOB.access_eva, GLOB.access_gateway, GLOB.access_all_personal_lockers, GLOB.access_heads_vault, GLOB.access_hop, GLOB.access_captain)
/proc/get_region_accesses_name(code)
switch(code)
if(0)
return "All"
if(1) //station general
return "General"
if(2) //security
return "Security"
if(3) //medbay
return "Medbay"
if(4) //research
return "Research"
if(5) //engineering and maintenance
return "Engineering"
if(6) //supply
return "Supply"
if(7) //command
return "Command"
/proc/get_access_desc(A)
switch(A)
if(GLOB.access_cargo)
return "Cargo Bay"
if(GLOB.access_cargo_bot)
return "Delivery Chutes"
if(GLOB.access_security)
return "Security"
if(GLOB.access_brig)
return "Holding Cells"
if(GLOB.access_court)
return "Courtroom"
if(GLOB.access_forensics_lockers)
return "Forensics"
if(GLOB.access_medical)
return "Medical"
if(GLOB.access_genetics)
return "Genetics Lab"
if(GLOB.access_morgue)
return "Morgue"
if(GLOB.access_tox)
return "R&D Lab"
if(GLOB.access_tox_storage)
return "Toxins Lab"
if(GLOB.access_chemistry)
return "Chemistry Lab"
if(GLOB.access_rd)
return "RD Office"
if(GLOB.access_bar)
return "Bar"
if(GLOB.access_janitor)
return "Custodial Closet"
if(GLOB.access_engine)
return "Engineering"
if(GLOB.access_engine_equip)
return "Power Equipment"
if(GLOB.access_maint_tunnels)
return "Maintenance"
if(GLOB.access_external_airlocks)
return "External Airlocks"
if(GLOB.access_emergency_storage)
return "Emergency Storage"
if(GLOB.access_change_ids)
return "ID Console"
if(GLOB.access_ai_upload)
return "AI Chambers"
if(GLOB.access_teleporter)
return "Teleporter"
if(GLOB.access_eva)
return "EVA"
if(GLOB.access_heads)
return "Bridge"
if(GLOB.access_captain)
return "Captain"
if(GLOB.access_all_personal_lockers)
return "Personal Lockers"
if(GLOB.access_chapel_office)
return "Chapel Office"
if(GLOB.access_tech_storage)
return "Technical Storage"
if(GLOB.access_atmospherics)
return "Atmospherics"
if(GLOB.access_crematorium)
return "Crematorium"
if(GLOB.access_armory)
return "Armory"
if(GLOB.access_construction)
return "Construction"
if(GLOB.access_kitchen)
return "Kitchen"
if(GLOB.access_hydroponics)
return "Hydroponics"
if(GLOB.access_library)
return "Library"
if(GLOB.access_lawyer)
return "Law Office"
if(GLOB.access_robotics)
return "Robotics"
if(GLOB.access_virology)
return "Virology"
if(GLOB.access_cmo)
return "CMO Office"
if(GLOB.access_qm)
return "Quartermaster"
if(GLOB.access_surgery)
return "Surgery"
if(GLOB.access_theatre)
return "Theatre"
if(GLOB.access_manufacturing)
return "Manufacturing"
if(GLOB.access_research)
return "Science"
if(GLOB.access_mining)
return "Mining"
if(GLOB.access_mining_office)
return "Mining Office"
if(GLOB.access_mailsorting)
return "Cargo Office"
if(GLOB.access_mint)
return "Mint"
if(GLOB.access_mint_vault)
return "Mint Vault"
if(GLOB.access_heads_vault)
return "Main Vault"
if(GLOB.access_mining_station)
return "Mining EVA"
if(GLOB.access_xenobiology)
return "Xenobiology Lab"
if(GLOB.access_hop)
return "HoP Office"
if(GLOB.access_hos)
return "HoS Office"
if(GLOB.access_ce)
return "CE Office"
if(GLOB.access_RC_announce)
return "RC Announcements"
if(GLOB.access_keycard_auth)
return "Keycode Auth."
if(GLOB.access_tcomsat)
return "Telecommunications"
if(GLOB.access_gateway)
return "Gateway"
if(GLOB.access_sec_doors)
return "Brig"
if(GLOB.access_mineral_storeroom)
return "Mineral Storage"
if(GLOB.access_minisat)
return "AI Satellite"
if(GLOB.access_weapons)
return "Weapon Permit"
if(GLOB.access_network)
return "Network Access"
if(GLOB.access_cloning)
return "Cloning Room"
/proc/get_centcom_access_desc(A)
switch(A)
if(GLOB.access_cent_general)
return "Code Grey"
if(GLOB.access_cent_thunder)
return "Code Yellow"
if(GLOB.access_cent_storage)
return "Code Orange"
if(GLOB.access_cent_living)
return "Code Green"
if(GLOB.access_cent_medical)
return "Code White"
if(GLOB.access_cent_teleporter)
return "Code Blue"
if(GLOB.access_cent_specops)
return "Code Black"
if(GLOB.access_cent_captain)
return "Code Gold"
if(GLOB.access_cent_bar)
return "Code Scotch"
/proc/get_all_jobs()
return list("Assistant", "Captain", "Head of Personnel", "Bartender", "Cook", "Botanist", "Quartermaster", "Cargo Technician",
"Shaft Miner", "Clown", "Mime", "Janitor", "Curator", "Lawyer", "Chaplain", "Chief Engineer", "Station Engineer",
"Atmospheric Technician", "Chief Medical Officer", "Medical Doctor", "Chemist", "Geneticist", "Virologist",
"Research Director", "Scientist", "Roboticist", "Head of Security", "Warden", "Detective", "Security Officer")
/proc/get_all_job_icons() //For all existing HUD icons
return get_all_jobs() + list("Prisoner")
/proc/get_all_centcom_jobs()
return list("VIP Guest","Custodian","Thunderdome Overseer","Centcom Official","Medical Officer","Death Commando","Research Officer","Special Ops Officer","Admiral","Centcom Commander","Emergency Response Team Commander","Security Response Officer","Engineer Response Officer", "Medical Response Officer","Centcom Bartender")
/obj/item/proc/GetJobName() //Used in secHUD icon generation
var/obj/item/weapon/card/id/I = GetID()
if(!I)
return
var/jobName = I.assignment
if(jobName in get_all_job_icons()) //Check if the job has a hud icon
return jobName
if(jobName in get_all_centcom_jobs()) //Return with the NT logo if it is a Centcom job
return "Centcom"
return "Unknown" //Return unknown if none of the above apply
GLOBAL_VAR_CONST(access_security, 1) // Security equipment
GLOBAL_VAR_CONST(access_brig, 2) // Brig timers and permabrig
GLOBAL_VAR_CONST(access_armory, 3)
GLOBAL_VAR_CONST(access_forensics_lockers, 4)
GLOBAL_VAR_CONST(access_medical, 5)
GLOBAL_VAR_CONST(access_morgue, 6)
GLOBAL_VAR_CONST(access_tox, 7)
GLOBAL_VAR_CONST(access_tox_storage, 8)
GLOBAL_VAR_CONST(access_genetics, 9)
GLOBAL_VAR_CONST(access_engine, 10)
GLOBAL_VAR_CONST(access_engine_equip, 11)
GLOBAL_VAR_CONST(access_maint_tunnels, 12)
GLOBAL_VAR_CONST(access_external_airlocks, 13)
GLOBAL_VAR_CONST(access_emergency_storage, 14)
GLOBAL_VAR_CONST(access_change_ids, 15)
GLOBAL_VAR_CONST(access_ai_upload, 16)
GLOBAL_VAR_CONST(access_teleporter, 17)
GLOBAL_VAR_CONST(access_eva, 18)
GLOBAL_VAR_CONST(access_heads, 19)
GLOBAL_VAR_CONST(access_captain, 20)
GLOBAL_VAR_CONST(access_all_personal_lockers, 21)
GLOBAL_VAR_CONST(access_chapel_office, 22)
GLOBAL_VAR_CONST(access_tech_storage, 23)
GLOBAL_VAR_CONST(access_atmospherics, 24)
GLOBAL_VAR_CONST(access_bar, 25)
GLOBAL_VAR_CONST(access_janitor, 26)
GLOBAL_VAR_CONST(access_crematorium, 27)
GLOBAL_VAR_CONST(access_kitchen, 28)
GLOBAL_VAR_CONST(access_robotics, 29)
GLOBAL_VAR_CONST(access_rd, 30)
GLOBAL_VAR_CONST(access_cargo, 31)
GLOBAL_VAR_CONST(access_construction, 32)
GLOBAL_VAR_CONST(access_chemistry, 33)
GLOBAL_VAR_CONST(access_cargo_bot, 34)
GLOBAL_VAR_CONST(access_hydroponics, 35)
GLOBAL_VAR_CONST(access_manufacturing, 36)
GLOBAL_VAR_CONST(access_library, 37)
GLOBAL_VAR_CONST(access_lawyer, 38)
GLOBAL_VAR_CONST(access_virology, 39)
GLOBAL_VAR_CONST(access_cmo, 40)
GLOBAL_VAR_CONST(access_qm, 41)
GLOBAL_VAR_CONST(access_court, 42)
GLOBAL_VAR_CONST(access_surgery, 45)
GLOBAL_VAR_CONST(access_theatre, 46)
GLOBAL_VAR_CONST(access_research, 47)
GLOBAL_VAR_CONST(access_mining, 48)
GLOBAL_VAR_CONST(access_mining_office, 49) //not in use
GLOBAL_VAR_CONST(access_mailsorting, 50)
GLOBAL_VAR_CONST(access_mint, 51)
GLOBAL_VAR_CONST(access_mint_vault, 52)
GLOBAL_VAR_CONST(access_heads_vault, 53)
GLOBAL_VAR_CONST(access_mining_station, 54)
GLOBAL_VAR_CONST(access_xenobiology, 55)
GLOBAL_VAR_CONST(access_ce, 56)
GLOBAL_VAR_CONST(access_hop, 57)
GLOBAL_VAR_CONST(access_hos, 58)
GLOBAL_VAR_CONST(access_RC_announce, 59) //Request console announcements
GLOBAL_VAR_CONST(access_keycard_auth, 60) //Used for events which require at least two people to confirm them
GLOBAL_VAR_CONST(access_tcomsat, 61) // has access to the entire telecomms satellite / machinery
GLOBAL_VAR_CONST(access_gateway, 62)
GLOBAL_VAR_CONST(access_sec_doors, 63) // Security front doors
GLOBAL_VAR_CONST(access_mineral_storeroom, 64)
GLOBAL_VAR_CONST(access_minisat, 65)
GLOBAL_VAR_CONST(access_weapons, 66) //Weapon authorization for secbots
GLOBAL_VAR_CONST(access_network, 67)
GLOBAL_VAR_CONST(access_cloning, 68) //Cloning room
//BEGIN CENTCOM ACCESS
/*Should leave plenty of room if we need to add more access levels.
Mostly for admin fun times.*/
GLOBAL_VAR_CONST(access_cent_general, 101)//General facilities.
GLOBAL_VAR_CONST(access_cent_thunder, 102)//Thunderdome.
GLOBAL_VAR_CONST(access_cent_specops, 103)//Special Ops.
GLOBAL_VAR_CONST(access_cent_medical, 104)//Medical/Research
GLOBAL_VAR_CONST(access_cent_living, 105)//Living quarters.
GLOBAL_VAR_CONST(access_cent_storage, 106)//Generic storage areas.
GLOBAL_VAR_CONST(access_cent_teleporter, 107)//Teleporter.
GLOBAL_VAR_CONST(access_cent_captain, 109)//Captain's office/ID comp/AI.
GLOBAL_VAR_CONST(access_cent_bar, 110) // The non-existent Centcom Bar
//The Syndicate
GLOBAL_VAR_CONST(access_syndicate, 150)//General Syndicate Access
GLOBAL_VAR_CONST(access_syndicate_leader, 151)//Nuke Op Leader Access
//Away Missions or Ruins
/*For generic away-mission/ruin access. Why would normal crew have access to a long-abandoned derelict
or a 2000 year-old temple? */
GLOBAL_VAR_CONST(access_away_general, 200)//General facilities.
GLOBAL_VAR_CONST(access_away_maint, 201)//Away maintenance
GLOBAL_VAR_CONST(access_away_med, 202)//Away medical
GLOBAL_VAR_CONST(access_away_sec, 203)//Away security
GLOBAL_VAR_CONST(access_away_engine, 204)//Away engineering
GLOBAL_VAR_CONST(access_away_generic1, 205)//Away generic access
GLOBAL_VAR_CONST(access_away_generic2, 206)
GLOBAL_VAR_CONST(access_away_generic3, 207)
GLOBAL_VAR_CONST(access_away_generic4, 208)
/obj/var/list/req_access = null
/obj/var/req_access_txt = "0"
/obj/var/list/req_one_access = null
/obj/var/req_one_access_txt = "0"
//returns 1 if this mob has sufficient access to use this object
/obj/proc/allowed(mob/M)
//check if it doesn't require any access at all
if(src.check_access(null))
return TRUE
if(issilicon(M))
if(ispAI(M))
return FALSE
return TRUE //AI can do whatever it wants
if(IsAdminGhost(M))
//Access can't stop the abuse
return TRUE
else if(ishuman(M))
var/mob/living/carbon/human/H = M
//if they are holding or wearing a card that has access, that works
if(check_access(H.get_active_held_item()) || src.check_access(H.wear_id))
return TRUE
else if(ismonkey(M) || isalienadult(M))
var/mob/living/carbon/george = M
//they can only hold things :(
if(check_access(george.get_active_held_item()))
return TRUE
else if(isanimal(M))
var/mob/living/simple_animal/A = M
if(check_access(A.get_active_held_item()) || check_access(A.access_card))
return TRUE
return FALSE
/obj/item/proc/GetAccess()
return list()
/obj/item/proc/GetID()
return null
//Call this before using req_access or req_one_access directly
/obj/proc/gen_access()
//These generations have been moved out of /obj/New() because they were slowing down the creation of objects that never even used the access system.
if(!src.req_access)
src.req_access = list()
if(src.req_access_txt)
var/list/req_access_str = splittext(req_access_txt,";")
for(var/x in req_access_str)
var/n = text2num(x)
if(n)
req_access += n
if(!src.req_one_access)
src.req_one_access = list()
if(src.req_one_access_txt)
var/list/req_one_access_str = splittext(req_one_access_txt,";")
for(var/x in req_one_access_str)
var/n = text2num(x)
if(n)
req_one_access += n
/obj/proc/check_access(obj/item/I)
gen_access()
if(!istype(src.req_access, /list)) //something's very wrong
return TRUE
var/list/L = src.req_access
if(!L.len && (!src.req_one_access || !src.req_one_access.len)) //no requirements
return TRUE
if(!I)
return FALSE
for(var/req in src.req_access)
if(!(req in I.GetAccess())) //doesn't have this access
return FALSE
if(src.req_one_access && src.req_one_access.len)
for(var/req in src.req_one_access)
if(req in I.GetAccess()) //has an access from the single access list
return TRUE
return FALSE
return TRUE
/obj/proc/check_access_list(list/L)
if(!src.req_access && !src.req_one_access)
return TRUE
if(!istype(src.req_access, /list))
return TRUE
if(!src.req_access.len && (!src.req_one_access || !src.req_one_access.len))
return TRUE
if(!L)
return FALSE
if(!istype(L, /list))
return FALSE
for(var/req in src.req_access)
if(!(req in L)) //doesn't have this access
return FALSE
if(src.req_one_access && src.req_one_access.len)
for(var/req in src.req_one_access)
if(req in L) //has an access from the single access list
return TRUE
return FALSE
return TRUE
/proc/get_centcom_access(job)
switch(job)
if("VIP Guest")
return list(GLOB.access_cent_general)
if("Custodian")
return list(GLOB.access_cent_general, GLOB.access_cent_living, GLOB.access_cent_storage)
if("Thunderdome Overseer")
return list(GLOB.access_cent_general, GLOB.access_cent_thunder)
if("Centcom Official")
return list(GLOB.access_cent_general, GLOB.access_cent_living)
if("Medical Officer")
return list(GLOB.access_cent_general, GLOB.access_cent_living, GLOB.access_cent_medical)
if("Death Commando")
return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_living, GLOB.access_cent_storage)
if("Research Officer")
return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_medical, GLOB.access_cent_teleporter, GLOB.access_cent_storage)
if("Special Ops Officer")
return list(GLOB.access_cent_general, GLOB.access_cent_thunder, GLOB.access_cent_specops, GLOB.access_cent_living, GLOB.access_cent_storage)
if("Admiral")
return get_all_centcom_access()
if("Centcom Commander")
return get_all_centcom_access()
if("Emergency Response Team Commander")
return get_ert_access("commander")
if("Security Response Officer")
return get_ert_access("sec")
if("Engineer Response Officer")
return get_ert_access("eng")
if("Medical Response Officer")
return get_ert_access("med")
if("Centcom Bartender")
return list(GLOB.access_cent_general, GLOB.access_cent_living, GLOB.access_cent_bar)
/proc/get_all_accesses()
return list(GLOB.access_security, GLOB.access_sec_doors, GLOB.access_brig, GLOB.access_armory, GLOB.access_forensics_lockers, GLOB.access_court,
GLOB.access_medical, GLOB.access_genetics, GLOB.access_morgue, GLOB.access_rd,
GLOB.access_tox, GLOB.access_tox_storage, GLOB.access_chemistry, GLOB.access_engine, GLOB.access_engine_equip, GLOB.access_maint_tunnels,
GLOB.access_external_airlocks, GLOB.access_change_ids, GLOB.access_ai_upload,
GLOB.access_teleporter, GLOB.access_eva, GLOB.access_heads, GLOB.access_captain, GLOB.access_all_personal_lockers,
GLOB.access_tech_storage, GLOB.access_chapel_office, GLOB.access_atmospherics, GLOB.access_kitchen,
GLOB.access_bar, GLOB.access_janitor, GLOB.access_crematorium, GLOB.access_robotics, GLOB.access_cargo, GLOB.access_construction,
GLOB.access_hydroponics, GLOB.access_library, GLOB.access_lawyer, GLOB.access_virology, GLOB.access_cmo, GLOB.access_qm, GLOB.access_surgery,
GLOB.access_theatre, GLOB.access_research, GLOB.access_mining, GLOB.access_mailsorting, GLOB.access_weapons,
GLOB.access_heads_vault, GLOB.access_mining_station, GLOB.access_xenobiology, GLOB.access_ce, GLOB.access_hop, GLOB.access_hos, GLOB.access_RC_announce,
GLOB.access_keycard_auth, GLOB.access_tcomsat, GLOB.access_gateway, GLOB.access_mineral_storeroom, GLOB.access_minisat, GLOB.access_network, GLOB.access_cloning)
/proc/get_all_centcom_access()
return list(GLOB.access_cent_general, GLOB.access_cent_thunder, GLOB.access_cent_specops, GLOB.access_cent_medical, GLOB.access_cent_living, GLOB.access_cent_storage, GLOB.access_cent_teleporter, GLOB.access_cent_captain)
/proc/get_ert_access(class)
switch(class)
if("commander")
return get_all_centcom_access()
if("sec")
return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_living)
if("eng")
return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_living, GLOB.access_cent_storage)
if("med")
return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_medical, GLOB.access_cent_living)
/proc/get_all_syndicate_access()
return list(GLOB.access_syndicate, GLOB.access_syndicate)
/proc/get_region_accesses(code)
switch(code)
if(0)
return get_all_accesses()
if(1) //station general
return list(GLOB.access_kitchen,GLOB.access_bar, GLOB.access_hydroponics, GLOB.access_janitor, GLOB.access_chapel_office, GLOB.access_crematorium, GLOB.access_library, GLOB.access_theatre, GLOB.access_lawyer)
if(2) //security
return list(GLOB.access_sec_doors, GLOB.access_weapons, GLOB.access_security, GLOB.access_brig, GLOB.access_armory, GLOB.access_forensics_lockers, GLOB.access_court, GLOB.access_hos)
if(3) //medbay
return list(GLOB.access_medical, GLOB.access_genetics, GLOB.access_cloning, GLOB.access_morgue, GLOB.access_chemistry, GLOB.access_virology, GLOB.access_surgery, GLOB.access_cmo)
if(4) //research
return list(GLOB.access_research, GLOB.access_tox, GLOB.access_tox_storage, GLOB.access_genetics, GLOB.access_robotics, GLOB.access_xenobiology, GLOB.access_minisat, GLOB.access_rd, GLOB.access_network)
if(5) //engineering and maintenance
return list(GLOB.access_construction, GLOB.access_maint_tunnels, GLOB.access_engine, GLOB.access_engine_equip, GLOB.access_external_airlocks, GLOB.access_tech_storage, GLOB.access_atmospherics, GLOB.access_tcomsat, GLOB.access_minisat, GLOB.access_ce)
if(6) //supply
return list(GLOB.access_mailsorting, GLOB.access_mining, GLOB.access_mining_station, GLOB.access_mineral_storeroom, GLOB.access_cargo, GLOB.access_qm)
if(7) //command
return list(GLOB.access_heads, GLOB.access_RC_announce, GLOB.access_keycard_auth, GLOB.access_change_ids, GLOB.access_ai_upload, GLOB.access_teleporter, GLOB.access_eva, GLOB.access_gateway, GLOB.access_all_personal_lockers, GLOB.access_heads_vault, GLOB.access_hop, GLOB.access_captain)
/proc/get_region_accesses_name(code)
switch(code)
if(0)
return "All"
if(1) //station general
return "General"
if(2) //security
return "Security"
if(3) //medbay
return "Medbay"
if(4) //research
return "Research"
if(5) //engineering and maintenance
return "Engineering"
if(6) //supply
return "Supply"
if(7) //command
return "Command"
/proc/get_access_desc(A)
switch(A)
if(GLOB.access_cargo)
return "Cargo Bay"
if(GLOB.access_cargo_bot)
return "Delivery Chutes"
if(GLOB.access_security)
return "Security"
if(GLOB.access_brig)
return "Holding Cells"
if(GLOB.access_court)
return "Courtroom"
if(GLOB.access_forensics_lockers)
return "Forensics"
if(GLOB.access_medical)
return "Medical"
if(GLOB.access_genetics)
return "Genetics Lab"
if(GLOB.access_morgue)
return "Morgue"
if(GLOB.access_tox)
return "R&D Lab"
if(GLOB.access_tox_storage)
return "Toxins Lab"
if(GLOB.access_chemistry)
return "Chemistry Lab"
if(GLOB.access_rd)
return "RD Office"
if(GLOB.access_bar)
return "Bar"
if(GLOB.access_janitor)
return "Custodial Closet"
if(GLOB.access_engine)
return "Engineering"
if(GLOB.access_engine_equip)
return "Power Equipment"
if(GLOB.access_maint_tunnels)
return "Maintenance"
if(GLOB.access_external_airlocks)
return "External Airlocks"
if(GLOB.access_emergency_storage)
return "Emergency Storage"
if(GLOB.access_change_ids)
return "ID Console"
if(GLOB.access_ai_upload)
return "AI Chambers"
if(GLOB.access_teleporter)
return "Teleporter"
if(GLOB.access_eva)
return "EVA"
if(GLOB.access_heads)
return "Bridge"
if(GLOB.access_captain)
return "Captain"
if(GLOB.access_all_personal_lockers)
return "Personal Lockers"
if(GLOB.access_chapel_office)
return "Chapel Office"
if(GLOB.access_tech_storage)
return "Technical Storage"
if(GLOB.access_atmospherics)
return "Atmospherics"
if(GLOB.access_crematorium)
return "Crematorium"
if(GLOB.access_armory)
return "Armory"
if(GLOB.access_construction)
return "Construction"
if(GLOB.access_kitchen)
return "Kitchen"
if(GLOB.access_hydroponics)
return "Hydroponics"
if(GLOB.access_library)
return "Library"
if(GLOB.access_lawyer)
return "Law Office"
if(GLOB.access_robotics)
return "Robotics"
if(GLOB.access_virology)
return "Virology"
if(GLOB.access_cmo)
return "CMO Office"
if(GLOB.access_qm)
return "Quartermaster"
if(GLOB.access_surgery)
return "Surgery"
if(GLOB.access_theatre)
return "Theatre"
if(GLOB.access_manufacturing)
return "Manufacturing"
if(GLOB.access_research)
return "Science"
if(GLOB.access_mining)
return "Mining"
if(GLOB.access_mining_office)
return "Mining Office"
if(GLOB.access_mailsorting)
return "Cargo Office"
if(GLOB.access_mint)
return "Mint"
if(GLOB.access_mint_vault)
return "Mint Vault"
if(GLOB.access_heads_vault)
return "Main Vault"
if(GLOB.access_mining_station)
return "Mining EVA"
if(GLOB.access_xenobiology)
return "Xenobiology Lab"
if(GLOB.access_hop)
return "HoP Office"
if(GLOB.access_hos)
return "HoS Office"
if(GLOB.access_ce)
return "CE Office"
if(GLOB.access_RC_announce)
return "RC Announcements"
if(GLOB.access_keycard_auth)
return "Keycode Auth."
if(GLOB.access_tcomsat)
return "Telecommunications"
if(GLOB.access_gateway)
return "Gateway"
if(GLOB.access_sec_doors)
return "Brig"
if(GLOB.access_mineral_storeroom)
return "Mineral Storage"
if(GLOB.access_minisat)
return "AI Satellite"
if(GLOB.access_weapons)
return "Weapon Permit"
if(GLOB.access_network)
return "Network Access"
if(GLOB.access_cloning)
return "Cloning Room"
/proc/get_centcom_access_desc(A)
switch(A)
if(GLOB.access_cent_general)
return "Code Grey"
if(GLOB.access_cent_thunder)
return "Code Yellow"
if(GLOB.access_cent_storage)
return "Code Orange"
if(GLOB.access_cent_living)
return "Code Green"
if(GLOB.access_cent_medical)
return "Code White"
if(GLOB.access_cent_teleporter)
return "Code Blue"
if(GLOB.access_cent_specops)
return "Code Black"
if(GLOB.access_cent_captain)
return "Code Gold"
if(GLOB.access_cent_bar)
return "Code Scotch"
/proc/get_all_jobs()
return list("Assistant", "Captain", "Head of Personnel", "Bartender", "Cook", "Botanist", "Quartermaster", "Cargo Technician",
"Shaft Miner", "Clown", "Mime", "Janitor", "Curator", "Lawyer", "Chaplain", "Chief Engineer", "Station Engineer",
"Atmospheric Technician", "Chief Medical Officer", "Medical Doctor", "Chemist", "Geneticist", "Virologist",
"Research Director", "Scientist", "Roboticist", "Head of Security", "Warden", "Detective", "Security Officer")
/proc/get_all_job_icons() //For all existing HUD icons
return get_all_jobs() + list("Prisoner")
/proc/get_all_centcom_jobs()
return list("VIP Guest","Custodian","Thunderdome Overseer","Centcom Official","Medical Officer","Death Commando","Research Officer","Special Ops Officer","Admiral","Centcom Commander","Emergency Response Team Commander","Security Response Officer","Engineer Response Officer", "Medical Response Officer","Centcom Bartender")
/obj/item/proc/GetJobName() //Used in secHUD icon generation
var/obj/item/weapon/card/id/I = GetID()
if(!I)
return
var/jobName = I.assignment
if(jobName in get_all_job_icons()) //Check if the job has a hud icon
return jobName
if(jobName in get_all_centcom_jobs()) //Return with the NT logo if it is a Centcom job
return "Centcom"
return "Unknown" //Return unknown if none of the above apply
+3 -3
View File
@@ -35,8 +35,8 @@ Clown
/obj/item/weapon/reagent_containers/spray/waterflower = 1,
/obj/item/weapon/reagent_containers/food/snacks/grown/banana = 1,
/obj/item/device/megaphone/clown = 1,
/obj/item/weapon/reagent_containers/food/drinks/soda_cans/canned_laughter = 1,
/obj/item/weapon/pneumatic_cannon/pie = 1
/obj/item/weapon/reagent_containers/food/drinks/soda_cans/canned_laughter = 1,
/obj/item/weapon/pneumatic_cannon/pie = 1
)
implants = list(/obj/item/weapon/implant/sad_trombone)
@@ -129,7 +129,7 @@ Curator
outfit = /datum/outfit/job/curator
access = list(GLOB.access_library)
minimal_access = list(GLOB.access_library, GLOB.access_construction,GLOB.access_mining_station)
minimal_access = list(GLOB.access_library, GLOB.access_construction,GLOB.access_mining_station)
/datum/outfit/job/curator
name = "Curator"
+108 -108
View File
@@ -1,109 +1,109 @@
GLOBAL_LIST_INIT(command_positions, list(
"Captain",
"Head of Personnel",
"Head of Security",
"Chief Engineer",
"Research Director",
"Chief Medical Officer"))
GLOBAL_LIST_INIT(engineering_positions, list(
"Chief Engineer",
"Station Engineer",
"Atmospheric Technician"))
GLOBAL_LIST_INIT(medical_positions, list(
"Chief Medical Officer",
"Medical Doctor",
"Geneticist",
"Virologist",
"Chemist"))
GLOBAL_LIST_INIT(science_positions, list(
"Research Director",
"Scientist",
"Roboticist"))
GLOBAL_LIST_INIT(supply_positions, list(
"Head of Personnel",
"Quartermaster",
"Cargo Technician",
"Shaft Miner"))
GLOBAL_LIST_INIT(civilian_positions, list(
"Bartender",
"Botanist",
"Cook",
"Janitor",
"Curator",
"Lawyer",
"Chaplain",
"Clown",
"Mime",
"Assistant"))
GLOBAL_LIST_INIT(security_positions, list(
"Head of Security",
"Warden",
"Detective",
"Security Officer"))
GLOBAL_LIST_INIT(nonhuman_positions, list(
"AI",
"Cyborg",
"pAI"))
/proc/guest_jobbans(job)
return ((job in GLOB.command_positions) || (job in GLOB.nonhuman_positions) || (job in GLOB.security_positions))
//this is necessary because antags happen before job datums are handed out, but NOT before they come into existence
//so I can't simply use job datum.department_head straight from the mind datum, laaaaame.
/proc/get_department_heads(var/job_title)
if(!job_title)
return list()
for(var/datum/job/J in SSjob.occupations)
if(J.title == job_title)
return J.department_head //this is a list
/proc/get_full_job_name(job)
var/static/regex/cap_expand = new("cap(?!tain)")
var/static/regex/cmo_expand = new("cmo")
var/static/regex/hos_expand = new("hos")
var/static/regex/hop_expand = new("hop")
var/static/regex/rd_expand = new("rd")
var/static/regex/ce_expand = new("ce")
var/static/regex/qm_expand = new("qm")
var/static/regex/sec_expand = new("(?<!security )officer")
var/static/regex/engi_expand = new("(?<!station )engineer")
var/static/regex/atmos_expand = new("atmos tech")
var/static/regex/doc_expand = new("(?<!medical )doctor|medic(?!al)")
var/static/regex/mine_expand = new("(?<!shaft )miner")
var/static/regex/chef_expand = new("chef")
var/static/regex/borg_expand = new("(?<!cy)borg")
job = lowertext(job)
job = cap_expand.Replace(job, "captain")
job = cmo_expand.Replace(job, "chief medical officer")
job = hos_expand.Replace(job, "head of security")
job = hop_expand.Replace(job, "head of personnel")
job = rd_expand.Replace(job, "research director")
job = ce_expand.Replace(job, "chief engineer")
job = qm_expand.Replace(job, "quartermaster")
job = sec_expand.Replace(job, "security officer")
job = engi_expand.Replace(job, "station engineer")
job = atmos_expand.Replace(job, "atmospheric technician")
job = doc_expand.Replace(job, "medical doctor")
job = mine_expand.Replace(job, "shaft miner")
job = chef_expand.Replace(job, "cook")
job = borg_expand.Replace(job, "cyborg")
GLOBAL_LIST_INIT(command_positions, list(
"Captain",
"Head of Personnel",
"Head of Security",
"Chief Engineer",
"Research Director",
"Chief Medical Officer"))
GLOBAL_LIST_INIT(engineering_positions, list(
"Chief Engineer",
"Station Engineer",
"Atmospheric Technician"))
GLOBAL_LIST_INIT(medical_positions, list(
"Chief Medical Officer",
"Medical Doctor",
"Geneticist",
"Virologist",
"Chemist"))
GLOBAL_LIST_INIT(science_positions, list(
"Research Director",
"Scientist",
"Roboticist"))
GLOBAL_LIST_INIT(supply_positions, list(
"Head of Personnel",
"Quartermaster",
"Cargo Technician",
"Shaft Miner"))
GLOBAL_LIST_INIT(civilian_positions, list(
"Bartender",
"Botanist",
"Cook",
"Janitor",
"Curator",
"Lawyer",
"Chaplain",
"Clown",
"Mime",
"Assistant"))
GLOBAL_LIST_INIT(security_positions, list(
"Head of Security",
"Warden",
"Detective",
"Security Officer"))
GLOBAL_LIST_INIT(nonhuman_positions, list(
"AI",
"Cyborg",
"pAI"))
/proc/guest_jobbans(job)
return ((job in GLOB.command_positions) || (job in GLOB.nonhuman_positions) || (job in GLOB.security_positions))
//this is necessary because antags happen before job datums are handed out, but NOT before they come into existence
//so I can't simply use job datum.department_head straight from the mind datum, laaaaame.
/proc/get_department_heads(var/job_title)
if(!job_title)
return list()
for(var/datum/job/J in SSjob.occupations)
if(J.title == job_title)
return J.department_head //this is a list
/proc/get_full_job_name(job)
var/static/regex/cap_expand = new("cap(?!tain)")
var/static/regex/cmo_expand = new("cmo")
var/static/regex/hos_expand = new("hos")
var/static/regex/hop_expand = new("hop")
var/static/regex/rd_expand = new("rd")
var/static/regex/ce_expand = new("ce")
var/static/regex/qm_expand = new("qm")
var/static/regex/sec_expand = new("(?<!security )officer")
var/static/regex/engi_expand = new("(?<!station )engineer")
var/static/regex/atmos_expand = new("atmos tech")
var/static/regex/doc_expand = new("(?<!medical )doctor|medic(?!al)")
var/static/regex/mine_expand = new("(?<!shaft )miner")
var/static/regex/chef_expand = new("chef")
var/static/regex/borg_expand = new("(?<!cy)borg")
job = lowertext(job)
job = cap_expand.Replace(job, "captain")
job = cmo_expand.Replace(job, "chief medical officer")
job = hos_expand.Replace(job, "head of security")
job = hop_expand.Replace(job, "head of personnel")
job = rd_expand.Replace(job, "research director")
job = ce_expand.Replace(job, "chief engineer")
job = qm_expand.Replace(job, "quartermaster")
job = sec_expand.Replace(job, "security officer")
job = engi_expand.Replace(job, "station engineer")
job = atmos_expand.Replace(job, "atmospheric technician")
job = doc_expand.Replace(job, "medical doctor")
job = mine_expand.Replace(job, "shaft miner")
job = chef_expand.Replace(job, "cook")
job = borg_expand.Replace(job, "cyborg")
return job
+61 -61
View File
@@ -1,61 +1,61 @@
//*******************************
//
// Library SQL Configuration
//
//*******************************
// Deprecated! See global.dm for new SQL config vars
/*
#define SQL_ADDRESS ""
#define SQL_DB ""
#define SQL_PORT "3306"
#define SQL_LOGIN ""
#define SQL_PASS ""
*/
//*******************************
// Requires Dantom.DB library ( http://www.byond.com/developer/Dantom/DB )
/*
The Library
------------
A place for the crew to go, relax, and enjoy a good book.
Aspiring authors can even self publish and, if they're lucky
convince the on-staff Curator to submit it to the Archives
to be chronicled in history forever - some say even persisting
through alternate dimensions.
Written by TLE for /tg/station 13
Feel free to use this as you like. Some credit would be cool.
Check us out at http://nanotrasen.com/ if you're so inclined.
*/
// CONTAINS:
// Objects:
// - bookcase
// - book
// - barcode scanner
// Machinery:
// - library computer
// - visitor's computer
// - book binder
// - book scanner
// Datum:
// - borrowbook
// Ideas for the future
// ---------------------
// - Visitor's computer should be able to search the current in-round library inventory (that the Curator has stocked and checked in)
// -- Give computer other features like an Instant Messenger application, or the ability to edit, save, and print documents.
// - Admin interface directly tied to the Archive DB. Right now there's no way to delete uploaded books in-game.
// -- If this gets implemented, allow Curators to "tag" or "suggest" books to be deleted. The DB ID of the tagged books gets saved to a text file (or another table in the DB maybe?).
// The admin interface would automatically take these IDs and SELECT them all from the DB to be displayed along with a Delete link to drop the row from the table.
// - When the game sets up and the round begins, have it automatically pick random books from the DB to populate the library with. Even if the Curator is a useless fuck there are at least a few books around.
// - Allow books to be "hollowed out" like the Chaplain's Bible, allowing you to store one pocket-sized item inside.
// - Make books/book cases burn when exposed to flame.
// - Make book binder hackable.
// - Books shouldn't print straight from the library computer. Make it synch with a machine like the book binder to print instead. This should consume some sort of resource.
//*******************************
//
// Library SQL Configuration
//
//*******************************
// Deprecated! See global.dm for new SQL config vars
/*
#define SQL_ADDRESS ""
#define SQL_DB ""
#define SQL_PORT "3306"
#define SQL_LOGIN ""
#define SQL_PASS ""
*/
//*******************************
// Requires Dantom.DB library ( http://www.byond.com/developer/Dantom/DB )
/*
The Library
------------
A place for the crew to go, relax, and enjoy a good book.
Aspiring authors can even self publish and, if they're lucky
convince the on-staff Curator to submit it to the Archives
to be chronicled in history forever - some say even persisting
through alternate dimensions.
Written by TLE for /tg/station 13
Feel free to use this as you like. Some credit would be cool.
Check us out at http://nanotrasen.com/ if you're so inclined.
*/
// CONTAINS:
// Objects:
// - bookcase
// - book
// - barcode scanner
// Machinery:
// - library computer
// - visitor's computer
// - book binder
// - book scanner
// Datum:
// - borrowbook
// Ideas for the future
// ---------------------
// - Visitor's computer should be able to search the current in-round library inventory (that the Curator has stocked and checked in)
// -- Give computer other features like an Instant Messenger application, or the ability to edit, save, and print documents.
// - Admin interface directly tied to the Archive DB. Right now there's no way to delete uploaded books in-game.
// -- If this gets implemented, allow Curators to "tag" or "suggest" books to be deleted. The DB ID of the tagged books gets saved to a text file (or another table in the DB maybe?).
// The admin interface would automatically take these IDs and SELECT them all from the DB to be displayed along with a Delete link to drop the row from the table.
// - When the game sets up and the round begins, have it automatically pick random books from the DB to populate the library with. Even if the Curator is a useless fuck there are at least a few books around.
// - Allow books to be "hollowed out" like the Chaplain's Bible, allowing you to store one pocket-sized item inside.
// - Make books/book cases burn when exposed to flame.
// - Make book binder hackable.
// - Books shouldn't print straight from the library computer. Make it synch with a machine like the book binder to print instead. This should consume some sort of resource.
+178 -178
View File
@@ -1,178 +1,178 @@
/datum/emote/living/carbon/human
mob_type_allowed_typecache = list(/mob/living/carbon/human)
/datum/emote/living/carbon/human/cry
key = "cry"
key_third_person = "cries"
message = "cries."
emote_type = EMOTE_AUDIBLE
/datum/emote/living/carbon/human/dap
key = "dap"
key_third_person = "daps"
message = "sadly can't find anybody to give daps to, and daps themself. Shameful."
message_param = "give daps to %t."
restraint_check = TRUE
/datum/emote/living/carbon/human/eyebrow
key = "eyebrow"
message = "raises an eyebrow."
/datum/emote/living/carbon/human/grumble
key = "grumble"
key_third_person = "grumbles"
message = "grumbles!"
emote_type = EMOTE_AUDIBLE
/datum/emote/living/carbon/human/handshake
key = "handshake"
message = "shakes their own hands."
message_param = "shakes hands with %t."
restraint_check = TRUE
emote_type = EMOTE_AUDIBLE
/datum/emote/living/carbon/human/hug
key = "hug"
key_third_person = "hugs"
message = "hugs themself."
message_param = "hugs %t."
restraint_check = TRUE
emote_type = EMOTE_AUDIBLE
/datum/emote/living/carbon/human/mumble
key = "mumble"
key_third_person = "mumbles"
message = "mumbles!"
emote_type = EMOTE_AUDIBLE
/datum/emote/living/carbon/human/pale
key = "pale"
message = "goes pale for a second."
/datum/emote/living/carbon/human/raise
key = "raise"
key_third_person = "raises"
message = "raises a hand."
restraint_check = TRUE
/datum/emote/living/carbon/human/salute
key = "salute"
key_third_person = "salutes"
message = "salutes."
message_param = "salutes to %t."
restraint_check = TRUE
/datum/emote/living/carbon/human/shrug
key = "shrug"
key_third_person = "shrugs"
message = "shrugs."
/datum/emote/living/carbon/human/wag
key = "wag"
key_third_person = "wags"
message = "wags their tail."
/datum/emote/living/carbon/human/wag/run_emote(mob/user, params)
. = ..()
var/mob/living/carbon/human/H = user
if(.)
H.startTailWag()
else
H.endTailWag()
/datum/emote/living/carbon/human/wag/can_run_emote(mob/user)
if(!..())
return FALSE
var/mob/living/carbon/human/H = user
if(H.dna && H.dna.species && ((H.dna.features["tail_lizard"] != "None") || (H.dna.features["tail_human"] != "None") || ("mam_tail" in H.dna.species.mutant_bodyparts)))
return TRUE
/datum/emote/living/carbon/human/wag/select_message_type(mob/user)
. = ..()
var/mob/living/carbon/human/H = user
if(("waggingtail_lizard" in H.dna.species.mutant_bodyparts) || ("waggingtail_human" in H.dna.species.mutant_bodyparts) || ("mam_waggingtail" in H.dna.species.mutant_bodyparts))
. = null
/datum/emote/living/carbon/human/wing
key = "wing"
key_third_person = "wings"
message = "their wings."
/datum/emote/living/carbon/human/wing/run_emote(mob/user, params)
. = ..()
if(.)
var/mob/living/carbon/human/H = user
if(findtext(select_message_type(user), "open"))
H.OpenWings()
else
H.CloseWings()
/datum/emote/living/carbon/human/wing/select_message_type(mob/user)
. = ..()
var/mob/living/carbon/human/H = user
if("wings" in H.dna.species.mutant_bodyparts)
. = "opens " + message
else
. = "closes " + message
/datum/emote/living/carbon/human/wing/can_run_emote(mob/user)
if(!..())
return FALSE
var/mob/living/carbon/human/H = user
if(H.dna && H.dna.species && (H.dna.features["wings"] != "None"))
return TRUE
//Don't know where else to put this, it's basically an emote
/mob/living/carbon/human/proc/startTailWag()
if(!dna || !dna.species)
return
if("tail_lizard" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "tail_lizard"
dna.species.mutant_bodyparts -= "spines"
dna.species.mutant_bodyparts |= "waggingtail_lizard"
dna.species.mutant_bodyparts |= "waggingspines"
if("tail_human" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "tail_human"
dna.species.mutant_bodyparts |= "waggingtail_human"
if("mam_tail" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "mam_tail"
dna.species.mutant_bodyparts |= "mam_waggingtail"
update_body()
/mob/living/carbon/human/proc/endTailWag()
if(!dna || !dna.species)
return
if("waggingtail_lizard" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "waggingtail_lizard"
dna.species.mutant_bodyparts -= "waggingspines"
dna.species.mutant_bodyparts |= "tail_lizard"
dna.species.mutant_bodyparts |= "spines"
if("waggingtail_human" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "waggingtail_human"
dna.species.mutant_bodyparts |= "tail_human"
if("mam_waggingtail" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "mam_waggingtail"
dna.species.mutant_bodyparts |= "mam_tail"
update_body()
/mob/living/carbon/human/proc/OpenWings()
if(!dna || !dna.species)
return
if("wings" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "wings"
dna.species.mutant_bodyparts |= "wingsopen"
update_body()
/mob/living/carbon/human/proc/CloseWings()
if(!dna || !dna.species)
return
if("wingsopen" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "wingsopen"
dna.species.mutant_bodyparts |= "wings"
update_body()
if(isturf(loc))
var/turf/T = loc
T.Entered(src)
//Ayy lmao
/datum/emote/living/carbon/human
mob_type_allowed_typecache = list(/mob/living/carbon/human)
/datum/emote/living/carbon/human/cry
key = "cry"
key_third_person = "cries"
message = "cries."
emote_type = EMOTE_AUDIBLE
/datum/emote/living/carbon/human/dap
key = "dap"
key_third_person = "daps"
message = "sadly can't find anybody to give daps to, and daps themself. Shameful."
message_param = "give daps to %t."
restraint_check = TRUE
/datum/emote/living/carbon/human/eyebrow
key = "eyebrow"
message = "raises an eyebrow."
/datum/emote/living/carbon/human/grumble
key = "grumble"
key_third_person = "grumbles"
message = "grumbles!"
emote_type = EMOTE_AUDIBLE
/datum/emote/living/carbon/human/handshake
key = "handshake"
message = "shakes their own hands."
message_param = "shakes hands with %t."
restraint_check = TRUE
emote_type = EMOTE_AUDIBLE
/datum/emote/living/carbon/human/hug
key = "hug"
key_third_person = "hugs"
message = "hugs themself."
message_param = "hugs %t."
restraint_check = TRUE
emote_type = EMOTE_AUDIBLE
/datum/emote/living/carbon/human/mumble
key = "mumble"
key_third_person = "mumbles"
message = "mumbles!"
emote_type = EMOTE_AUDIBLE
/datum/emote/living/carbon/human/pale
key = "pale"
message = "goes pale for a second."
/datum/emote/living/carbon/human/raise
key = "raise"
key_third_person = "raises"
message = "raises a hand."
restraint_check = TRUE
/datum/emote/living/carbon/human/salute
key = "salute"
key_third_person = "salutes"
message = "salutes."
message_param = "salutes to %t."
restraint_check = TRUE
/datum/emote/living/carbon/human/shrug
key = "shrug"
key_third_person = "shrugs"
message = "shrugs."
/datum/emote/living/carbon/human/wag
key = "wag"
key_third_person = "wags"
message = "wags their tail."
/datum/emote/living/carbon/human/wag/run_emote(mob/user, params)
. = ..()
var/mob/living/carbon/human/H = user
if(.)
H.startTailWag()
else
H.endTailWag()
/datum/emote/living/carbon/human/wag/can_run_emote(mob/user)
if(!..())
return FALSE
var/mob/living/carbon/human/H = user
if(H.dna && H.dna.species && ((H.dna.features["tail_lizard"] != "None") || (H.dna.features["tail_human"] != "None") || ("mam_tail" in H.dna.species.mutant_bodyparts)))
return TRUE
/datum/emote/living/carbon/human/wag/select_message_type(mob/user)
. = ..()
var/mob/living/carbon/human/H = user
if(("waggingtail_lizard" in H.dna.species.mutant_bodyparts) || ("waggingtail_human" in H.dna.species.mutant_bodyparts) || ("mam_waggingtail" in H.dna.species.mutant_bodyparts))
. = null
/datum/emote/living/carbon/human/wing
key = "wing"
key_third_person = "wings"
message = "their wings."
/datum/emote/living/carbon/human/wing/run_emote(mob/user, params)
. = ..()
if(.)
var/mob/living/carbon/human/H = user
if(findtext(select_message_type(user), "open"))
H.OpenWings()
else
H.CloseWings()
/datum/emote/living/carbon/human/wing/select_message_type(mob/user)
. = ..()
var/mob/living/carbon/human/H = user
if("wings" in H.dna.species.mutant_bodyparts)
. = "opens " + message
else
. = "closes " + message
/datum/emote/living/carbon/human/wing/can_run_emote(mob/user)
if(!..())
return FALSE
var/mob/living/carbon/human/H = user
if(H.dna && H.dna.species && (H.dna.features["wings"] != "None"))
return TRUE
//Don't know where else to put this, it's basically an emote
/mob/living/carbon/human/proc/startTailWag()
if(!dna || !dna.species)
return
if("tail_lizard" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "tail_lizard"
dna.species.mutant_bodyparts -= "spines"
dna.species.mutant_bodyparts |= "waggingtail_lizard"
dna.species.mutant_bodyparts |= "waggingspines"
if("tail_human" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "tail_human"
dna.species.mutant_bodyparts |= "waggingtail_human"
if("mam_tail" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "mam_tail"
dna.species.mutant_bodyparts |= "mam_waggingtail"
update_body()
/mob/living/carbon/human/proc/endTailWag()
if(!dna || !dna.species)
return
if("waggingtail_lizard" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "waggingtail_lizard"
dna.species.mutant_bodyparts -= "waggingspines"
dna.species.mutant_bodyparts |= "tail_lizard"
dna.species.mutant_bodyparts |= "spines"
if("waggingtail_human" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "waggingtail_human"
dna.species.mutant_bodyparts |= "tail_human"
if("mam_waggingtail" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "mam_waggingtail"
dna.species.mutant_bodyparts |= "mam_tail"
update_body()
/mob/living/carbon/human/proc/OpenWings()
if(!dna || !dna.species)
return
if("wings" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "wings"
dna.species.mutant_bodyparts |= "wingsopen"
update_body()
/mob/living/carbon/human/proc/CloseWings()
if(!dna || !dna.species)
return
if("wingsopen" in dna.species.mutant_bodyparts)
dna.species.mutant_bodyparts -= "wingsopen"
dna.species.mutant_bodyparts |= "wings"
update_body()
if(isturf(loc))
var/turf/T = loc
T.Entered(src)
//Ayy lmao
File diff suppressed because it is too large Load Diff
@@ -1,421 +1,421 @@
/mob/living/simple_animal/bot/secbot
name = "\improper Securitron"
desc = "A little security robot. He looks less than thrilled."
icon = 'icons/mob/aibots.dmi'
icon_state = "secbot0"
density = 0
anchored = 0
health = 25
maxHealth = 25
damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
pass_flags = PASSMOB
radio_key = /obj/item/device/encryptionkey/secbot //AI Priv + Security
radio_channel = "Security" //Security channel
bot_type = SEC_BOT
model = "Securitron"
bot_core_type = /obj/machinery/bot_core/secbot
var/baton_type = /obj/item/weapon/melee/baton
window_id = "autosec"
window_name = "Automatic Security Unit v1.6"
allow_pai = 0
data_hud_type = DATA_HUD_SECURITY_ADVANCED
var/mob/living/carbon/target
var/oldtarget_name
var/threatlevel = 0
var/target_lastloc //Loc of target when arrested.
var/last_found //There's a delay
var/declare_arrests = 1 //When making an arrest, should it notify everyone on the security channel?
var/idcheck = 0 //If true, arrest people with no IDs
var/weaponscheck = 0 //If true, arrest people for weapons if they lack access
var/check_records = 1 //Does it check security records?
var/arrest_type = 0 //If true, don't handcuff
/mob/living/simple_animal/bot/secbot/beepsky
name = "Officer Beep O'sky"
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
idcheck = 0
weaponscheck = 0
auto_patrol = 1
/mob/living/simple_animal/bot/secbot/beepsky/jr
name = "Officer Pipsqueak"
desc = "It's Officer Beep O'sky's smaller, just-as aggressive cousin, Pipsqueak."
/mob/living/simple_animal/bot/secbot/beepsky/jr/Initialize()
..()
resize = 0.8
update_transform()
/mob/living/simple_animal/bot/secbot/beepsky/explode()
var/turf/Tsec = get_turf(src)
new /obj/item/weapon/stock_parts/cell/potato(Tsec)
var/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/shotglass/S = new(Tsec)
S.reagents.add_reagent("whiskey", 15)
S.on_reagent_change()
..()
/mob/living/simple_animal/bot/secbot/pingsky
name = "Officer Pingsky"
desc = "It's Officer Pingsky! Delegated to satellite guard duty for harbouring anti-human sentiment."
radio_channel = "AI Private"
/mob/living/simple_animal/bot/secbot/Initialize()
..()
icon_state = "secbot[on]"
spawn(3)
var/datum/job/detective/J = new/datum/job/detective
access_card.access += J.get_access()
prev_access = access_card.access
//SECHUD
var/datum/atom_hud/secsensor = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
secsensor.add_hud_to(src)
/mob/living/simple_animal/bot/secbot/turn_on()
..()
icon_state = "secbot[on]"
/mob/living/simple_animal/bot/secbot/turn_off()
..()
icon_state = "secbot[on]"
/mob/living/simple_animal/bot/secbot/bot_reset()
..()
target = null
oldtarget_name = null
anchored = 0
walk_to(src,0)
last_found = world.time
/mob/living/simple_animal/bot/secbot/set_custom_texts()
text_hack = "You overload [name]'s target identification system."
text_dehack = "You reboot [name] and restore the target identification."
text_dehack_fail = "[name] refuses to accept your authority!"
/mob/living/simple_animal/bot/secbot/get_controls(mob/user)
var/dat
dat += hack(user)
dat += showpai(user)
dat += text({"
<TT><B>Securitron v1.6 controls</B></TT><BR><BR>
Status: []<BR>
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
Maintenance panel panel is [open ? "opened" : "closed"]"},
"<A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A>" )
if(!locked || issilicon(user) || IsAdminGhost(user))
dat += text({"<BR>
Arrest Unidentifiable Persons: []<BR>
Arrest for Unauthorized Weapons: []<BR>
Arrest for Warrant: []<BR>
Operating Mode: []<BR>
Report Arrests[]<BR>
Auto Patrol: []"},
"<A href='?src=\ref[src];operation=idcheck'>[idcheck ? "Yes" : "No"]</A>",
"<A href='?src=\ref[src];operation=weaponscheck'>[weaponscheck ? "Yes" : "No"]</A>",
"<A href='?src=\ref[src];operation=ignorerec'>[check_records ? "Yes" : "No"]</A>",
"<A href='?src=\ref[src];operation=switchmode'>[arrest_type ? "Detain" : "Arrest"]</A>",
"<A href='?src=\ref[src];operation=declarearrests'>[declare_arrests ? "Yes" : "No"]</A>",
"<A href='?src=\ref[src];operation=patrol'>[auto_patrol ? "On" : "Off"]</A>" )
return dat
/mob/living/simple_animal/bot/secbot/Topic(href, href_list)
if(..())
return 1
switch(href_list["operation"])
if("idcheck")
idcheck = !idcheck
update_controls()
if("weaponscheck")
weaponscheck = !weaponscheck
update_controls()
if("ignorerec")
check_records = !check_records
update_controls()
if("switchmode")
arrest_type = !arrest_type
update_controls()
if("declarearrests")
declare_arrests = !declare_arrests
update_controls()
/mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/H)
threatlevel = H.assess_threat(src)
threatlevel += 6
if(threatlevel >= 4)
target = H
mode = BOT_HUNT
/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H)
if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM))
retaliate(H)
return ..()
/mob/living/simple_animal/bot/secbot/attackby(obj/item/weapon/W, mob/user, params)
..()
if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry.
return
if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
retaliate(user)
/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
..()
if(emagged == 2)
if(user)
to_chat(user, "<span class='danger'>You short out [src]'s target assessment circuits.</span>")
oldtarget_name = user.name
audible_message("<span class='danger'>[src] buzzes oddly!</span>")
declare_arrests = 0
icon_state = "secbot[on]"
/mob/living/simple_animal/bot/secbot/bullet_act(obj/item/projectile/Proj)
if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet))
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
if(!Proj.nodamage && Proj.damage < src.health)
retaliate(Proj.firer)
..()
/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A)
if(!on)
return
if(iscarbon(A))
var/mob/living/carbon/C = A
if(!C.stunned || arrest_type)
stun_attack(A)
else if(C.canBeHandcuffed() && !C.handcuffed)
cuff(A)
else
..()
/mob/living/simple_animal/bot/secbot/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0)
if(istype(AM, /obj/item))
var/obj/item/I = AM
if(I.throwforce < src.health && I.thrownby && ishuman(I.thrownby))
var/mob/living/carbon/human/H = I.thrownby
retaliate(H)
..()
/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
mode = BOT_ARREST
playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
C.visible_message("<span class='danger'>[src] is trying to put zipties on [C]!</span>",\
"<span class='userdanger'>[src] is trying to put zipties on you!</span>")
spawn(60)
if( !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
return
if(!C.handcuffed)
C.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(C)
C.update_handcuffed()
playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0)
back_to_idle()
/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
icon_state = "secbot-c"
spawn(2)
icon_state = "secbot[on]"
var/threat = 5
if(ishuman(C))
C.stuttering = 5
C.Stun(5)
C.Weaken(5)
var/mob/living/carbon/human/H = C
threat = H.assess_threat(src)
else
C.Weaken(5)
C.stuttering = 5
C.Stun(5)
threat = C.assess_threat()
add_logs(src,C,"stunned")
if(declare_arrests)
var/area/location = get_area(src)
speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag <b>[C]</b> in [location].", radio_channel)
C.visible_message("<span class='danger'>[src] has stunned [C]!</span>",\
"<span class='userdanger'>[src] has stunned you!</span>")
/mob/living/simple_animal/bot/secbot/handle_automated_action()
if(!..())
return
switch(mode)
if(BOT_IDLE) // idle
walk_to(src,0)
look_for_perp() // see if any criminals are in range
if(!mode && auto_patrol) // still idle, and set to patrol
mode = BOT_START_PATROL // switch to patrol mode
if(BOT_HUNT) // hunting for perp
// if can't reach perp for long enough, go idle
if(frustration >= 8)
walk_to(src,0)
back_to_idle()
return
if(target) // make sure target exists
if(Adjacent(target) && isturf(target.loc)) // if right next to perp
stun_attack(target)
mode = BOT_PREP_ARREST
anchored = 1
target_lastloc = target.loc
return
else // not next to perp
var/turf/olddist = get_dist(src, target)
walk_to(src, target,1,4)
if((get_dist(src, target)) >= (olddist))
frustration++
else
frustration = 0
else
back_to_idle()
if(BOT_PREP_ARREST) // preparing to arrest target
// see if he got away. If he's no no longer adjacent or inside a closet or about to get up, we hunt again.
if( !Adjacent(target) || !isturf(target.loc) || target.weakened < 2 )
back_to_hunt()
return
if(iscarbon(target) && target.canBeHandcuffed())
if(!arrest_type)
if(!target.handcuffed) //he's not cuffed? Try to cuff him!
cuff(target)
else
back_to_idle()
return
else
back_to_idle()
return
if(BOT_ARREST)
if(!target)
anchored = 0
mode = BOT_IDLE
last_found = world.time
frustration = 0
return
if(target.handcuffed) //no target or target cuffed? back to idle.
back_to_idle()
return
if(!Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && target.weakened < 2)) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again.
back_to_hunt()
return
else //Try arresting again if the target escapes.
mode = BOT_PREP_ARREST
anchored = 0
if(BOT_START_PATROL)
look_for_perp()
start_patrol()
if(BOT_PATROL)
look_for_perp()
bot_patrol()
return
/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
anchored = 0
mode = BOT_IDLE
target = null
last_found = world.time
frustration = 0
spawn(0)
handle_automated_action() //ensure bot quickly responds
/mob/living/simple_animal/bot/secbot/proc/back_to_hunt()
anchored = 0
frustration = 0
mode = BOT_HUNT
spawn(0)
handle_automated_action() //ensure bot quickly responds
// look for a criminal in view of the bot
/mob/living/simple_animal/bot/secbot/proc/look_for_perp()
anchored = 0
for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
if((C.stat) || (C.handcuffed))
continue
if((C.name == oldtarget_name) && (world.time < last_found + 100))
continue
threatlevel = C.assess_threat(src)
if(!threatlevel)
continue
else if(threatlevel >= 4)
target = C
oldtarget_name = C.name
speak("Level [threatlevel] infraction alert!")
playsound(loc, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, 0)
visible_message("<b>[src]</b> points at [C.name]!")
mode = BOT_HUNT
spawn(0)
handle_automated_action() // ensure bot quickly responds to a perp
break
else
continue
/mob/living/simple_animal/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item)
if(slot_item && slot_item.needs_permit)
return 1
return 0
/mob/living/simple_animal/bot/secbot/explode()
walk_to(src,0)
visible_message("<span class='boldannounce'>[src] blows apart!</span>")
var/turf/Tsec = get_turf(src)
var/obj/item/weapon/secbot_assembly/Sa = new /obj/item/weapon/secbot_assembly(Tsec)
Sa.build_step = 1
Sa.add_overlay("hs_hole")
Sa.created_name = name
new /obj/item/device/assembly/prox_sensor(Tsec)
new baton_type(Tsec)
if(prob(50))
new /obj/item/bodypart/l_arm/robot(Tsec)
do_sparks(3, TRUE, src)
new /obj/effect/decal/cleanable/oil(loc)
..()
/mob/living/simple_animal/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob)
..()
if(!isalien(target))
target = user
mode = BOT_HUNT
/mob/living/simple_animal/bot/secbot/Crossed(atom/movable/AM)
if(ismob(AM) && target)
var/mob/living/carbon/C = AM
if(!istype(C) || !C || in_range(src, target))
return
knockOver(C)
return
..()
/obj/machinery/bot_core/secbot
req_access = list(GLOB.access_security)
/mob/living/simple_animal/bot/secbot
name = "\improper Securitron"
desc = "A little security robot. He looks less than thrilled."
icon = 'icons/mob/aibots.dmi'
icon_state = "secbot0"
density = 0
anchored = 0
health = 25
maxHealth = 25
damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
pass_flags = PASSMOB
radio_key = /obj/item/device/encryptionkey/secbot //AI Priv + Security
radio_channel = "Security" //Security channel
bot_type = SEC_BOT
model = "Securitron"
bot_core_type = /obj/machinery/bot_core/secbot
var/baton_type = /obj/item/weapon/melee/baton
window_id = "autosec"
window_name = "Automatic Security Unit v1.6"
allow_pai = 0
data_hud_type = DATA_HUD_SECURITY_ADVANCED
var/mob/living/carbon/target
var/oldtarget_name
var/threatlevel = 0
var/target_lastloc //Loc of target when arrested.
var/last_found //There's a delay
var/declare_arrests = 1 //When making an arrest, should it notify everyone on the security channel?
var/idcheck = 0 //If true, arrest people with no IDs
var/weaponscheck = 0 //If true, arrest people for weapons if they lack access
var/check_records = 1 //Does it check security records?
var/arrest_type = 0 //If true, don't handcuff
/mob/living/simple_animal/bot/secbot/beepsky
name = "Officer Beep O'sky"
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
idcheck = 0
weaponscheck = 0
auto_patrol = 1
/mob/living/simple_animal/bot/secbot/beepsky/jr
name = "Officer Pipsqueak"
desc = "It's Officer Beep O'sky's smaller, just-as aggressive cousin, Pipsqueak."
/mob/living/simple_animal/bot/secbot/beepsky/jr/Initialize()
..()
resize = 0.8
update_transform()
/mob/living/simple_animal/bot/secbot/beepsky/explode()
var/turf/Tsec = get_turf(src)
new /obj/item/weapon/stock_parts/cell/potato(Tsec)
var/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/shotglass/S = new(Tsec)
S.reagents.add_reagent("whiskey", 15)
S.on_reagent_change()
..()
/mob/living/simple_animal/bot/secbot/pingsky
name = "Officer Pingsky"
desc = "It's Officer Pingsky! Delegated to satellite guard duty for harbouring anti-human sentiment."
radio_channel = "AI Private"
/mob/living/simple_animal/bot/secbot/Initialize()
..()
icon_state = "secbot[on]"
spawn(3)
var/datum/job/detective/J = new/datum/job/detective
access_card.access += J.get_access()
prev_access = access_card.access
//SECHUD
var/datum/atom_hud/secsensor = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
secsensor.add_hud_to(src)
/mob/living/simple_animal/bot/secbot/turn_on()
..()
icon_state = "secbot[on]"
/mob/living/simple_animal/bot/secbot/turn_off()
..()
icon_state = "secbot[on]"
/mob/living/simple_animal/bot/secbot/bot_reset()
..()
target = null
oldtarget_name = null
anchored = 0
walk_to(src,0)
last_found = world.time
/mob/living/simple_animal/bot/secbot/set_custom_texts()
text_hack = "You overload [name]'s target identification system."
text_dehack = "You reboot [name] and restore the target identification."
text_dehack_fail = "[name] refuses to accept your authority!"
/mob/living/simple_animal/bot/secbot/get_controls(mob/user)
var/dat
dat += hack(user)
dat += showpai(user)
dat += text({"
<TT><B>Securitron v1.6 controls</B></TT><BR><BR>
Status: []<BR>
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
Maintenance panel panel is [open ? "opened" : "closed"]"},
"<A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A>" )
if(!locked || issilicon(user) || IsAdminGhost(user))
dat += text({"<BR>
Arrest Unidentifiable Persons: []<BR>
Arrest for Unauthorized Weapons: []<BR>
Arrest for Warrant: []<BR>
Operating Mode: []<BR>
Report Arrests[]<BR>
Auto Patrol: []"},
"<A href='?src=\ref[src];operation=idcheck'>[idcheck ? "Yes" : "No"]</A>",
"<A href='?src=\ref[src];operation=weaponscheck'>[weaponscheck ? "Yes" : "No"]</A>",
"<A href='?src=\ref[src];operation=ignorerec'>[check_records ? "Yes" : "No"]</A>",
"<A href='?src=\ref[src];operation=switchmode'>[arrest_type ? "Detain" : "Arrest"]</A>",
"<A href='?src=\ref[src];operation=declarearrests'>[declare_arrests ? "Yes" : "No"]</A>",
"<A href='?src=\ref[src];operation=patrol'>[auto_patrol ? "On" : "Off"]</A>" )
return dat
/mob/living/simple_animal/bot/secbot/Topic(href, href_list)
if(..())
return 1
switch(href_list["operation"])
if("idcheck")
idcheck = !idcheck
update_controls()
if("weaponscheck")
weaponscheck = !weaponscheck
update_controls()
if("ignorerec")
check_records = !check_records
update_controls()
if("switchmode")
arrest_type = !arrest_type
update_controls()
if("declarearrests")
declare_arrests = !declare_arrests
update_controls()
/mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/H)
threatlevel = H.assess_threat(src)
threatlevel += 6
if(threatlevel >= 4)
target = H
mode = BOT_HUNT
/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H)
if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM))
retaliate(H)
return ..()
/mob/living/simple_animal/bot/secbot/attackby(obj/item/weapon/W, mob/user, params)
..()
if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry.
return
if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
retaliate(user)
/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
..()
if(emagged == 2)
if(user)
to_chat(user, "<span class='danger'>You short out [src]'s target assessment circuits.</span>")
oldtarget_name = user.name
audible_message("<span class='danger'>[src] buzzes oddly!</span>")
declare_arrests = 0
icon_state = "secbot[on]"
/mob/living/simple_animal/bot/secbot/bullet_act(obj/item/projectile/Proj)
if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet))
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
if(!Proj.nodamage && Proj.damage < src.health)
retaliate(Proj.firer)
..()
/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A)
if(!on)
return
if(iscarbon(A))
var/mob/living/carbon/C = A
if(!C.stunned || arrest_type)
stun_attack(A)
else if(C.canBeHandcuffed() && !C.handcuffed)
cuff(A)
else
..()
/mob/living/simple_animal/bot/secbot/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0)
if(istype(AM, /obj/item))
var/obj/item/I = AM
if(I.throwforce < src.health && I.thrownby && ishuman(I.thrownby))
var/mob/living/carbon/human/H = I.thrownby
retaliate(H)
..()
/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
mode = BOT_ARREST
playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
C.visible_message("<span class='danger'>[src] is trying to put zipties on [C]!</span>",\
"<span class='userdanger'>[src] is trying to put zipties on you!</span>")
spawn(60)
if( !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
return
if(!C.handcuffed)
C.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(C)
C.update_handcuffed()
playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0)
back_to_idle()
/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
icon_state = "secbot-c"
spawn(2)
icon_state = "secbot[on]"
var/threat = 5
if(ishuman(C))
C.stuttering = 5
C.Stun(5)
C.Weaken(5)
var/mob/living/carbon/human/H = C
threat = H.assess_threat(src)
else
C.Weaken(5)
C.stuttering = 5
C.Stun(5)
threat = C.assess_threat()
add_logs(src,C,"stunned")
if(declare_arrests)
var/area/location = get_area(src)
speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag <b>[C]</b> in [location].", radio_channel)
C.visible_message("<span class='danger'>[src] has stunned [C]!</span>",\
"<span class='userdanger'>[src] has stunned you!</span>")
/mob/living/simple_animal/bot/secbot/handle_automated_action()
if(!..())
return
switch(mode)
if(BOT_IDLE) // idle
walk_to(src,0)
look_for_perp() // see if any criminals are in range
if(!mode && auto_patrol) // still idle, and set to patrol
mode = BOT_START_PATROL // switch to patrol mode
if(BOT_HUNT) // hunting for perp
// if can't reach perp for long enough, go idle
if(frustration >= 8)
walk_to(src,0)
back_to_idle()
return
if(target) // make sure target exists
if(Adjacent(target) && isturf(target.loc)) // if right next to perp
stun_attack(target)
mode = BOT_PREP_ARREST
anchored = 1
target_lastloc = target.loc
return
else // not next to perp
var/turf/olddist = get_dist(src, target)
walk_to(src, target,1,4)
if((get_dist(src, target)) >= (olddist))
frustration++
else
frustration = 0
else
back_to_idle()
if(BOT_PREP_ARREST) // preparing to arrest target
// see if he got away. If he's no no longer adjacent or inside a closet or about to get up, we hunt again.
if( !Adjacent(target) || !isturf(target.loc) || target.weakened < 2 )
back_to_hunt()
return
if(iscarbon(target) && target.canBeHandcuffed())
if(!arrest_type)
if(!target.handcuffed) //he's not cuffed? Try to cuff him!
cuff(target)
else
back_to_idle()
return
else
back_to_idle()
return
if(BOT_ARREST)
if(!target)
anchored = 0
mode = BOT_IDLE
last_found = world.time
frustration = 0
return
if(target.handcuffed) //no target or target cuffed? back to idle.
back_to_idle()
return
if(!Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && target.weakened < 2)) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again.
back_to_hunt()
return
else //Try arresting again if the target escapes.
mode = BOT_PREP_ARREST
anchored = 0
if(BOT_START_PATROL)
look_for_perp()
start_patrol()
if(BOT_PATROL)
look_for_perp()
bot_patrol()
return
/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
anchored = 0
mode = BOT_IDLE
target = null
last_found = world.time
frustration = 0
spawn(0)
handle_automated_action() //ensure bot quickly responds
/mob/living/simple_animal/bot/secbot/proc/back_to_hunt()
anchored = 0
frustration = 0
mode = BOT_HUNT
spawn(0)
handle_automated_action() //ensure bot quickly responds
// look for a criminal in view of the bot
/mob/living/simple_animal/bot/secbot/proc/look_for_perp()
anchored = 0
for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
if((C.stat) || (C.handcuffed))
continue
if((C.name == oldtarget_name) && (world.time < last_found + 100))
continue
threatlevel = C.assess_threat(src)
if(!threatlevel)
continue
else if(threatlevel >= 4)
target = C
oldtarget_name = C.name
speak("Level [threatlevel] infraction alert!")
playsound(loc, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, 0)
visible_message("<b>[src]</b> points at [C.name]!")
mode = BOT_HUNT
spawn(0)
handle_automated_action() // ensure bot quickly responds to a perp
break
else
continue
/mob/living/simple_animal/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item)
if(slot_item && slot_item.needs_permit)
return 1
return 0
/mob/living/simple_animal/bot/secbot/explode()
walk_to(src,0)
visible_message("<span class='boldannounce'>[src] blows apart!</span>")
var/turf/Tsec = get_turf(src)
var/obj/item/weapon/secbot_assembly/Sa = new /obj/item/weapon/secbot_assembly(Tsec)
Sa.build_step = 1
Sa.add_overlay("hs_hole")
Sa.created_name = name
new /obj/item/device/assembly/prox_sensor(Tsec)
new baton_type(Tsec)
if(prob(50))
new /obj/item/bodypart/l_arm/robot(Tsec)
do_sparks(3, TRUE, src)
new /obj/effect/decal/cleanable/oil(loc)
..()
/mob/living/simple_animal/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob)
..()
if(!isalien(target))
target = user
mode = BOT_HUNT
/mob/living/simple_animal/bot/secbot/Crossed(atom/movable/AM)
if(ismob(AM) && target)
var/mob/living/carbon/C = AM
if(!istype(C) || !C || in_range(src, target))
return
knockOver(C)
return
..()
/obj/machinery/bot_core/secbot
req_access = list(GLOB.access_security)
@@ -1,57 +1,57 @@
/obj/item/projectile/hivebotbullet
damage = 10
damage_type = BRUTE
/mob/living/simple_animal/hostile/hivebot
name = "hivebot"
desc = "A small robot."
icon = 'icons/mob/hivebot.dmi'
icon_state = "basic"
icon_living = "basic"
icon_dead = "basic"
gender = NEUTER
health = 15
maxHealth = 15
healable = 0
melee_damage_lower = 2
melee_damage_upper = 3
attacktext = "claws"
attack_sound = 'sound/weapons/bladeslice.ogg'
projectilesound = 'sound/weapons/Gunshot.ogg'
projectiletype = /obj/item/projectile/hivebotbullet
faction = list("hivebot")
check_friendly_fire = 1
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
speak_emote = list("states")
gold_core_spawnable = 1
del_on_death = 1
loot = list(/obj/effect/decal/cleanable/robot_debris)
/mob/living/simple_animal/hostile/hivebot/Initialize()
..()
deathmessage = "[src] blows apart!"
/mob/living/simple_animal/hostile/hivebot/range
name = "hivebot"
desc = "A smallish robot, this one is armed!"
ranged = 1
retreat_distance = 5
minimum_distance = 5
/mob/living/simple_animal/hostile/hivebot/rapid
ranged = 1
rapid = 1
retreat_distance = 5
minimum_distance = 5
/mob/living/simple_animal/hostile/hivebot/strong
name = "strong hivebot"
desc = "A robot, this one is armed and looks tough!"
health = 80
maxHealth = 80
ranged = 1
/mob/living/simple_animal/hostile/hivebot/death(gibbed)
do_sparks(3, TRUE, src)
/obj/item/projectile/hivebotbullet
damage = 10
damage_type = BRUTE
/mob/living/simple_animal/hostile/hivebot
name = "hivebot"
desc = "A small robot."
icon = 'icons/mob/hivebot.dmi'
icon_state = "basic"
icon_living = "basic"
icon_dead = "basic"
gender = NEUTER
health = 15
maxHealth = 15
healable = 0
melee_damage_lower = 2
melee_damage_upper = 3
attacktext = "claws"
attack_sound = 'sound/weapons/bladeslice.ogg'
projectilesound = 'sound/weapons/Gunshot.ogg'
projectiletype = /obj/item/projectile/hivebotbullet
faction = list("hivebot")
check_friendly_fire = 1
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
speak_emote = list("states")
gold_core_spawnable = 1
del_on_death = 1
loot = list(/obj/effect/decal/cleanable/robot_debris)
/mob/living/simple_animal/hostile/hivebot/Initialize()
..()
deathmessage = "[src] blows apart!"
/mob/living/simple_animal/hostile/hivebot/range
name = "hivebot"
desc = "A smallish robot, this one is armed!"
ranged = 1
retreat_distance = 5
minimum_distance = 5
/mob/living/simple_animal/hostile/hivebot/rapid
ranged = 1
rapid = 1
retreat_distance = 5
minimum_distance = 5
/mob/living/simple_animal/hostile/hivebot/strong
name = "strong hivebot"
desc = "A robot, this one is armed and looks tough!"
health = 80
maxHealth = 80
ranged = 1
/mob/living/simple_animal/hostile/hivebot/death(gibbed)
do_sparks(3, TRUE, src)
..(1)
+236 -236
View File
@@ -1,236 +1,236 @@
/obj/item/ammo_casing/energy
name = "energy weapon lens"
desc = "The part of the gun that makes the laser go pew"
caliber = "energy"
projectile_type = /obj/item/projectile/energy
var/e_cost = 100 //The amount of energy a cell needs to expend to create this shot.
var/select_name = "energy"
fire_sound = 'sound/weapons/Laser.ogg'
firing_effect_type = /obj/effect/overlay/temp/dir_setting/firing_effect/energy
/obj/item/ammo_casing/energy/chameleon
e_cost = 0
var/list/projectile_vars = list()
/obj/item/ammo_casing/energy/chameleon/ready_proj()
. = ..()
if(!BB)
newshot()
for(var/V in projectile_vars)
if(BB.vars[V])
BB.vars[V] = projectile_vars[V]
/obj/item/ammo_casing/energy/laser
projectile_type = /obj/item/projectile/beam/laser
select_name = "kill"
/obj/item/ammo_casing/energy/lasergun
projectile_type = /obj/item/projectile/beam/laser
e_cost = 83
select_name = "kill"
/obj/item/ammo_casing/energy/laser/hos
e_cost = 100
/obj/item/ammo_casing/energy/laser/practice
projectile_type = /obj/item/projectile/beam/practice
select_name = "practice"
/obj/item/ammo_casing/energy/laser/scatter
projectile_type = /obj/item/projectile/beam/scatter
pellets = 5
variance = 25
select_name = "scatter"
/obj/item/ammo_casing/energy/laser/scatter/disabler
projectile_type = /obj/item/projectile/beam/disabler
pellets = 3
variance = 15
/obj/item/ammo_casing/energy/laser/heavy
projectile_type = /obj/item/projectile/beam/laser/heavylaser
select_name = "anti-vehicle"
fire_sound = 'sound/weapons/lasercannonfire.ogg'
/obj/item/ammo_casing/energy/laser/pulse
projectile_type = /obj/item/projectile/beam/pulse
e_cost = 200
select_name = "DESTROY"
fire_sound = 'sound/weapons/pulse.ogg'
/obj/item/ammo_casing/energy/laser/bluetag
projectile_type = /obj/item/projectile/beam/lasertag/bluetag
select_name = "bluetag"
/obj/item/ammo_casing/energy/laser/redtag
projectile_type = /obj/item/projectile/beam/lasertag/redtag
select_name = "redtag"
/obj/item/ammo_casing/energy/xray
projectile_type = /obj/item/projectile/beam/xray
e_cost = 50
fire_sound = 'sound/weapons/laser3.ogg'
/obj/item/ammo_casing/energy/electrode
projectile_type = /obj/item/projectile/energy/electrode
select_name = "stun"
fire_sound = 'sound/weapons/taser.ogg'
e_cost = 200
/obj/item/ammo_casing/energy/electrode/gun
fire_sound = 'sound/weapons/gunshot.ogg'
e_cost = 100
/obj/item/ammo_casing/energy/electrode/hos
e_cost = 200
/obj/item/ammo_casing/energy/ion
projectile_type = /obj/item/projectile/ion
select_name = "ion"
fire_sound = 'sound/weapons/IonRifle.ogg'
/obj/item/ammo_casing/energy/declone
projectile_type = /obj/item/projectile/energy/declone
select_name = "declone"
fire_sound = 'sound/weapons/pulse3.ogg'
/obj/item/ammo_casing/energy/mindflayer
projectile_type = /obj/item/projectile/beam/mindflayer
select_name = "MINDFUCK"
fire_sound = 'sound/weapons/Laser.ogg'
/obj/item/ammo_casing/energy/flora
fire_sound = 'sound/effects/stealthoff.ogg'
/obj/item/ammo_casing/energy/flora/yield
projectile_type = /obj/item/projectile/energy/florayield
select_name = "yield"
/obj/item/ammo_casing/energy/flora/mut
projectile_type = /obj/item/projectile/energy/floramut
select_name = "mutation"
/obj/item/ammo_casing/energy/temp
projectile_type = /obj/item/projectile/temp
select_name = "freeze"
e_cost = 250
fire_sound = 'sound/weapons/pulse3.ogg'
/obj/item/ammo_casing/energy/temp/hot
projectile_type = /obj/item/projectile/temp/hot
select_name = "bake"
/obj/item/ammo_casing/energy/meteor
projectile_type = /obj/item/projectile/meteor
select_name = "goddamn meteor"
/obj/item/ammo_casing/energy/disabler
projectile_type = /obj/item/projectile/beam/disabler
select_name = "disable"
e_cost = 50
fire_sound = 'sound/weapons/taser2.ogg'
/obj/item/ammo_casing/energy/plasma
projectile_type = /obj/item/projectile/plasma
select_name = "plasma burst"
fire_sound = 'sound/weapons/plasma_cutter.ogg'
delay = 15
e_cost = 25
/obj/item/ammo_casing/energy/plasma/adv
projectile_type = /obj/item/projectile/plasma/adv
delay = 10
e_cost = 10
/obj/item/ammo_casing/energy/wormhole
projectile_type = /obj/item/projectile/beam/wormhole
e_cost = 0
fire_sound = 'sound/weapons/pulse3.ogg'
var/obj/item/weapon/gun/energy/wormhole_projector/gun = null
select_name = "blue"
/obj/item/ammo_casing/energy/wormhole/orange
projectile_type = /obj/item/projectile/beam/wormhole/orange
select_name = "orange"
/obj/item/ammo_casing/energy/bolt
projectile_type = /obj/item/projectile/energy/bolt
select_name = "bolt"
e_cost = 500
fire_sound = 'sound/weapons/Genhit.ogg'
/obj/item/ammo_casing/energy/bolt/halloween
projectile_type = /obj/item/projectile/energy/bolt/halloween
/obj/item/ammo_casing/energy/bolt/large
projectile_type = /obj/item/projectile/energy/bolt/large
select_name = "heavy bolt"
/obj/item/ammo_casing/energy/net
projectile_type = /obj/item/projectile/energy/net
select_name = "netting"
pellets = 6
variance = 40
/obj/item/ammo_casing/energy/trap
projectile_type = /obj/item/projectile/energy/trap
select_name = "snare"
/obj/item/ammo_casing/energy/instakill
projectile_type = /obj/item/projectile/beam/instakill
e_cost = 0
select_name = "DESTROY"
/obj/item/ammo_casing/energy/instakill/blue
projectile_type = /obj/item/projectile/beam/instakill/blue
/obj/item/ammo_casing/energy/instakill/red
projectile_type = /obj/item/projectile/beam/instakill/red
/obj/item/ammo_casing/energy/tesla_revolver
fire_sound = 'sound/magic/lightningbolt.ogg'
e_cost = 200
select_name = "stun"
projectile_type = /obj/item/projectile/energy/tesla/revolver
/obj/item/ammo_casing/energy/gravityrepulse
projectile_type = /obj/item/projectile/gravityrepulse
e_cost = 0
fire_sound = 'sound/weapons/wave.ogg'
select_name = "repulse"
delay = 50
var/obj/item/weapon/gun/energy/gravity_gun/gun = null
/obj/item/ammo_casing/energy/gravityrepulse/New(var/obj/item/weapon/gun/energy/gravity_gun/G)
gun = G
/obj/item/ammo_casing/energy/gravityattract
projectile_type = /obj/item/projectile/gravityattract
e_cost = 0
fire_sound = 'sound/weapons/wave.ogg'
select_name = "attract"
delay = 50
var/obj/item/weapon/gun/energy/gravity_gun/gun = null
/obj/item/ammo_casing/energy/gravityattract/New(var/obj/item/weapon/gun/energy/gravity_gun/G)
gun = G
/obj/item/ammo_casing/energy/gravitychaos
projectile_type = /obj/item/projectile/gravitychaos
e_cost = 0
fire_sound = 'sound/weapons/wave.ogg'
select_name = "chaos"
delay = 50
var/obj/item/weapon/gun/energy/gravity_gun/gun = null
/obj/item/ammo_casing/energy/gravitychaos/New(var/obj/item/weapon/gun/energy/gravity_gun/G)
gun = G
/obj/item/ammo_casing/energy/plasma
projectile_type = /obj/item/projectile/plasma
select_name = "plasma burst"
fire_sound = 'sound/weapons/pulse.ogg'
/obj/item/ammo_casing/energy/plasma/adv
projectile_type = /obj/item/projectile/plasma/adv
/obj/item/ammo_casing/energy
name = "energy weapon lens"
desc = "The part of the gun that makes the laser go pew"
caliber = "energy"
projectile_type = /obj/item/projectile/energy
var/e_cost = 100 //The amount of energy a cell needs to expend to create this shot.
var/select_name = "energy"
fire_sound = 'sound/weapons/Laser.ogg'
firing_effect_type = /obj/effect/overlay/temp/dir_setting/firing_effect/energy
/obj/item/ammo_casing/energy/chameleon
e_cost = 0
var/list/projectile_vars = list()
/obj/item/ammo_casing/energy/chameleon/ready_proj()
. = ..()
if(!BB)
newshot()
for(var/V in projectile_vars)
if(BB.vars[V])
BB.vars[V] = projectile_vars[V]
/obj/item/ammo_casing/energy/laser
projectile_type = /obj/item/projectile/beam/laser
select_name = "kill"
/obj/item/ammo_casing/energy/lasergun
projectile_type = /obj/item/projectile/beam/laser
e_cost = 83
select_name = "kill"
/obj/item/ammo_casing/energy/laser/hos
e_cost = 100
/obj/item/ammo_casing/energy/laser/practice
projectile_type = /obj/item/projectile/beam/practice
select_name = "practice"
/obj/item/ammo_casing/energy/laser/scatter
projectile_type = /obj/item/projectile/beam/scatter
pellets = 5
variance = 25
select_name = "scatter"
/obj/item/ammo_casing/energy/laser/scatter/disabler
projectile_type = /obj/item/projectile/beam/disabler
pellets = 3
variance = 15
/obj/item/ammo_casing/energy/laser/heavy
projectile_type = /obj/item/projectile/beam/laser/heavylaser
select_name = "anti-vehicle"
fire_sound = 'sound/weapons/lasercannonfire.ogg'
/obj/item/ammo_casing/energy/laser/pulse
projectile_type = /obj/item/projectile/beam/pulse
e_cost = 200
select_name = "DESTROY"
fire_sound = 'sound/weapons/pulse.ogg'
/obj/item/ammo_casing/energy/laser/bluetag
projectile_type = /obj/item/projectile/beam/lasertag/bluetag
select_name = "bluetag"
/obj/item/ammo_casing/energy/laser/redtag
projectile_type = /obj/item/projectile/beam/lasertag/redtag
select_name = "redtag"
/obj/item/ammo_casing/energy/xray
projectile_type = /obj/item/projectile/beam/xray
e_cost = 50
fire_sound = 'sound/weapons/laser3.ogg'
/obj/item/ammo_casing/energy/electrode
projectile_type = /obj/item/projectile/energy/electrode
select_name = "stun"
fire_sound = 'sound/weapons/taser.ogg'
e_cost = 200
/obj/item/ammo_casing/energy/electrode/gun
fire_sound = 'sound/weapons/gunshot.ogg'
e_cost = 100
/obj/item/ammo_casing/energy/electrode/hos
e_cost = 200
/obj/item/ammo_casing/energy/ion
projectile_type = /obj/item/projectile/ion
select_name = "ion"
fire_sound = 'sound/weapons/IonRifle.ogg'
/obj/item/ammo_casing/energy/declone
projectile_type = /obj/item/projectile/energy/declone
select_name = "declone"
fire_sound = 'sound/weapons/pulse3.ogg'
/obj/item/ammo_casing/energy/mindflayer
projectile_type = /obj/item/projectile/beam/mindflayer
select_name = "MINDFUCK"
fire_sound = 'sound/weapons/Laser.ogg'
/obj/item/ammo_casing/energy/flora
fire_sound = 'sound/effects/stealthoff.ogg'
/obj/item/ammo_casing/energy/flora/yield
projectile_type = /obj/item/projectile/energy/florayield
select_name = "yield"
/obj/item/ammo_casing/energy/flora/mut
projectile_type = /obj/item/projectile/energy/floramut
select_name = "mutation"
/obj/item/ammo_casing/energy/temp
projectile_type = /obj/item/projectile/temp
select_name = "freeze"
e_cost = 250
fire_sound = 'sound/weapons/pulse3.ogg'
/obj/item/ammo_casing/energy/temp/hot
projectile_type = /obj/item/projectile/temp/hot
select_name = "bake"
/obj/item/ammo_casing/energy/meteor
projectile_type = /obj/item/projectile/meteor
select_name = "goddamn meteor"
/obj/item/ammo_casing/energy/disabler
projectile_type = /obj/item/projectile/beam/disabler
select_name = "disable"
e_cost = 50
fire_sound = 'sound/weapons/taser2.ogg'
/obj/item/ammo_casing/energy/plasma
projectile_type = /obj/item/projectile/plasma
select_name = "plasma burst"
fire_sound = 'sound/weapons/plasma_cutter.ogg'
delay = 15
e_cost = 25
/obj/item/ammo_casing/energy/plasma/adv
projectile_type = /obj/item/projectile/plasma/adv
delay = 10
e_cost = 10
/obj/item/ammo_casing/energy/wormhole
projectile_type = /obj/item/projectile/beam/wormhole
e_cost = 0
fire_sound = 'sound/weapons/pulse3.ogg'
var/obj/item/weapon/gun/energy/wormhole_projector/gun = null
select_name = "blue"
/obj/item/ammo_casing/energy/wormhole/orange
projectile_type = /obj/item/projectile/beam/wormhole/orange
select_name = "orange"
/obj/item/ammo_casing/energy/bolt
projectile_type = /obj/item/projectile/energy/bolt
select_name = "bolt"
e_cost = 500
fire_sound = 'sound/weapons/Genhit.ogg'
/obj/item/ammo_casing/energy/bolt/halloween
projectile_type = /obj/item/projectile/energy/bolt/halloween
/obj/item/ammo_casing/energy/bolt/large
projectile_type = /obj/item/projectile/energy/bolt/large
select_name = "heavy bolt"
/obj/item/ammo_casing/energy/net
projectile_type = /obj/item/projectile/energy/net
select_name = "netting"
pellets = 6
variance = 40
/obj/item/ammo_casing/energy/trap
projectile_type = /obj/item/projectile/energy/trap
select_name = "snare"
/obj/item/ammo_casing/energy/instakill
projectile_type = /obj/item/projectile/beam/instakill
e_cost = 0
select_name = "DESTROY"
/obj/item/ammo_casing/energy/instakill/blue
projectile_type = /obj/item/projectile/beam/instakill/blue
/obj/item/ammo_casing/energy/instakill/red
projectile_type = /obj/item/projectile/beam/instakill/red
/obj/item/ammo_casing/energy/tesla_revolver
fire_sound = 'sound/magic/lightningbolt.ogg'
e_cost = 200
select_name = "stun"
projectile_type = /obj/item/projectile/energy/tesla/revolver
/obj/item/ammo_casing/energy/gravityrepulse
projectile_type = /obj/item/projectile/gravityrepulse
e_cost = 0
fire_sound = 'sound/weapons/wave.ogg'
select_name = "repulse"
delay = 50
var/obj/item/weapon/gun/energy/gravity_gun/gun = null
/obj/item/ammo_casing/energy/gravityrepulse/New(var/obj/item/weapon/gun/energy/gravity_gun/G)
gun = G
/obj/item/ammo_casing/energy/gravityattract
projectile_type = /obj/item/projectile/gravityattract
e_cost = 0
fire_sound = 'sound/weapons/wave.ogg'
select_name = "attract"
delay = 50
var/obj/item/weapon/gun/energy/gravity_gun/gun = null
/obj/item/ammo_casing/energy/gravityattract/New(var/obj/item/weapon/gun/energy/gravity_gun/G)
gun = G
/obj/item/ammo_casing/energy/gravitychaos
projectile_type = /obj/item/projectile/gravitychaos
e_cost = 0
fire_sound = 'sound/weapons/wave.ogg'
select_name = "chaos"
delay = 50
var/obj/item/weapon/gun/energy/gravity_gun/gun = null
/obj/item/ammo_casing/energy/gravitychaos/New(var/obj/item/weapon/gun/energy/gravity_gun/G)
gun = G
/obj/item/ammo_casing/energy/plasma
projectile_type = /obj/item/projectile/plasma
select_name = "plasma burst"
fire_sound = 'sound/weapons/pulse.ogg'
/obj/item/ammo_casing/energy/plasma/adv
projectile_type = /obj/item/projectile/plasma/adv
+313 -313
View File
@@ -1,313 +1,313 @@
/obj/item/projectile
name = "projectile"
icon = 'icons/obj/projectiles.dmi'
icon_state = "bullet"
density = 0
anchored = 1
flags = ABSTRACT
pass_flags = PASSTABLE
mouse_opacity = 0
hitsound = 'sound/weapons/pierce.ogg'
var/hitsound_wall = ""
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/def_zone = "" //Aiming at
var/mob/firer = null//Who shot it
var/suppressed = 0 //Attack message
var/yo = null
var/xo = null
var/current = null
var/atom/original = null // the original target clicked
var/turf/starting = null // the projectile's starting turf
var/list/permutated = list() // we've passed through these atoms, don't try to hit them again
var/paused = FALSE //for suspending the projectile midair
var/p_x = 16
var/p_y = 16 // the pixel location of the tile that the player clicked. Default is the center
var/speed = 0.8 //Amount of deciseconds it takes for projectile to travel
var/Angle = 0
var/spread = 0 //amount (in degrees) of projectile spread
var/legacy = 0 //legacy projectile system
animate_movement = 0 //Use SLIDE_STEPS in conjunction with legacy
var/damage = 10
var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE are the only things that should be in here
var/nodamage = 0 //Determines if the projectile will skip any damage inflictions
var/flag = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb
var/projectile_type = /obj/item/projectile
var/range = 50 //This will de-increment every step. When 0, it will delete the projectile.
//Effects
var/stun = 0
var/weaken = 0
var/paralyze = 0
var/irradiate = 0
var/stutter = 0
var/slur = 0
var/eyeblur = 0
var/drowsy = 0
var/stamina = 0
var/jitter = 0
var/forcedodge = 0 //to pass through everything
var/dismemberment = 0 //The higher the number, the greater the bonus to dismembering. 0 will not dismember at all.
var/impact_effect_type //what type of impact effect to show when hitting something
var/log_override = FALSE //is this type spammed enough to not log? (KAs)
/obj/item/projectile/New()
permutated = list()
return ..()
/obj/item/projectile/proc/Range()
range--
if(range <= 0 && loc)
on_range()
/obj/item/projectile/proc/on_range() //if we want there to be effects when they reach the end of their range
qdel(src)
//to get the correct limb (if any) for the projectile hit message
/mob/living/proc/check_limb_hit(hit_zone)
if(has_limbs)
return hit_zone
/mob/living/carbon/check_limb_hit(hit_zone)
if(get_bodypart(hit_zone))
return hit_zone
else //when a limb is missing the damage is actually passed to the chest
return "chest"
/obj/item/projectile/proc/prehit(atom/target)
return
/obj/item/projectile/proc/on_hit(atom/target, blocked = 0)
var/turf/target_loca = get_turf(target)
if(!isliving(target))
if(impact_effect_type)
new impact_effect_type(target_loca, target, src)
return 0
var/mob/living/L = target
if(blocked != 100) // not completely blocked
if(damage && L.blood_volume && damage_type == BRUTE)
var/splatter_dir = dir
if(starting)
splatter_dir = get_dir(starting, target_loca)
if(isalien(L))
new /obj/effect/overlay/temp/dir_setting/bloodsplatter/xenosplatter(target_loca, splatter_dir)
else
new /obj/effect/overlay/temp/dir_setting/bloodsplatter(target_loca, splatter_dir)
if(prob(33))
L.add_splatter_floor(target_loca)
else if(impact_effect_type)
new impact_effect_type(target_loca, target, src)
var/organ_hit_text = ""
var/limb_hit = L.check_limb_hit(def_zone)//to get the correct message info.
if(limb_hit)
organ_hit_text = " in \the [parse_zone(limb_hit)]"
if(suppressed)
playsound(loc, hitsound, 5, 1, -1)
to_chat(L, "<span class='userdanger'>You're shot by \a [src][organ_hit_text]!</span>")
else
if(hitsound)
var/volume = vol_by_damage()
playsound(loc, hitsound, volume, 1, -1)
L.visible_message("<span class='danger'>[L] is hit by \a [src][organ_hit_text]!</span>", \
"<span class='userdanger'>[L] is hit by \a [src][organ_hit_text]!</span>", null, COMBAT_MESSAGE_RANGE)
L.on_hit(src)
var/reagent_note
if(reagents && reagents.reagent_list)
reagent_note = " REAGENTS:"
for(var/datum/reagent/R in reagents.reagent_list)
reagent_note += R.id + " ("
reagent_note += num2text(R.volume) + ") "
add_logs(firer, L, "shot", src, reagent_note)
return L.apply_effects(stun, weaken, paralyze, irradiate, slur, stutter, eyeblur, drowsy, blocked, stamina, jitter)
/obj/item/projectile/proc/vol_by_damage()
if(src.damage)
return Clamp((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then clamp the value between 30 and 100
else
return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume
/obj/item/projectile/Bump(atom/A, yes)
if(!yes) //prevents double bumps.
return
if(firer)
if(A == firer || (A == firer.loc && istype(A, /obj/mecha))) //cannot shoot yourself or your mech
loc = A.loc
return 0
var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
if(isturf(A) && hitsound_wall)
var/volume = Clamp(vol_by_damage() + 20, 0, 100)
if(suppressed)
volume = 5
playsound(loc, hitsound_wall, volume, 1, -1)
var/turf/target_turf = get_turf(A)
prehit(A)
var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null
if(permutation == -1 || forcedodge)// the bullet passes through a dense object!
loc = target_turf
if(A)
permutated.Add(A)
return 0
else
if(A && A.density && !ismob(A) && !(A.flags & ON_BORDER)) //if we hit a dense non-border obj or dense turf then we also hit one of the mobs on that tile.
var/list/mobs_list = list()
for(var/mob/living/L in target_turf)
mobs_list += L
if(mobs_list.len)
var/mob/living/picked_mob = pick(mobs_list)
prehit(picked_mob)
picked_mob.bullet_act(src, def_zone)
qdel(src)
/obj/item/projectile/Process_Spacemove(var/movement_dir = 0)
return 1 //Bullets don't drift in space
/obj/item/projectile/proc/fire(setAngle, atom/direct_target)
if(!log_override && firer && original)
add_logs(firer, original, "fired at", src, " [get_area(src)]")
if(direct_target)
prehit(direct_target)
direct_target.bullet_act(src, def_zone)
qdel(src)
return
if(setAngle)
Angle = setAngle
var/old_pixel_x = pixel_x
var/old_pixel_y = pixel_y
if(!legacy) //new projectiles
set waitfor = 0
var/next_run = world.time
while(loc)
if(paused)
next_run = world.time
sleep(1)
continue
if((!( current ) || loc == current))
current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z)
if(!Angle)
Angle=round(Get_Angle(src,current))
if(spread)
Angle += (rand() - 0.5) * spread
var/matrix/M = new
M.Turn(Angle)
transform = M
var/Pixel_x=round((sin(Angle)+16*sin(Angle)*2), 1) //round() is a floor operation when only one argument is supplied, we don't want that here
var/Pixel_y=round((cos(Angle)+16*cos(Angle)*2), 1)
var/pixel_x_offset = old_pixel_x + Pixel_x
var/pixel_y_offset = old_pixel_y + Pixel_y
var/new_x = x
var/new_y = y
while(pixel_x_offset > 16)
pixel_x_offset -= 32
old_pixel_x -= 32
new_x++// x++
while(pixel_x_offset < -16)
pixel_x_offset += 32
old_pixel_x += 32
new_x--
while(pixel_y_offset > 16)
pixel_y_offset -= 32
old_pixel_y -= 32
new_y++
while(pixel_y_offset < -16)
pixel_y_offset += 32
old_pixel_y += 32
new_y--
pixel_x = old_pixel_x
pixel_y = old_pixel_y
step_towards(src, locate(new_x, new_y, z))
next_run += max(world.tick_lag, speed)
var/delay = next_run - world.time
if(delay <= world.tick_lag*2)
pixel_x = pixel_x_offset
pixel_y = pixel_y_offset
else
animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (delay <= 3 ? delay - 1 : delay)), flags = ANIMATION_END_NOW)
old_pixel_x = pixel_x_offset
old_pixel_y = pixel_y_offset
if(original && (original.layer>=2.75) || ismob(original))
if(loc == get_turf(original))
if(!(original in permutated))
Bump(original, 1)
Range()
if (delay > 0)
sleep(delay)
else //old projectile system
set waitfor = 0
while(loc)
if(!paused)
if((!( current ) || loc == current))
current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z)
step_towards(src, current)
if(original && (original.layer>=2.75) || ismob(original))
if(loc == get_turf(original))
if(!(original in permutated))
Bump(original, 1)
Range()
sleep(config.run_speed * 0.9)
/obj/item/projectile/proc/preparePixelProjectile(atom/target, var/turf/targloc, mob/living/user, params, spread)
var/turf/curloc = get_turf(user)
src.loc = get_turf(user)
src.starting = get_turf(user)
src.current = curloc
src.yo = targloc.y - curloc.y
src.xo = targloc.x - curloc.x
if(params)
var/list/mouse_control = params2list(params)
if(mouse_control["icon-x"])
src.p_x = text2num(mouse_control["icon-x"])
if(mouse_control["icon-y"])
src.p_y = text2num(mouse_control["icon-y"])
if(mouse_control["screen-loc"])
//Split screen-loc up into X+Pixel_X and Y+Pixel_Y
var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",")
//Split X+Pixel_X up into list(X, Pixel_X)
var/list/screen_loc_X = splittext(screen_loc_params[1],":")
//Split Y+Pixel_Y up into list(Y, Pixel_Y)
var/list/screen_loc_Y = splittext(screen_loc_params[2],":")
// to_chat(world, "X: [screen_loc_X[1]] PixelX: [screen_loc_X[2]] / Y: [screen_loc_Y[1]] PixelY: [screen_loc_Y[2]]")
var/x = text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32
var/y = text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32
//Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average.
var/screenview = (user.client.view * 2 + 1) * world.icon_size //Refer to http://www.byond.com/docs/ref/info.html#/client/var/view for mad maths
var/ox = round(screenview/2) //"origin" x
var/oy = round(screenview/2) //"origin" y
// to_chat(world, "Pixel position: [x] [y]")
var/angle = Atan2(y - oy, x - ox)
// to_chat(world, "Angle: [angle]")
src.Angle = angle
if(spread)
src.Angle += spread
/obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a projectile is hit by it.
..()
if(isliving(AM) && AM.density && !checkpass(PASSMOB))
Bump(AM, 1)
/obj/item/projectile/Destroy()
return ..()
/obj/item/projectile/experience_pressure_difference()
return
/obj/item/projectile
name = "projectile"
icon = 'icons/obj/projectiles.dmi'
icon_state = "bullet"
density = 0
anchored = 1
flags = ABSTRACT
pass_flags = PASSTABLE
mouse_opacity = 0
hitsound = 'sound/weapons/pierce.ogg'
var/hitsound_wall = ""
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/def_zone = "" //Aiming at
var/mob/firer = null//Who shot it
var/suppressed = 0 //Attack message
var/yo = null
var/xo = null
var/current = null
var/atom/original = null // the original target clicked
var/turf/starting = null // the projectile's starting turf
var/list/permutated = list() // we've passed through these atoms, don't try to hit them again
var/paused = FALSE //for suspending the projectile midair
var/p_x = 16
var/p_y = 16 // the pixel location of the tile that the player clicked. Default is the center
var/speed = 0.8 //Amount of deciseconds it takes for projectile to travel
var/Angle = 0
var/spread = 0 //amount (in degrees) of projectile spread
var/legacy = 0 //legacy projectile system
animate_movement = 0 //Use SLIDE_STEPS in conjunction with legacy
var/damage = 10
var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE are the only things that should be in here
var/nodamage = 0 //Determines if the projectile will skip any damage inflictions
var/flag = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb
var/projectile_type = /obj/item/projectile
var/range = 50 //This will de-increment every step. When 0, it will delete the projectile.
//Effects
var/stun = 0
var/weaken = 0
var/paralyze = 0
var/irradiate = 0
var/stutter = 0
var/slur = 0
var/eyeblur = 0
var/drowsy = 0
var/stamina = 0
var/jitter = 0
var/forcedodge = 0 //to pass through everything
var/dismemberment = 0 //The higher the number, the greater the bonus to dismembering. 0 will not dismember at all.
var/impact_effect_type //what type of impact effect to show when hitting something
var/log_override = FALSE //is this type spammed enough to not log? (KAs)
/obj/item/projectile/New()
permutated = list()
return ..()
/obj/item/projectile/proc/Range()
range--
if(range <= 0 && loc)
on_range()
/obj/item/projectile/proc/on_range() //if we want there to be effects when they reach the end of their range
qdel(src)
//to get the correct limb (if any) for the projectile hit message
/mob/living/proc/check_limb_hit(hit_zone)
if(has_limbs)
return hit_zone
/mob/living/carbon/check_limb_hit(hit_zone)
if(get_bodypart(hit_zone))
return hit_zone
else //when a limb is missing the damage is actually passed to the chest
return "chest"
/obj/item/projectile/proc/prehit(atom/target)
return
/obj/item/projectile/proc/on_hit(atom/target, blocked = 0)
var/turf/target_loca = get_turf(target)
if(!isliving(target))
if(impact_effect_type)
new impact_effect_type(target_loca, target, src)
return 0
var/mob/living/L = target
if(blocked != 100) // not completely blocked
if(damage && L.blood_volume && damage_type == BRUTE)
var/splatter_dir = dir
if(starting)
splatter_dir = get_dir(starting, target_loca)
if(isalien(L))
new /obj/effect/overlay/temp/dir_setting/bloodsplatter/xenosplatter(target_loca, splatter_dir)
else
new /obj/effect/overlay/temp/dir_setting/bloodsplatter(target_loca, splatter_dir)
if(prob(33))
L.add_splatter_floor(target_loca)
else if(impact_effect_type)
new impact_effect_type(target_loca, target, src)
var/organ_hit_text = ""
var/limb_hit = L.check_limb_hit(def_zone)//to get the correct message info.
if(limb_hit)
organ_hit_text = " in \the [parse_zone(limb_hit)]"
if(suppressed)
playsound(loc, hitsound, 5, 1, -1)
to_chat(L, "<span class='userdanger'>You're shot by \a [src][organ_hit_text]!</span>")
else
if(hitsound)
var/volume = vol_by_damage()
playsound(loc, hitsound, volume, 1, -1)
L.visible_message("<span class='danger'>[L] is hit by \a [src][organ_hit_text]!</span>", \
"<span class='userdanger'>[L] is hit by \a [src][organ_hit_text]!</span>", null, COMBAT_MESSAGE_RANGE)
L.on_hit(src)
var/reagent_note
if(reagents && reagents.reagent_list)
reagent_note = " REAGENTS:"
for(var/datum/reagent/R in reagents.reagent_list)
reagent_note += R.id + " ("
reagent_note += num2text(R.volume) + ") "
add_logs(firer, L, "shot", src, reagent_note)
return L.apply_effects(stun, weaken, paralyze, irradiate, slur, stutter, eyeblur, drowsy, blocked, stamina, jitter)
/obj/item/projectile/proc/vol_by_damage()
if(src.damage)
return Clamp((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then clamp the value between 30 and 100
else
return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume
/obj/item/projectile/Bump(atom/A, yes)
if(!yes) //prevents double bumps.
return
if(firer)
if(A == firer || (A == firer.loc && istype(A, /obj/mecha))) //cannot shoot yourself or your mech
loc = A.loc
return 0
var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
if(isturf(A) && hitsound_wall)
var/volume = Clamp(vol_by_damage() + 20, 0, 100)
if(suppressed)
volume = 5
playsound(loc, hitsound_wall, volume, 1, -1)
var/turf/target_turf = get_turf(A)
prehit(A)
var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null
if(permutation == -1 || forcedodge)// the bullet passes through a dense object!
loc = target_turf
if(A)
permutated.Add(A)
return 0
else
if(A && A.density && !ismob(A) && !(A.flags & ON_BORDER)) //if we hit a dense non-border obj or dense turf then we also hit one of the mobs on that tile.
var/list/mobs_list = list()
for(var/mob/living/L in target_turf)
mobs_list += L
if(mobs_list.len)
var/mob/living/picked_mob = pick(mobs_list)
prehit(picked_mob)
picked_mob.bullet_act(src, def_zone)
qdel(src)
/obj/item/projectile/Process_Spacemove(var/movement_dir = 0)
return 1 //Bullets don't drift in space
/obj/item/projectile/proc/fire(setAngle, atom/direct_target)
if(!log_override && firer && original)
add_logs(firer, original, "fired at", src, " [get_area(src)]")
if(direct_target)
prehit(direct_target)
direct_target.bullet_act(src, def_zone)
qdel(src)
return
if(setAngle)
Angle = setAngle
var/old_pixel_x = pixel_x
var/old_pixel_y = pixel_y
if(!legacy) //new projectiles
set waitfor = 0
var/next_run = world.time
while(loc)
if(paused)
next_run = world.time
sleep(1)
continue
if((!( current ) || loc == current))
current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z)
if(!Angle)
Angle=round(Get_Angle(src,current))
if(spread)
Angle += (rand() - 0.5) * spread
var/matrix/M = new
M.Turn(Angle)
transform = M
var/Pixel_x=round((sin(Angle)+16*sin(Angle)*2), 1) //round() is a floor operation when only one argument is supplied, we don't want that here
var/Pixel_y=round((cos(Angle)+16*cos(Angle)*2), 1)
var/pixel_x_offset = old_pixel_x + Pixel_x
var/pixel_y_offset = old_pixel_y + Pixel_y
var/new_x = x
var/new_y = y
while(pixel_x_offset > 16)
pixel_x_offset -= 32
old_pixel_x -= 32
new_x++// x++
while(pixel_x_offset < -16)
pixel_x_offset += 32
old_pixel_x += 32
new_x--
while(pixel_y_offset > 16)
pixel_y_offset -= 32
old_pixel_y -= 32
new_y++
while(pixel_y_offset < -16)
pixel_y_offset += 32
old_pixel_y += 32
new_y--
pixel_x = old_pixel_x
pixel_y = old_pixel_y
step_towards(src, locate(new_x, new_y, z))
next_run += max(world.tick_lag, speed)
var/delay = next_run - world.time
if(delay <= world.tick_lag*2)
pixel_x = pixel_x_offset
pixel_y = pixel_y_offset
else
animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (delay <= 3 ? delay - 1 : delay)), flags = ANIMATION_END_NOW)
old_pixel_x = pixel_x_offset
old_pixel_y = pixel_y_offset
if(original && (original.layer>=2.75) || ismob(original))
if(loc == get_turf(original))
if(!(original in permutated))
Bump(original, 1)
Range()
if (delay > 0)
sleep(delay)
else //old projectile system
set waitfor = 0
while(loc)
if(!paused)
if((!( current ) || loc == current))
current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z)
step_towards(src, current)
if(original && (original.layer>=2.75) || ismob(original))
if(loc == get_turf(original))
if(!(original in permutated))
Bump(original, 1)
Range()
sleep(config.run_speed * 0.9)
/obj/item/projectile/proc/preparePixelProjectile(atom/target, var/turf/targloc, mob/living/user, params, spread)
var/turf/curloc = get_turf(user)
src.loc = get_turf(user)
src.starting = get_turf(user)
src.current = curloc
src.yo = targloc.y - curloc.y
src.xo = targloc.x - curloc.x
if(params)
var/list/mouse_control = params2list(params)
if(mouse_control["icon-x"])
src.p_x = text2num(mouse_control["icon-x"])
if(mouse_control["icon-y"])
src.p_y = text2num(mouse_control["icon-y"])
if(mouse_control["screen-loc"])
//Split screen-loc up into X+Pixel_X and Y+Pixel_Y
var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",")
//Split X+Pixel_X up into list(X, Pixel_X)
var/list/screen_loc_X = splittext(screen_loc_params[1],":")
//Split Y+Pixel_Y up into list(Y, Pixel_Y)
var/list/screen_loc_Y = splittext(screen_loc_params[2],":")
// to_chat(world, "X: [screen_loc_X[1]] PixelX: [screen_loc_X[2]] / Y: [screen_loc_Y[1]] PixelY: [screen_loc_Y[2]]")
var/x = text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32
var/y = text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32
//Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average.
var/screenview = (user.client.view * 2 + 1) * world.icon_size //Refer to http://www.byond.com/docs/ref/info.html#/client/var/view for mad maths
var/ox = round(screenview/2) //"origin" x
var/oy = round(screenview/2) //"origin" y
// to_chat(world, "Pixel position: [x] [y]")
var/angle = Atan2(y - oy, x - ox)
// to_chat(world, "Angle: [angle]")
src.Angle = angle
if(spread)
src.Angle += spread
/obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a projectile is hit by it.
..()
if(isliving(AM) && AM.density && !checkpass(PASSMOB))
Bump(AM, 1)
/obj/item/projectile/Destroy()
return ..()
/obj/item/projectile/experience_pressure_difference()
return