icons should exist
@@ -117,8 +117,8 @@
|
||||
#define ui_borg_camera "CENTER+3:21,SOUTH:5"
|
||||
#define ui_borg_alerts "CENTER+4:21,SOUTH:5"
|
||||
#define ui_borg_language_menu "CENTER+4:21,SOUTH+1:5"
|
||||
#define ui_borg_sensor "CENTER-3:15, SOUTH:5" //LEGACY
|
||||
#define ui_borg_thrusters "CENTER-5:15, SOUTH:5" //LEGACY
|
||||
#define ui_borg_sensor "CENTER-6:16, SOUTH:5" //LEGACY
|
||||
#define ui_borg_thrusters "CENTER-5:16, SOUTH:5" //LEGACY
|
||||
|
||||
//Aliens
|
||||
#define ui_alien_health "EAST,CENTER-1:15"
|
||||
|
||||
@@ -676,7 +676,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
|
||||
if(!preview_shuttle)
|
||||
load_template(loading_template)
|
||||
preview_shuttle.linkup(loading_template, destination_port)
|
||||
// preview_shuttle.linkup(loading_template, destination_port)
|
||||
preview_template = loading_template
|
||||
|
||||
// get the existing shuttle information, if any
|
||||
|
||||
@@ -454,12 +454,12 @@
|
||||
return SSshuttle.shuttle_purchase_requirements_met["emagged"]
|
||||
|
||||
|
||||
/datum/map_template/shuttle/emergency/cruise
|
||||
suffix = "cruise"
|
||||
name = "The NTSS Independence"
|
||||
description = "Ordinarily reserved for special functions and events, the Cruise Shuttle Independence can bring a summery cheer to your next station evacuation for a 'modest' fee!"
|
||||
admin_notes = "This motherfucker is BIG. You might need to force dock it."
|
||||
credit_cost = 8000
|
||||
// /datum/map_template/shuttle/emergency/cruise
|
||||
// suffix = "cruise"
|
||||
// name = "The NTSS Independence"
|
||||
// description = "Ordinarily reserved for special functions and events, the Cruise Shuttle Independence can bring a summery cheer to your next station evacuation for a 'modest' fee!"
|
||||
// admin_notes = "This motherfucker is BIG. You might need to force dock it."
|
||||
// credit_cost = 8000
|
||||
|
||||
/datum/map_template/shuttle/emergency/monkey
|
||||
suffix = "nature"
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#define DEFAULT_MAP_SIZE 15
|
||||
|
||||
/obj/machinery/computer/security
|
||||
name = "security camera console"
|
||||
desc = "Used to access the various cameras on the station."
|
||||
@@ -8,15 +10,19 @@
|
||||
|
||||
var/list/network = list("ss13")
|
||||
var/obj/machinery/camera/active_camera
|
||||
/// The turf where the camera was last updated.
|
||||
var/turf/last_camera_turf
|
||||
var/list/concurrent_users = list()
|
||||
|
||||
// Stuff needed to render the map
|
||||
var/map_name
|
||||
var/const/default_map_size = 15
|
||||
var/obj/screen/cam_screen
|
||||
var/obj/screen/plane_master/lighting/cam_plane_master
|
||||
var/obj/screen/map_view/cam_screen
|
||||
/// All the plane masters that need to be applied.
|
||||
var/list/cam_plane_masters
|
||||
var/obj/screen/background/cam_background
|
||||
|
||||
interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_SET_MACHINE | INTERACT_MACHINE_REQUIRES_SIGHT
|
||||
|
||||
/obj/machinery/computer/security/Initialize()
|
||||
. = ..()
|
||||
// Map name has to start and end with an A-Z character,
|
||||
@@ -33,18 +39,20 @@
|
||||
cam_screen.assigned_map = map_name
|
||||
cam_screen.del_on_map_removal = FALSE
|
||||
cam_screen.screen_loc = "[map_name]:1,1"
|
||||
cam_plane_master = new
|
||||
cam_plane_master.name = "plane_master"
|
||||
cam_plane_master.assigned_map = map_name
|
||||
cam_plane_master.del_on_map_removal = FALSE
|
||||
cam_plane_master.screen_loc = "[map_name]:CENTER"
|
||||
cam_plane_masters = list()
|
||||
for(var/plane in subtypesof(/obj/screen/plane_master))
|
||||
var/obj/screen/instance = new plane()
|
||||
instance.assigned_map = map_name
|
||||
instance.del_on_map_removal = FALSE
|
||||
instance.screen_loc = "[map_name]:CENTER"
|
||||
cam_plane_masters += instance
|
||||
cam_background = new
|
||||
cam_background.assigned_map = map_name
|
||||
cam_background.del_on_map_removal = FALSE
|
||||
|
||||
/obj/machinery/computer/security/Destroy()
|
||||
qdel(cam_screen)
|
||||
qdel(cam_plane_master)
|
||||
QDEL_LIST(cam_plane_masters)
|
||||
qdel(cam_background)
|
||||
return ..()
|
||||
|
||||
@@ -56,9 +64,10 @@
|
||||
/obj/machinery/computer/security/ui_interact(mob/user, datum/tgui/ui)
|
||||
// Update UI
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
// Show static if can't use the camera
|
||||
if(!active_camera?.can_use())
|
||||
show_camera_static()
|
||||
|
||||
// Update the camera, showing static if necessary and updating data if the location has moved.
|
||||
update_active_camera_screen()
|
||||
|
||||
if(!ui)
|
||||
var/user_ref = REF(user)
|
||||
var/is_living = isliving(user)
|
||||
@@ -72,7 +81,7 @@
|
||||
use_power(active_power_usage)
|
||||
// Register map objects
|
||||
user.client.register_map_obj(cam_screen)
|
||||
for(var/plane in cam_plane_master)
|
||||
for(var/plane in cam_plane_masters)
|
||||
user.client.register_map_obj(plane)
|
||||
user.client.register_map_obj(cam_background)
|
||||
// Open UI
|
||||
@@ -100,6 +109,7 @@
|
||||
data["cameras"] += list(list(
|
||||
name = C.c_tag,
|
||||
))
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/security/ui_act(action, params)
|
||||
@@ -110,31 +120,51 @@
|
||||
if(action == "switch_camera")
|
||||
var/c_tag = params["name"]
|
||||
var/list/cameras = get_available_cameras()
|
||||
var/obj/machinery/camera/C = cameras[c_tag]
|
||||
active_camera = C
|
||||
var/obj/machinery/camera/selected_camera = cameras[c_tag]
|
||||
active_camera = selected_camera
|
||||
playsound(src, get_sfx("terminal_type"), 25, FALSE)
|
||||
|
||||
// Show static if can't use the camera
|
||||
if(!active_camera?.can_use())
|
||||
show_camera_static()
|
||||
if(!selected_camera)
|
||||
return TRUE
|
||||
|
||||
var/list/visible_turfs = list()
|
||||
for(var/turf/T in (C.isXRay() \
|
||||
? range(C.view_range, C) \
|
||||
: view(C.view_range, C)))
|
||||
visible_turfs += T
|
||||
|
||||
var/list/bbox = get_bbox_of_atoms(visible_turfs)
|
||||
var/size_x = bbox[3] - bbox[1] + 1
|
||||
var/size_y = bbox[4] - bbox[2] + 1
|
||||
|
||||
cam_screen.vis_contents = visible_turfs
|
||||
cam_background.icon_state = "clear"
|
||||
cam_background.fill_rect(1, 1, size_x, size_y)
|
||||
update_active_camera_screen()
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/security/proc/update_active_camera_screen()
|
||||
// Show static if can't use the camera
|
||||
if(!active_camera?.can_use())
|
||||
show_camera_static()
|
||||
return
|
||||
|
||||
var/list/visible_turfs = list()
|
||||
|
||||
// Is this camera located in or attached to a living thing? If so, assume the camera's loc is the living thing.
|
||||
var/cam_location = isliving(active_camera.loc) ? active_camera.loc : active_camera
|
||||
|
||||
// If we're not forcing an update for some reason and the cameras are in the same location,
|
||||
// we don't need to update anything.
|
||||
// Most security cameras will end here as they're not moving.
|
||||
var/newturf = get_turf(cam_location)
|
||||
if(last_camera_turf == newturf)
|
||||
return
|
||||
|
||||
// Cameras that get here are moving, and are likely attached to some moving atom such as cyborgs.
|
||||
last_camera_turf = get_turf(cam_location)
|
||||
|
||||
var/list/visible_things = active_camera.isXRay() ? range(active_camera.view_range, cam_location) : view(active_camera.view_range, cam_location)
|
||||
|
||||
for(var/turf/visible_turf in visible_things)
|
||||
visible_turfs += visible_turf
|
||||
|
||||
var/list/bbox = get_bbox_of_atoms(visible_turfs)
|
||||
var/size_x = bbox[3] - bbox[1] + 1
|
||||
var/size_y = bbox[4] - bbox[2] + 1
|
||||
|
||||
cam_screen.vis_contents = visible_turfs
|
||||
cam_background.icon_state = "clear"
|
||||
cam_background.fill_rect(1, 1, size_x, size_y)
|
||||
|
||||
/obj/machinery/computer/security/ui_close(mob/user)
|
||||
var/user_ref = REF(user)
|
||||
var/is_living = isliving(user)
|
||||
@@ -151,7 +181,7 @@
|
||||
/obj/machinery/computer/security/proc/show_camera_static()
|
||||
cam_screen.vis_contents.Cut()
|
||||
cam_background.icon_state = "scanline2"
|
||||
cam_background.fill_rect(1, 1, default_map_size, default_map_size)
|
||||
cam_background.fill_rect(1, 1, DEFAULT_MAP_SIZE, DEFAULT_MAP_SIZE)
|
||||
|
||||
// Returns the list of cameras accessible from this computer
|
||||
/obj/machinery/computer/security/proc/get_available_cameras()
|
||||
@@ -179,7 +209,7 @@
|
||||
name = "security camera monitor"
|
||||
desc = "An old TV hooked into the station's camera network."
|
||||
icon_state = "television"
|
||||
icon_keyboard = null
|
||||
icon_keyboard = "no_keyboard"
|
||||
icon_screen = "detective_tv"
|
||||
pass_flags = PASSTABLE
|
||||
|
||||
@@ -211,7 +241,7 @@
|
||||
|
||||
/obj/machinery/computer/security/qm
|
||||
name = "\improper Quartermaster's camera console"
|
||||
desc = "A console with access to the mining, auxillary base and vault camera networks."
|
||||
desc = "A console with access to the mining, auxiliary base and vault camera networks."
|
||||
network = list("mine", "auxbase", "vault")
|
||||
circuit = null
|
||||
|
||||
@@ -222,17 +252,12 @@
|
||||
desc = "Used for watching an empty arena."
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "telescreen"
|
||||
layer = SIGN_LAYER
|
||||
network = list("thunder")
|
||||
density = FALSE
|
||||
circuit = null
|
||||
light_power = 0
|
||||
|
||||
/obj/machinery/computer/security/telescreen/Initialize()
|
||||
. = ..()
|
||||
var/turf/T = get_turf_pixel(src)
|
||||
if(iswallturf(T))
|
||||
plane = ABOVE_WALL_PLANE
|
||||
|
||||
/obj/machinery/computer/security/telescreen/update_icon_state()
|
||||
icon_state = initial(icon_state)
|
||||
if(stat & BROKEN)
|
||||
@@ -246,21 +271,19 @@
|
||||
network = list("thunder")
|
||||
density = FALSE
|
||||
circuit = null
|
||||
//interaction_flags_atom = NONE // interact() is called by BigClick()
|
||||
interaction_flags_atom = NONE // interact() is called by BigClick()
|
||||
var/icon_state_off = "entertainment_blank"
|
||||
var/icon_state_on = "entertainment"
|
||||
|
||||
/* If someone would like to try to get this long-distance viewing thing working, be my guest. I tried everything I could possibly think of and it just refused to operate correctly.
|
||||
|
||||
/obj/machinery/computer/security/telescreen/entertainment/Initialize()
|
||||
. = ..()
|
||||
RegisterSignal(src, COMSIG_CLICK, .proc/BigClick)
|
||||
|
||||
// Bypass clickchain to allow humans to use the telescreen from a distance
|
||||
/obj/machinery/computer/security/telescreen/entertainment/proc/BigClick()
|
||||
interact(usr)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
*/
|
||||
INVOKE_ASYNC(src, /atom.proc/interact, usr)
|
||||
|
||||
/obj/machinery/computer/security/telescreen/entertainment/proc/notify(on)
|
||||
if(on && icon_state == icon_state_off)
|
||||
@@ -279,8 +302,8 @@
|
||||
network = list("rd", "aicore", "aiupload", "minisat", "xeno", "test")
|
||||
|
||||
/obj/machinery/computer/security/telescreen/circuitry
|
||||
name = "circuitry telescreen"
|
||||
desc = "Used for watching the other eggheads from the safety of the circuitry lab."
|
||||
name = "research telescreen"
|
||||
desc = "A telescreen with access to the research division's camera network."
|
||||
network = list("rd")
|
||||
|
||||
/obj/machinery/computer/security/telescreen/ce
|
||||
@@ -324,8 +347,8 @@
|
||||
network = list("prison")
|
||||
|
||||
/obj/machinery/computer/security/telescreen/auxbase
|
||||
name = "auxillary base monitor"
|
||||
desc = "A telescreen that connects to the auxillary base's camera."
|
||||
name = "auxiliary base monitor"
|
||||
desc = "A telescreen that connects to the auxiliary base's camera."
|
||||
network = list("auxbase")
|
||||
|
||||
/obj/machinery/computer/security/telescreen/minisat
|
||||
@@ -346,3 +369,5 @@
|
||||
for(var/i in network)
|
||||
network -= i
|
||||
network += "[idnum][i]"
|
||||
|
||||
#undef DEFAULT_MAP_SIZE
|
||||
|
||||
@@ -1,21 +1,37 @@
|
||||
/obj/machinery/computer/pod
|
||||
name = "mass driver launch control"
|
||||
desc = "A combined blastdoor and mass driver control unit."
|
||||
// processing_flags = START_PROCESSING_MANUALLY
|
||||
/// Connected mass driver
|
||||
var/obj/machinery/mass_driver/connected = null
|
||||
var/title = "Mass Driver Controls"
|
||||
/// ID of the launch control
|
||||
var/id = 1
|
||||
var/timing = 0
|
||||
/// If the launch timer counts down
|
||||
var/timing = FALSE
|
||||
/// Time before auto launch
|
||||
var/time = 30
|
||||
/// Range in which we search for a mass drivers and poddoors nearby
|
||||
var/range = 4
|
||||
|
||||
/// Countdown timer for the mass driver's delayed launch functionality.
|
||||
COOLDOWN_DECLARE(massdriver_countdown)
|
||||
|
||||
/obj/machinery/computer/pod/Initialize()
|
||||
. = ..()
|
||||
for(var/obj/machinery/mass_driver/M in range(range, src))
|
||||
if(M.id == id)
|
||||
connected = M
|
||||
break
|
||||
|
||||
/obj/machinery/computer/pod/process(delta_time)
|
||||
if(COOLDOWN_FINISHED(src, massdriver_countdown))
|
||||
timing = FALSE
|
||||
// alarm() sleeps, so we want to end processing first and can't rely on return PROCESS_KILL
|
||||
end_processing()
|
||||
alarm()
|
||||
|
||||
/**
|
||||
* Initiates launching sequence by checking if all components are functional, opening poddoors, firing mass drivers and then closing poddoors
|
||||
*/
|
||||
/obj/machinery/computer/pod/proc/alarm()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
@@ -39,92 +55,110 @@
|
||||
if(M.id == id)
|
||||
M.close()
|
||||
|
||||
/obj/machinery/computer/pod/ui_interact(mob/user)
|
||||
/obj/machinery/computer/pod/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "MassDriverControl", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/pod/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
// If the cooldown has finished, just display the time. If the cooldown hasn't finished, display the cooldown.
|
||||
var/display_time = COOLDOWN_FINISHED(src, massdriver_countdown) ? time : COOLDOWN_TIMELEFT(src, massdriver_countdown) * 0.1
|
||||
data["connected"] = connected ? TRUE : FALSE
|
||||
data["seconds"] = round(display_time % 60)
|
||||
data["minutes"] = round((display_time - data["seconds"]) / 60)
|
||||
data["timing"] = timing
|
||||
data["power"] = connected ? connected.power : 0.25
|
||||
data["poddoor"] = FALSE
|
||||
for(var/obj/machinery/door/poddoor/door in range(range, src))
|
||||
if(door.id == id)
|
||||
data["poddoor"] = TRUE
|
||||
break
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/pod/ui_act(action, list/params)
|
||||
. = ..()
|
||||
if(!allowed(user))
|
||||
to_chat(user, "<span class='warning'>Access denied.</span>")
|
||||
if(.)
|
||||
return
|
||||
if(!allowed(usr))
|
||||
to_chat(usr, "<span class='warning'>Access denied.</span>")
|
||||
return
|
||||
|
||||
var/dat = ""
|
||||
if(connected)
|
||||
var/d2
|
||||
if(timing) //door controls do not need timers.
|
||||
d2 = "<A href='?src=[REF(src)];time=0'>Stop Time Launch</A>"
|
||||
else
|
||||
d2 = "<A href='?src=[REF(src)];time=1'>Initiate Time Launch</A>"
|
||||
dat += "<HR>\nTimer System: [d2]\nTime Left: [DisplayTimeText(time)] <A href='?src=[REF(src)];tp=-30'>-</A> <A href='?src=[REF(src)];tp=-1'>-</A> <A href='?src=[REF(src)];tp=1'>+</A> <A href='?src=[REF(src)];tp=30'>+</A>"
|
||||
var/temp = ""
|
||||
var/list/L = list( 0.25, 0.5, 1, 2, 4, 8, 16 )
|
||||
for(var/t in L)
|
||||
if(t == connected.power)
|
||||
temp += "[t] "
|
||||
switch(action)
|
||||
if("set_power")
|
||||
if(!connected)
|
||||
return
|
||||
var/value = text2num(params["power"])
|
||||
if(!value)
|
||||
return
|
||||
value = clamp(value, 0.25, 16)
|
||||
connected.power = value
|
||||
return TRUE
|
||||
if("launch")
|
||||
alarm()
|
||||
return TRUE
|
||||
if("time")
|
||||
timing = !timing
|
||||
if(timing)
|
||||
COOLDOWN_START(src, massdriver_countdown, time SECONDS)
|
||||
begin_processing()
|
||||
else
|
||||
temp += "<A href = '?src=[REF(src)];power=[t]'>[t]</A> "
|
||||
dat += "<HR>\nPower Level: [temp]<BR>\n<A href = '?src=[REF(src)];alarm=1'>Firing Sequence</A><BR>\n<A href = '?src=[REF(src)];drive=1'>Test Fire Driver</A><BR>\n<A href = '?src=[REF(src)];door=1'>Toggle Outer Door</A><BR>"
|
||||
else
|
||||
dat += "<BR>\n<A href = '?src=[REF(src)];door=1'>Toggle Outer Door</A><BR>"
|
||||
dat += "<BR><BR><A href='?src=[REF(user)];mach_close=computer'>Close</A>"
|
||||
add_fingerprint(usr)
|
||||
var/datum/browser/popup = new(user, "computer", title, 400, 500)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/computer/pod/process()
|
||||
if(!..())
|
||||
return
|
||||
if(timing)
|
||||
if(time > 0)
|
||||
time = round(time) - 1
|
||||
else
|
||||
alarm()
|
||||
time = 0
|
||||
timing = 0
|
||||
updateDialog()
|
||||
|
||||
|
||||
/obj/machinery/computer/pod/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || hasSiliconAccessInArea(usr))
|
||||
usr.set_machine(src)
|
||||
if(href_list["power"])
|
||||
var/t = text2num(href_list["power"])
|
||||
t = min(max(0.25, t), 16)
|
||||
if(connected)
|
||||
connected.power = t
|
||||
if(href_list["alarm"])
|
||||
alarm()
|
||||
if(href_list["time"])
|
||||
timing = text2num(href_list["time"])
|
||||
if(href_list["tp"])
|
||||
var/tp = text2num(href_list["tp"])
|
||||
time += tp
|
||||
time = min(max(round(time), 0), 120)
|
||||
if(href_list["door"])
|
||||
time = COOLDOWN_TIMELEFT(src, massdriver_countdown) * 0.1
|
||||
COOLDOWN_RESET(src, massdriver_countdown)
|
||||
end_processing()
|
||||
return TRUE
|
||||
if("input")
|
||||
var/value = text2num(params["adjust"])
|
||||
if(!value)
|
||||
return
|
||||
value = round(time + value)
|
||||
time = clamp(value, 0, 120)
|
||||
return TRUE
|
||||
if("door")
|
||||
for(var/obj/machinery/door/poddoor/M in range(range, src))
|
||||
if(M.id == id)
|
||||
if(M.density)
|
||||
M.open()
|
||||
else
|
||||
M.close()
|
||||
if(href_list["drive"])
|
||||
return TRUE
|
||||
if("driver_test")
|
||||
for(var/obj/machinery/mass_driver/M in range(range, src))
|
||||
if(M.id == id)
|
||||
M.power = connected.power
|
||||
M.power = connected?.power
|
||||
M.drive()
|
||||
updateUsrDialog()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/pod/old
|
||||
name = "\improper DoorMex control console"
|
||||
title = "Door Controls"
|
||||
icon_state = "oldcomp"
|
||||
icon_screen = "library"
|
||||
icon_keyboard = null
|
||||
icon_keyboard = "no_keyboard"
|
||||
|
||||
// /obj/machinery/computer/pod/old/mass_driver_controller
|
||||
// name = "\improper Mass Driver Controller"
|
||||
// icon = 'icons/obj/airlock_machines.dmi'
|
||||
// icon_state = "airlock_control_standby"
|
||||
// icon_keyboard = "no_keyboard"
|
||||
// density = FALSE
|
||||
|
||||
// /obj/machinery/computer/pod/old/mass_driver_controller/toxinsdriver
|
||||
// id = MASSDRIVER_TOXINS
|
||||
|
||||
// //for maps where pod doors are outside of the standard 4 tile controller detection range (ie Pubbystation)
|
||||
// /obj/machinery/computer/pod/old/mass_driver_controller/toxinsdriver/longrange
|
||||
// range = 6
|
||||
|
||||
// /obj/machinery/computer/pod/old/mass_driver_controller/chapelgun
|
||||
// id = MASSDRIVER_CHAPEL
|
||||
|
||||
// /obj/machinery/computer/pod/old/mass_driver_controller/trash
|
||||
// id = MASSDRIVER_DISPOSALS
|
||||
|
||||
/obj/machinery/computer/pod/old/syndicate
|
||||
name = "\improper ProComp Executive IIc"
|
||||
desc = "The Syndicate operate on a tight budget. Operates external airlocks."
|
||||
title = "External Airlock Controls"
|
||||
req_access = list(ACCESS_SYNDICATE)
|
||||
|
||||
/obj/machinery/computer/pod/old/swf
|
||||
|
||||
@@ -11,8 +11,24 @@
|
||||
var/id = 1
|
||||
var/drive_range = 50 //this is mostly irrelevant since current mass drivers throw into space, but you could make a lower-range mass driver for interstation transport or something I guess.
|
||||
|
||||
/obj/machinery/mass_driver/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
|
||||
id = "[idnum][id]"
|
||||
// /obj/machinery/mass_driver/chapelgun
|
||||
// name = "holy driver"
|
||||
// id = MASSDRIVER_CHAPEL
|
||||
|
||||
// /obj/machinery/mass_driver/toxins
|
||||
// id = MASSDRIVER_TOXINS
|
||||
|
||||
// /obj/machinery/mass_driver/trash
|
||||
// id = MASSDRIVER_DISPOSALS
|
||||
|
||||
// /obj/machinery/mass_driver/Destroy()
|
||||
// for(var/obj/machinery/computer/pod/control in GLOB.machines)
|
||||
// if(control.id == id)
|
||||
// control.connected = null
|
||||
// return ..()
|
||||
|
||||
/obj/machinery/mass_driver/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock)
|
||||
id = "[port.id]_[id]"
|
||||
|
||||
/obj/machinery/mass_driver/proc/drive(amount)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
@@ -22,6 +38,8 @@
|
||||
var/atom/target = get_edge_target_turf(src, dir)
|
||||
for(var/atom/movable/O in loc)
|
||||
if(!O.anchored || ismecha(O)) //Mechs need their launch platforms.
|
||||
// if(ismob(O) && !isliving(O))
|
||||
// continue
|
||||
O_limit++
|
||||
if(O_limit >= 20)
|
||||
audible_message("<span class='notice'>[src] lets out a screech, it doesn't seem to be able to handle the load.</span>")
|
||||
@@ -30,7 +48,6 @@
|
||||
O.throw_at(target, drive_range * power, power)
|
||||
flick("mass_driver1", src)
|
||||
|
||||
|
||||
/obj/machinery/mass_driver/emp_act(severity)
|
||||
. = ..()
|
||||
if (. & EMP_PROTECT_SELF)
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
integrity = round((M.obj_integrity / M.max_integrity) * 100),
|
||||
charge = M.cell ? round(M.cell.percent()) : null,
|
||||
airtank = M.internal_tank ? M.return_pressure() : null,
|
||||
pilot = M.occupant,
|
||||
pilot = list(M.occupant),
|
||||
location = get_area_name(M, TRUE),
|
||||
active_equipment = M.selected,
|
||||
emp_recharging = MT.recharging,
|
||||
@@ -38,7 +38,7 @@
|
||||
if(istype(M, /obj/mecha/working/ripley))
|
||||
var/obj/mecha/working/ripley/RM = M
|
||||
mech_data += list(
|
||||
cargo_space = round((RM.cargo.len / RM.cargo_capacity) * 100)
|
||||
cargo_space = round((LAZYLEN(RM.cargo) / RM.cargo_capacity) * 100)
|
||||
)
|
||||
|
||||
data["mechs"] += list(mech_data)
|
||||
@@ -46,7 +46,8 @@
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/mecha/ui_act(action, params)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
@@ -57,7 +58,7 @@
|
||||
var/message = stripped_input(usr, "Input message", "Transmit message")
|
||||
var/obj/mecha/M = MT.chassis
|
||||
if(trim(message) && M)
|
||||
M.occupant_message(message)
|
||||
to_chat(M.occupant, message)
|
||||
to_chat(usr, "<span class='notice'>Message sent.</span>")
|
||||
. = TRUE
|
||||
if("shock")
|
||||
@@ -67,8 +68,8 @@
|
||||
var/obj/mecha/M = MT.chassis
|
||||
if(M)
|
||||
MT.shock()
|
||||
log_game("[key_name(usr)] has activated remote EMP on exosuit [M], located at [loc_name(M)], which is currently [M.occupant? "being piloted by [key_name(M.occupant)]." : "without a pilot."] ")
|
||||
message_admins("[key_name_admin(usr)][ADMIN_FLW(usr)] has activated remote EMP on exosuit [M][ADMIN_JMP(M)], which is currently [M.occupant ? "being piloted by [key_name_admin(M.occupant)][ADMIN_FLW(M.occupant)]." : "without a pilot."] ")
|
||||
log_game("[key_name(usr)] has activated remote EMP on exosuit [M], located at [loc_name(M)], which [M.occupant ? "has the occupants [M.occupant]." : "without a pilot."] ")
|
||||
message_admins("[key_name_admin(usr)][ADMIN_FLW(usr)] has activated remote EMP on exosuit [M][ADMIN_JMP(M)], which is currently [M.occupants ? "occupied by [M.occupant][ADMIN_FLW(M)]." : "without a pilot."] ")
|
||||
. = TRUE
|
||||
|
||||
/obj/item/mecha_parts/mecha_tracking
|
||||
@@ -85,8 +86,8 @@
|
||||
var/obj/mecha/chassis
|
||||
|
||||
/**
|
||||
* Returns a html formatted string describing attached mech status
|
||||
*/
|
||||
* Returns a html formatted string describing attached mech status
|
||||
*/
|
||||
/obj/item/mecha_parts/mecha_tracking/proc/get_mecha_info()
|
||||
if(!chassis)
|
||||
return FALSE
|
||||
@@ -101,7 +102,7 @@
|
||||
<b>Active Equipment:</b> [chassis.selected || "None"]"}
|
||||
if(istype(chassis, /obj/mecha/working/ripley))
|
||||
var/obj/mecha/working/ripley/RM = chassis
|
||||
answer += "<br><b>Used Cargo Space:</b> [round((RM.cargo.len / RM.cargo_capacity * 100), 0.01)]%"
|
||||
answer += "<br><b>Used Cargo Space:</b> [round((LAZYLEN(RM.cargo) / RM.cargo_capacity * 100), 0.01)]%"
|
||||
|
||||
return answer
|
||||
|
||||
@@ -125,8 +126,8 @@
|
||||
chassis = M
|
||||
|
||||
/**
|
||||
* Attempts to EMP mech that the tracker is attached to, if there is one and tracker is not on cooldown
|
||||
*/
|
||||
* Attempts to EMP mech that the tracker is attached to, if there is one and tracker is not on cooldown
|
||||
*/
|
||||
/obj/item/mecha_parts/mecha_tracking/proc/shock()
|
||||
if(recharging)
|
||||
return
|
||||
@@ -136,8 +137,8 @@
|
||||
recharging = TRUE
|
||||
|
||||
/**
|
||||
* Resets recharge variable, allowing tracker to be EMP pulsed again
|
||||
*/
|
||||
* Resets recharge variable, allowing tracker to be EMP pulsed again
|
||||
*/
|
||||
/obj/item/mecha_parts/mecha_tracking/proc/recharge()
|
||||
recharging = FALSE
|
||||
|
||||
|
||||
@@ -439,6 +439,8 @@
|
||||
if(zero_amount())
|
||||
return
|
||||
return split_stack(user, 1)
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/obj/item/stack/AltClick(mob/living/user)
|
||||
. = ..()
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
/obj/item/tank
|
||||
name = "tank"
|
||||
icon = 'icons/obj/tank.dmi'
|
||||
icon_state = "generic"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/tanks_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/tanks_righthand.dmi'
|
||||
flags_1 = CONDUCT_1
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
// worn_icon = 'icons/mob/clothing/back.dmi' //since these can also get thrown into suit storage slots. if something goes on the belt, set this to null.
|
||||
hitsound = 'sound/weapons/smash.ogg'
|
||||
pressure_resistance = ONE_ATMOSPHERE * 5
|
||||
force = 5
|
||||
@@ -18,12 +20,14 @@
|
||||
var/distribute_pressure = ONE_ATMOSPHERE
|
||||
var/integrity = 3
|
||||
var/volume = 70
|
||||
/// Icon state when in a tank holder. Null makes it incompatible with tank holder.
|
||||
var/tank_holder_icon_state = "holder_generic"
|
||||
|
||||
/obj/item/tank/ui_action_click(mob/user)
|
||||
toggle_internals(user)
|
||||
|
||||
/obj/item/tank/proc/toggle_internals(mob/user)
|
||||
var/mob/living/carbon/H = user
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(!istype(H))
|
||||
return
|
||||
|
||||
@@ -84,18 +88,23 @@
|
||||
|
||||
/obj/item/tank/Destroy()
|
||||
if(air_contents)
|
||||
qdel(air_contents)
|
||||
QDEL_NULL(air_contents)
|
||||
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
// /obj/item/tank/ComponentInitialize()
|
||||
// . = ..()
|
||||
// if(tank_holder_icon_state)
|
||||
// AddComponent(/datum/component/container_item/tank_holder, tank_holder_icon_state)
|
||||
|
||||
/obj/item/tank/examine(mob/user)
|
||||
var/obj/icon = src
|
||||
. = ..()
|
||||
if(istype(src.loc, /obj/item/assembly))
|
||||
icon = src.loc
|
||||
if(!in_range(src, user) && !isobserver(user))
|
||||
if (icon == src)
|
||||
if(icon == src)
|
||||
. += "<span class='notice'>If you want any more information you'll need to get closer.</span>"
|
||||
return
|
||||
|
||||
@@ -140,14 +149,14 @@
|
||||
if(T)
|
||||
T.assume_air(air_contents)
|
||||
air_update_turf()
|
||||
playsound(src.loc, 'sound/effects/spray.ogg', 10, 1, -3)
|
||||
playsound(src.loc, 'sound/effects/spray.ogg', 10, TRUE, -3)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/tank/suicide_act(mob/user)
|
||||
var/mob/living/carbon/human/H = user
|
||||
user.visible_message("<span class='suicide'>[user] is putting [src]'s valve to [user.p_their()] lips! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
playsound(loc, 'sound/effects/spray.ogg', 10, 1, -3)
|
||||
if (!QDELETED(H) && air_contents && air_contents.return_pressure() >= 1000)
|
||||
playsound(loc, 'sound/effects/spray.ogg', 10, TRUE, -3)
|
||||
if(!QDELETED(H) && air_contents && air_contents.return_pressure() >= 1000)
|
||||
for(var/obj/item/W in H)
|
||||
H.dropItemToGround(W)
|
||||
if(prob(50))
|
||||
@@ -159,12 +168,10 @@
|
||||
H.spawn_gibs()
|
||||
H.spill_organs()
|
||||
H.spread_bodyparts()
|
||||
|
||||
return (BRUTELOSS)
|
||||
|
||||
/obj/item/tank/attack_ghost(mob/dead/observer/O)
|
||||
. = ..()
|
||||
atmosanalyzer_scan(air_contents, O, src, FALSE)
|
||||
return MANUAL_SUICIDE
|
||||
else
|
||||
to_chat(user, "<span class='warning'>There isn't enough pressure in [src] to commit suicide with...</span>")
|
||||
return SHAME
|
||||
|
||||
/obj/item/tank/attackby(obj/item/W, mob/user, params)
|
||||
add_fingerprint(user)
|
||||
@@ -182,27 +189,30 @@
|
||||
ui = new(user, src, "Tank", name)
|
||||
ui.open()
|
||||
|
||||
/obj/item/tank/ui_static_data(mob/user)
|
||||
. = list (
|
||||
"defaultReleasePressure" = round(TANK_DEFAULT_RELEASE_PRESSURE),
|
||||
"minReleasePressure" = round(TANK_MIN_RELEASE_PRESSURE),
|
||||
"maxReleasePressure" = round(TANK_MAX_RELEASE_PRESSURE),
|
||||
"leakPressure" = round(TANK_LEAK_PRESSURE),
|
||||
"fragmentPressure" = round(TANK_FRAGMENT_PRESSURE)
|
||||
)
|
||||
|
||||
/obj/item/tank/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
|
||||
data["releasePressure"] = round(distribute_pressure ? distribute_pressure : 0)
|
||||
data["defaultReleasePressure"] = round(TANK_DEFAULT_RELEASE_PRESSURE)
|
||||
data["minReleasePressure"] = round(TANK_MIN_RELEASE_PRESSURE)
|
||||
data["maxReleasePressure"] = round(TANK_MAX_RELEASE_PRESSURE)
|
||||
. = list(
|
||||
"tankPressure" = round(air_contents.return_pressure()),
|
||||
"releasePressure" = round(distribute_pressure)
|
||||
)
|
||||
|
||||
var/mob/living/carbon/C = user
|
||||
if(!istype(C))
|
||||
C = loc.loc
|
||||
if(!istype(C))
|
||||
return data
|
||||
|
||||
if(C.internal == src)
|
||||
data["connected"] = TRUE
|
||||
|
||||
return data
|
||||
if(istype(C) && C.internal == src)
|
||||
.["connected"] = TRUE
|
||||
|
||||
/obj/item/tank/ui_act(action, params)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
switch(action)
|
||||
if("pressure")
|
||||
@@ -228,6 +238,9 @@
|
||||
/obj/item/tank/return_air()
|
||||
return air_contents
|
||||
|
||||
// /obj/item/tank/return_analyzable_air()
|
||||
// return air_contents
|
||||
|
||||
/obj/item/tank/assume_air(datum/gas_mixture/giver)
|
||||
air_contents.merge(giver)
|
||||
|
||||
@@ -239,10 +252,9 @@
|
||||
return null
|
||||
|
||||
var/tank_pressure = air_contents.return_pressure()
|
||||
if(tank_pressure < distribute_pressure)
|
||||
distribute_pressure = tank_pressure
|
||||
var/actual_distribute_pressure = clamp(tank_pressure, 0, distribute_pressure)
|
||||
|
||||
var/moles_needed = distribute_pressure*volume_to_return/(R_IDEAL_GAS_EQUATION*air_contents.return_temperature())
|
||||
var/moles_needed = actual_distribute_pressure*volume_to_return/(R_IDEAL_GAS_EQUATION*air_contents.return_temperature())
|
||||
|
||||
return remove_air(moles_needed)
|
||||
|
||||
@@ -266,7 +278,7 @@
|
||||
log_game("Explosive tank rupture! Last key to touch the tank was [src.fingerprintslast].")
|
||||
//Give the gas a chance to build up more pressure through reacting
|
||||
air_contents.react(src)
|
||||
air_contents.react(src)
|
||||
// air_contents.react(src)
|
||||
//Citadel Edit: removing extra react for "balance"
|
||||
pressure = air_contents.return_pressure()
|
||||
var/range = (pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE
|
||||
@@ -285,7 +297,7 @@
|
||||
if(!T)
|
||||
return
|
||||
T.assume_air(air_contents)
|
||||
playsound(src.loc, 'sound/effects/spray.ogg', 10, 1, -3)
|
||||
playsound(src.loc, 'sound/effects/spray.ogg', 10, TRUE, -3)
|
||||
qdel(src)
|
||||
else
|
||||
integrity--
|
||||
|
||||
@@ -4,6 +4,11 @@ SAFES
|
||||
FLOOR SAFES
|
||||
*/
|
||||
|
||||
/// Chance for a sound clue
|
||||
#define SOUND_CHANCE 10
|
||||
/// Explosion number threshold for opening safe
|
||||
#define BROKEN_THRESHOLD 3
|
||||
|
||||
//SAFES
|
||||
/obj/structure/safe
|
||||
name = "safe"
|
||||
@@ -14,31 +19,36 @@ FLOOR SAFES
|
||||
density = TRUE
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT
|
||||
var/open = FALSE //is the safe open?
|
||||
var/tumbler_1_pos //the tumbler position- from 0 to 72
|
||||
var/tumbler_1_open //the tumbler position to open at- 0 to 72
|
||||
var/tumbler_2_pos
|
||||
var/tumbler_2_open
|
||||
var/dial = 0 //where is the dial pointing?
|
||||
var/space = 0 //the combined w_class of everything in the safe
|
||||
var/maxspace = 24 //the maximum combined w_class of stuff in the safe
|
||||
var/explosion_count = 0 //Tough, but breakable
|
||||
|
||||
/obj/structure/safe/New()
|
||||
..()
|
||||
tumbler_1_pos = rand(0, 71)
|
||||
tumbler_1_open = rand(0, 71)
|
||||
|
||||
tumbler_2_pos = rand(0, 71)
|
||||
tumbler_2_open = rand(0, 71)
|
||||
|
||||
/// The maximum combined w_class of stuff in the safe
|
||||
var/maxspace = 24
|
||||
/// The amount of tumblers that will be generated
|
||||
var/number_of_tumblers = 2
|
||||
/// Whether the safe is open or not
|
||||
var/open = FALSE
|
||||
/// Whether the safe is locked or not
|
||||
var/locked = TRUE
|
||||
/// The position the dial is pointing to
|
||||
var/dial = 0
|
||||
/// The list of tumbler dial positions that need to be hit
|
||||
var/list/tumblers = list()
|
||||
/// The index in the tumblers list of the tumbler dial position that needs to be hit
|
||||
var/current_tumbler_index = 1
|
||||
/// The combined w_class of everything in the safe
|
||||
var/space = 0
|
||||
/// Tough, but breakable if explosion counts reaches set value
|
||||
var/explosion_count = 0
|
||||
|
||||
/obj/structure/safe/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
// Combination generation
|
||||
for(var/i in 1 to number_of_tumblers)
|
||||
tumblers.Add(rand(0, 99))
|
||||
|
||||
if(!mapload)
|
||||
return
|
||||
|
||||
// Put as many items on our turf inside as possible
|
||||
for(var/obj/item/I in loc)
|
||||
if(space >= maxspace)
|
||||
return
|
||||
@@ -46,141 +56,36 @@ FLOOR SAFES
|
||||
space += I.w_class
|
||||
I.forceMove(src)
|
||||
|
||||
|
||||
/obj/structure/safe/proc/check_unlocked(mob/user, canhear)
|
||||
if(explosion_count > 2)
|
||||
return 1
|
||||
if(user && canhear)
|
||||
if(tumbler_1_pos == tumbler_1_open)
|
||||
to_chat(user, "<span class='italics'>You hear a [pick("tonk", "krunk", "plunk")] from [src].</span>")
|
||||
if(tumbler_2_pos == tumbler_2_open)
|
||||
to_chat(user, "<span class='italics'>You hear a [pick("tink", "krink", "plink")] from [src].</span>")
|
||||
if(tumbler_1_pos == tumbler_1_open && tumbler_2_pos == tumbler_2_open)
|
||||
if(user)
|
||||
visible_message("<i><b>[pick("Spring", "Sprang", "Sproing", "Clunk", "Krunk")]!</b></i>")
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/structure/safe/proc/decrement(num)
|
||||
num -= 1
|
||||
if(num < 0)
|
||||
num = 71
|
||||
return num
|
||||
|
||||
/obj/structure/safe/proc/increment(num)
|
||||
num += 1
|
||||
if(num > 71)
|
||||
num = 0
|
||||
return num
|
||||
|
||||
/obj/structure/safe/update_icon_state()
|
||||
if(open)
|
||||
icon_state = "[initial(icon_state)]-open"
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
|
||||
/obj/structure/safe/ui_interact(mob/user)
|
||||
user.set_machine(src)
|
||||
var/dat = "<center>"
|
||||
dat += "<a href='?src=[REF(src)];open=1'>[open ? "Close" : "Open"] [src]</a> | <a href='?src=[REF(src)];decrement=1'>-</a> [dial] <a href='?src=[REF(src)];increment=1'>+</a>"
|
||||
if(open)
|
||||
dat += "<table>"
|
||||
for(var/i = contents.len, i>=1, i--)
|
||||
var/obj/item/P = contents[i]
|
||||
dat += "<tr><td><a href='?src=[REF(src)];retrieve=[REF(P)]'>[P.name]</a></td></tr>"
|
||||
dat += "</table></center>"
|
||||
user << browse("<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>[name]</title></head><body>[dat]</body></html>", "window=safe;size=350x300")
|
||||
|
||||
/obj/structure/safe/Topic(href, href_list)
|
||||
if(!ishuman(usr))
|
||||
return
|
||||
var/mob/living/carbon/human/user = usr
|
||||
|
||||
if(!user.canUseTopic(src))
|
||||
return
|
||||
|
||||
var/canhear = FALSE
|
||||
if(user.is_holding_item_of_type(/obj/item/clothing/neck/stethoscope))
|
||||
canhear = TRUE
|
||||
|
||||
if(href_list["open"])
|
||||
if(check_unlocked())
|
||||
to_chat(user, "<span class='notice'>You [open ? "close" : "open"] [src].</span>")
|
||||
open = !open
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
return
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't [open ? "close" : "open"] [src], the lock is engaged!</span>")
|
||||
return
|
||||
|
||||
if(href_list["decrement"])
|
||||
dial = decrement(dial)
|
||||
if(dial == tumbler_1_pos + 1 || dial == tumbler_1_pos - 71)
|
||||
tumbler_1_pos = decrement(tumbler_1_pos)
|
||||
if(canhear)
|
||||
to_chat(user, "<span class='italics'>You hear a [pick("clack", "scrape", "clank")] from [src].</span>")
|
||||
if(tumbler_1_pos == tumbler_2_pos + 37 || tumbler_1_pos == tumbler_2_pos - 35)
|
||||
tumbler_2_pos = decrement(tumbler_2_pos)
|
||||
if(canhear)
|
||||
to_chat(user, "<span class='italics'>You hear a [pick("click", "chink", "clink")] from [src].</span>")
|
||||
check_unlocked(user, canhear)
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
if(href_list["increment"])
|
||||
dial = increment(dial)
|
||||
if(dial == tumbler_1_pos - 1 || dial == tumbler_1_pos + 71)
|
||||
tumbler_1_pos = increment(tumbler_1_pos)
|
||||
if(canhear)
|
||||
to_chat(user, "<span class='italics'>You hear a [pick("clack", "scrape", "clank")] from [src].</span>")
|
||||
if(tumbler_1_pos == tumbler_2_pos - 37 || tumbler_1_pos == tumbler_2_pos + 35)
|
||||
tumbler_2_pos = increment(tumbler_2_pos)
|
||||
if(canhear)
|
||||
to_chat(user, "<span class='italics'>You hear a [pick("click", "chink", "clink")] from [src].</span>")
|
||||
check_unlocked(user, canhear)
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
if(href_list["retrieve"])
|
||||
user << browse("", "window=safe") // Close the menu
|
||||
|
||||
var/obj/item/P = locate(href_list["retrieve"]) in src
|
||||
if(open)
|
||||
if(P && in_range(src, user))
|
||||
user.put_in_hands(P)
|
||||
space -= P.w_class
|
||||
updateUsrDialog()
|
||||
|
||||
|
||||
/obj/structure/safe/attackby(obj/item/I, mob/user, params)
|
||||
if(open)
|
||||
. = 1 //no afterattack
|
||||
. = TRUE //no afterattack
|
||||
if(I.w_class + space <= maxspace)
|
||||
space += I.w_class
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
to_chat(user, "<span class='warning'>\The [I] is stuck to your hand, you cannot put it in the safe!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You put [I] in [src].</span>")
|
||||
updateUsrDialog()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[I] won't fit in [src].</span>")
|
||||
else
|
||||
if(istype(I, /obj/item/clothing/neck/stethoscope))
|
||||
attack_hand(user)
|
||||
return
|
||||
else
|
||||
to_chat(user, "<span class='notice'>[I] won't fit in [src].</span>")
|
||||
to_chat(user, "<span class='warning'>You can't put [I] into the safe while it is closed!</span>")
|
||||
return
|
||||
else if(istype(I, /obj/item/clothing/neck/stethoscope))
|
||||
to_chat(user, "<span class='warning'>Hold [I] in one of your hands while you manipulate the dial!</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/structure/safe/handle_atom_del(atom/A)
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/structure/safe/blob_act(obj/structure/blob/B)
|
||||
return
|
||||
|
||||
/obj/structure/safe/ex_act(severity, target)
|
||||
if(((severity == 2 && target == src) || severity == 1) && explosion_count < 3)
|
||||
if(((severity == 2 && target == src) || severity == 1) && explosion_count < BROKEN_THRESHOLD)
|
||||
explosion_count++
|
||||
switch(explosion_count)
|
||||
if(1)
|
||||
@@ -190,6 +95,144 @@ FLOOR SAFES
|
||||
if(3)
|
||||
desc = initial(desc) + "\nThe lock seems to be broken."
|
||||
|
||||
/obj/structure/safe/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/simple/safe),
|
||||
)
|
||||
|
||||
/obj/structure/safe/ui_state(mob/user)
|
||||
return GLOB.physical_state
|
||||
|
||||
/obj/structure/safe/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Safe", name)
|
||||
ui.open()
|
||||
|
||||
/obj/structure/safe/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["dial"] = dial
|
||||
data["open"] = open
|
||||
data["locked"] = locked
|
||||
data["broken"] = check_broken()
|
||||
|
||||
if(open)
|
||||
var/list/contents_names = list()
|
||||
data["contents"] = contents_names
|
||||
for(var/obj/O in contents)
|
||||
contents_names[++contents_names.len] = list("name" = O.name, "sprite" = O.icon_state)
|
||||
user << browse_rsc(icon(O.icon, O.icon_state), "[O.icon_state].png")
|
||||
|
||||
return data
|
||||
|
||||
/obj/structure/safe/ui_act(action, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(!ishuman(usr))
|
||||
return
|
||||
var/mob/living/carbon/human/user = usr
|
||||
if(!user.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
|
||||
var/canhear = FALSE
|
||||
if(user.is_holding_item_of_type(/obj/item/clothing/neck/stethoscope))
|
||||
canhear = TRUE
|
||||
|
||||
switch(action)
|
||||
if("open")
|
||||
if(!check_unlocked() && !open && !broken)
|
||||
to_chat(user, "<span class='warning'>You cannot open [src], as its lock is engaged!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You [open ? "close" : "open"] [src].</span>")
|
||||
open = !open
|
||||
update_icon()
|
||||
return TRUE
|
||||
if("turnright")
|
||||
if(open)
|
||||
return
|
||||
if(broken)
|
||||
to_chat(user, "<span class='warning'>The dial will not turn, as the mechanism is destroyed!</span>")
|
||||
return
|
||||
var/ticks = text2num(params["num"])
|
||||
for(var/i = 1 to ticks)
|
||||
dial = WRAP(dial - 1, 0, 100)
|
||||
|
||||
var/invalid_turn = current_tumbler_index % 2 == 0 || current_tumbler_index > number_of_tumblers
|
||||
if(invalid_turn) // The moment you turn the wrong way or go too far, the tumblers reset
|
||||
current_tumbler_index = 1
|
||||
|
||||
if(!invalid_turn && dial == tumblers[current_tumbler_index])
|
||||
notify_user(user, canhear, list("tink", "krink", "plink"), ticks, i)
|
||||
current_tumbler_index++
|
||||
else
|
||||
notify_user(user, canhear, list("clack", "scrape", "clank"), ticks, i)
|
||||
check_unlocked()
|
||||
return TRUE
|
||||
if("turnleft")
|
||||
if(open)
|
||||
return
|
||||
if(broken)
|
||||
to_chat(user, "<span class='warning'>The dial will not turn, as the mechanism is destroyed!</span>")
|
||||
return
|
||||
var/ticks = text2num(params["num"])
|
||||
for(var/i = 1 to ticks)
|
||||
dial = WRAP(dial + 1, 0, 100)
|
||||
|
||||
var/invalid_turn = current_tumbler_index % 2 != 0 || current_tumbler_index > number_of_tumblers
|
||||
if(invalid_turn) // The moment you turn the wrong way or go too far, the tumblers reset
|
||||
current_tumbler_index = 1
|
||||
|
||||
if(!invalid_turn && dial == tumblers[current_tumbler_index])
|
||||
notify_user(user, canhear, list("tonk", "krunk", "plunk"), ticks, i)
|
||||
current_tumbler_index++
|
||||
else
|
||||
notify_user(user, canhear, list("click", "chink", "clink"), ticks, i)
|
||||
check_unlocked()
|
||||
return TRUE
|
||||
if("retrieve")
|
||||
if(!open)
|
||||
return
|
||||
var/index = text2num(params["index"])
|
||||
if(!index)
|
||||
return
|
||||
var/obj/item/I = contents[index]
|
||||
if(!I || !in_range(src, user))
|
||||
return
|
||||
user.put_in_hands(I)
|
||||
space -= I.w_class
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Checks if safe is considered in a broken state for force-opening the safe
|
||||
*/
|
||||
/obj/structure/safe/proc/check_broken()
|
||||
return broken || explosion_count >= BROKEN_THRESHOLD
|
||||
|
||||
/**
|
||||
* Called every dial turn to determine whether the safe should unlock or not.
|
||||
*/
|
||||
/obj/structure/safe/proc/check_unlocked()
|
||||
if(check_broken())
|
||||
return TRUE
|
||||
if(current_tumbler_index > number_of_tumblers)
|
||||
locked = FALSE
|
||||
visible_message("<span class='boldnotice'>[pick("Spring", "Sprang", "Sproing", "Clunk", "Krunk")]!</span>")
|
||||
return TRUE
|
||||
locked = TRUE
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Called every dial turn to provide feedback if possible.
|
||||
*/
|
||||
/obj/structure/safe/proc/notify_user(user, canhear, sounds, total_ticks, current_tick)
|
||||
if(!canhear)
|
||||
return
|
||||
if(current_tick == 2)
|
||||
to_chat(user, "<span class='italics'>The sounds from [src] are too fast and blend together.</span>")
|
||||
if(total_ticks == 1 || prob(SOUND_CHANCE))
|
||||
to_chat(user, "<span class='italics'>You hear a [pick(sounds)] from [src].</span>")
|
||||
|
||||
//FLOOR SAFES
|
||||
/obj/structure/safe/floor
|
||||
@@ -199,13 +242,11 @@ FLOOR SAFES
|
||||
level = 1 //underfloor
|
||||
layer = LOW_OBJ_LAYER
|
||||
|
||||
|
||||
/obj/structure/safe/floor/Initialize(mapload)
|
||||
. = ..()
|
||||
if(mapload)
|
||||
var/turf/T = loc
|
||||
hide(T.intact)
|
||||
|
||||
|
||||
/obj/structure/safe/floor/hide(var/intact)
|
||||
invisibility = intact ? INVISIBILITY_MAXIMUM : 0
|
||||
#undef SOUND_CHANCE
|
||||
#undef BROKEN_THRESHOLD
|
||||
|
||||
@@ -1547,22 +1547,17 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
msg += "</UL></BODY></HTML>"
|
||||
src << browse(msg.Join(), "window=Player_playtime_check")
|
||||
|
||||
/datum/admins/proc/cmd_show_exp_panel(client/C)
|
||||
/datum/admins/proc/cmd_show_exp_panel(client/client_to_check)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(!C)
|
||||
to_chat(usr, "<span class='danger'>ERROR: Client not found.</span>")
|
||||
if(!client_to_check)
|
||||
to_chat(usr, "<span class='danger'>ERROR: Client not found.</span>", confidential = TRUE)
|
||||
return
|
||||
if(!CONFIG_GET(flag/use_exp_tracking))
|
||||
to_chat(usr, "<span class='warning'>Tracking is disabled in the server configuration file.</span>")
|
||||
to_chat(usr, "<span class='warning'>Tracking is disabled in the server configuration file.</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
var/list/body = list()
|
||||
body += "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Playtime for [C.key]</title></head><BODY><BR>Playtime:"
|
||||
body += C.get_exp_report()
|
||||
body += "<A href='?_src_=holder;[HrefToken()];toggleexempt=[REF(C)]'>Toggle Exempt status</a>"
|
||||
body += "</BODY></HTML>"
|
||||
usr << browse(body.Join(), "window=playerplaytime[C.ckey];size=550x615")
|
||||
new /datum/job_report_menu(client_to_check, usr)
|
||||
|
||||
/datum/admins/proc/toggle_exempt_status(client/C)
|
||||
if(!check_rights(R_ADMIN))
|
||||
|
||||
@@ -359,3 +359,27 @@ get_true_breath_pressure(pp) --> gas_pp = pp/breath_pp*total_moles()
|
||||
to_chat(src, "Total time (new gas mixture): [total_time]ms")
|
||||
to_chat(src, "Operations per second: [100000 / (total_time/1000)]")
|
||||
*/
|
||||
|
||||
/// Releases gas from src to output air. This means that it can not transfer air to gas mixture with higher pressure.
|
||||
/datum/gas_mixture/proc/release_gas_to(datum/gas_mixture/output_air, target_pressure)
|
||||
var/output_starting_pressure = output_air.return_pressure()
|
||||
var/input_starting_pressure = return_pressure()
|
||||
|
||||
if(output_starting_pressure >= min(target_pressure,input_starting_pressure-10))
|
||||
//No need to pump gas if target is already reached or input pressure is too low
|
||||
//Need at least 10 KPa difference to overcome friction in the mechanism
|
||||
return FALSE
|
||||
|
||||
//Calculate necessary moles to transfer using PV = nRT
|
||||
if((total_moles() > 0) && (return_temperature()>0))
|
||||
var/pressure_delta = min(target_pressure - output_starting_pressure, (input_starting_pressure - output_starting_pressure)/2)
|
||||
//Can not have a pressure delta that would cause output_pressure > input_pressure
|
||||
|
||||
var/transfer_moles = pressure_delta*output_air.return_volume()/(return_temperature() * R_IDEAL_GAS_EQUATION)
|
||||
|
||||
//Actually transfer the gas
|
||||
var/datum/gas_mixture/removed = remove(transfer_moles)
|
||||
output_air.merge(removed)
|
||||
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -55,26 +55,7 @@ Passive gate is similar to the regular pump except:
|
||||
|
||||
var/datum/gas_mixture/air1 = airs[1]
|
||||
var/datum/gas_mixture/air2 = airs[2]
|
||||
|
||||
var/output_starting_pressure = air2.return_pressure()
|
||||
var/input_starting_pressure = air1.return_pressure()
|
||||
|
||||
if(output_starting_pressure >= min(target_pressure,input_starting_pressure-10))
|
||||
//No need to pump gas if target is already reached or input pressure is too low
|
||||
//Need at least 10 KPa difference to overcome friction in the mechanism
|
||||
return
|
||||
|
||||
//Calculate necessary moles to transfer using PV = nRT
|
||||
if((air1.total_moles() > 0) && (air1.return_temperature()>0))
|
||||
var/pressure_delta = min(target_pressure - output_starting_pressure, (input_starting_pressure - output_starting_pressure)/2)
|
||||
//Can not have a pressure delta that would cause output_pressure > input_pressure
|
||||
|
||||
var/transfer_moles = pressure_delta*air2.return_volume()/(air1.return_temperature() * R_IDEAL_GAS_EQUATION)
|
||||
|
||||
//Actually transfer the gas
|
||||
var/datum/gas_mixture/removed = air1.remove(transfer_moles)
|
||||
air2.merge(removed)
|
||||
|
||||
if(air1.release_gas_to(air2, target_pressure))
|
||||
update_parents()
|
||||
|
||||
|
||||
|
||||
@@ -2,15 +2,18 @@
|
||||
/obj/machinery/atmospherics/components/unary/tank
|
||||
icon = 'icons/obj/atmospherics/pipes/pressure_tank.dmi'
|
||||
icon_state = "generic"
|
||||
|
||||
name = "pressure tank"
|
||||
desc = "A large vessel containing pressurized gas."
|
||||
|
||||
max_integrity = 800
|
||||
density = TRUE
|
||||
layer = ABOVE_WINDOW_LAYER
|
||||
plane = GAME_PLANE
|
||||
pipe_flags = PIPING_ONE_PER_TURF
|
||||
|
||||
var/volume = 10000 //in liters
|
||||
var/gas_type = 0
|
||||
/// The typepath of the gas this tank should be filled with.
|
||||
var/gas_type = null
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/New()
|
||||
..()
|
||||
@@ -20,6 +23,7 @@
|
||||
if(gas_type)
|
||||
air_contents.set_moles(AIR_CONTENTS)
|
||||
name = "[name] ([GLOB.meta_gas_names[gas_type]])"
|
||||
setPipingLayer(piping_layer)
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/air
|
||||
icon_state = "grey"
|
||||
@@ -38,15 +42,71 @@
|
||||
icon_state = "orange"
|
||||
gas_type = /datum/gas/plasma
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/oxygen
|
||||
icon_state = "blue"
|
||||
gas_type = /datum/gas/oxygen
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/nitrogen
|
||||
icon_state = "red"
|
||||
gas_type = /datum/gas/nitrogen
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/nitrous_oxide
|
||||
/obj/machinery/atmospherics/components/unary/tank/oxygen
|
||||
icon_state = "blue"
|
||||
gas_type = /datum/gas/oxygen
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/nitrous
|
||||
icon_state = "red_white"
|
||||
gas_type = /datum/gas/nitrous_oxide
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/bz
|
||||
gas_type = /datum/gas/bz
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/freon
|
||||
// icon_state = "blue"
|
||||
// gas_type = /datum/gas/freon
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/halon
|
||||
// icon_state = "blue"
|
||||
// gas_type = /datum/gas/halon
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/healium
|
||||
// icon_state = "red"
|
||||
// gas_type = /datum/gas/healium
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/hydrogen
|
||||
// icon_state = "grey"
|
||||
// gas_type = /datum/gas/hydrogen
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/hypernoblium
|
||||
icon_state = "blue"
|
||||
gas_type = /datum/gas/hypernoblium
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/miasma
|
||||
gas_type = /datum/gas/miasma
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/nitryl
|
||||
gas_type = /datum/gas/nitryl
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/pluoxium
|
||||
icon_state = "blue"
|
||||
gas_type = /datum/gas/pluoxium
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/proto_nitrate
|
||||
// icon_state = "red"
|
||||
// gas_type = /datum/gas/proto_nitrate
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/stimulum
|
||||
icon_state = "red"
|
||||
gas_type = /datum/gas/stimulum
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/tritium
|
||||
gas_type = /datum/gas/tritium
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/tank/water_vapor
|
||||
icon_state = "grey"
|
||||
gas_type = /datum/gas/water_vapor
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/zauker
|
||||
// gas_type = /datum/gas/zauker
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/helium
|
||||
// gas_type = /datum/gas/helium
|
||||
|
||||
// /obj/machinery/atmospherics/components/unary/tank/antinoblium
|
||||
// gas_type = /datum/gas/antinoblium
|
||||
|
||||
@@ -5,22 +5,28 @@
|
||||
desc = "A canister for the storage of gas."
|
||||
icon_state = "yellow"
|
||||
density = TRUE
|
||||
|
||||
var/valve_open = FALSE
|
||||
var/obj/machinery/atmospherics/components/binary/passive_gate/pump
|
||||
var/release_log = ""
|
||||
|
||||
volume = 1000
|
||||
var/filled = 0.5
|
||||
var/gas_type
|
||||
var/release_pressure = ONE_ATMOSPHERE
|
||||
var/can_max_release_pressure = (ONE_ATMOSPHERE * 10)
|
||||
var/can_min_release_pressure = (ONE_ATMOSPHERE / 10)
|
||||
|
||||
armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 100, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 50)
|
||||
max_integrity = 250
|
||||
integrity_failure = 0.4
|
||||
pressure_resistance = 7 * ONE_ATMOSPHERE
|
||||
|
||||
var/valve_open = FALSE
|
||||
var/release_log = ""
|
||||
|
||||
var/filled = 0.5
|
||||
var/gas_type
|
||||
|
||||
var/release_pressure = ONE_ATMOSPHERE
|
||||
var/can_max_release_pressure = (ONE_ATMOSPHERE * 10)
|
||||
var/can_min_release_pressure = (ONE_ATMOSPHERE / 10)
|
||||
|
||||
// this removes atmos fusion cans**
|
||||
///Max amount of heat allowed inside of the canister before it starts to melt (different tiers have different limits)
|
||||
// var/heat_limit = 5000
|
||||
///Max amount of pressure allowed inside of the canister before it starts to break (different tiers have different limits)
|
||||
// var/pressure_limit = 50000
|
||||
|
||||
var/temperature_resistance = 1000 + T0C
|
||||
var/starter_temp
|
||||
// Prototype vars
|
||||
@@ -32,6 +38,8 @@
|
||||
var/maximum_timer_set = 300
|
||||
var/timing = FALSE
|
||||
var/restricted = FALSE
|
||||
///Set the tier of the canister and overlay used
|
||||
// var/mode = CANISTER_TIER_1
|
||||
req_access = list()
|
||||
|
||||
var/update = 0
|
||||
@@ -195,27 +203,19 @@
|
||||
filled = 1
|
||||
release_pressure = ONE_ATMOSPHERE*2
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/New(loc, datum/gas_mixture/existing_mixture)
|
||||
..()
|
||||
/obj/machinery/portable_atmospherics/canister/Initialize(mapload, datum/gas_mixture/existing_mixture)
|
||||
. = ..()
|
||||
if(existing_mixture)
|
||||
air_contents.copy_from(existing_mixture)
|
||||
else
|
||||
create_gas()
|
||||
pump = new(src, FALSE)
|
||||
pump.on = TRUE
|
||||
pump.stat = 0
|
||||
SSair.add_to_rebuild_queue(pump)
|
||||
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/Destroy()
|
||||
qdel(pump)
|
||||
pump = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/proc/create_gas()
|
||||
if(gas_type)
|
||||
// air_contents.add_gas(gas_type)
|
||||
if(starter_temp)
|
||||
air_contents.set_temperature(starter_temp)
|
||||
air_contents.set_moles(gas_type,(maximum_pressure * filled) * air_contents.return_volume() / (R_IDEAL_GAS_EQUATION * air_contents.return_temperature()))
|
||||
@@ -266,14 +266,17 @@
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
return FALSE
|
||||
|
||||
if(stat & BROKEN)
|
||||
if(!I.tool_start_check(user, amount=0))
|
||||
return TRUE
|
||||
to_chat(user, "<span class='notice'>You begin cutting [src] apart...</span>")
|
||||
if(I.use_tool(src, user, 30, volume=50))
|
||||
deconstruct(TRUE)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You cannot slice [src] apart when it isn't broken.</span>")
|
||||
if(!I.tool_start_check(user, amount=0))
|
||||
return TRUE
|
||||
var/pressure = air_contents.return_pressure()
|
||||
if(pressure > 300)
|
||||
to_chat(user, "<span class='alert'>The pressure gauge on \the [src] indicates a high pressure inside... maybe you want to reconsider?</span>")
|
||||
message_admins("[src] deconstructed by [ADMIN_LOOKUPFLW(user)]")
|
||||
log_game("[src] deconstructed by [key_name(user)]")
|
||||
to_chat(user, "<span class='notice'>You begin cutting \the [src] apart...</span>")
|
||||
if(I.use_tool(src, user, 3 SECONDS, volume=50))
|
||||
to_chat(user, "<span class='notice'>You cut \the [src] apart.</span>")
|
||||
deconstruct(TRUE)
|
||||
|
||||
return TRUE
|
||||
|
||||
@@ -317,18 +320,19 @@
|
||||
valve_open = !valve_open
|
||||
timing = FALSE
|
||||
if(!valve_open)
|
||||
pump.airs[1] = null
|
||||
pump.airs[2] = null
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
var/datum/gas_mixture/target_air = holding ? holding.air_contents : T.return_air()
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
pump.airs[1] = air_contents
|
||||
pump.airs[2] = holding ? holding.air_contents : T.return_air()
|
||||
pump.target_pressure = release_pressure
|
||||
if(air_contents.release_gas_to(target_air, release_pressure) && !holding)
|
||||
air_update_turf()
|
||||
|
||||
pump.process_atmos() // Pump gas.
|
||||
if(!holding)
|
||||
air_update_turf() // Update the environment if needed.
|
||||
// var/our_pressure = air_contents.return_pressure()
|
||||
// var/our_temperature = air_contents.return_temperature()
|
||||
|
||||
///function used to check the limit of the canisters and also set the amount of damage that the canister can receive, if the heat and pressure are way higher than the limit the more damage will be done
|
||||
// currently unused
|
||||
// if(our_temperature > heat_limit || our_pressure > pressure_limit)
|
||||
// take_damage(clamp((our_temperature/heat_limit) * (our_pressure/pressure_limit) * delta_time * 2, 5, 50), BURN, 0)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/ui_state(mob/user)
|
||||
@@ -340,35 +344,48 @@
|
||||
ui = new(user, src, "Canister", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/ui_static_data(mob/user)
|
||||
return list(
|
||||
"defaultReleasePressure" = round(CAN_DEFAULT_RELEASE_PRESSURE),
|
||||
"minReleasePressure" = round(can_min_release_pressure),
|
||||
"maxReleasePressure" = round(can_max_release_pressure),
|
||||
"pressureLimit" = round(1e14),
|
||||
"holdingTankLeakPressure" = round(TANK_LEAK_PRESSURE),
|
||||
"holdingTankFragPressure" = round(TANK_FRAGMENT_PRESSURE)
|
||||
)
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/ui_data()
|
||||
var/data = list()
|
||||
data["portConnected"] = connected_port ? 1 : 0
|
||||
data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
|
||||
data["releasePressure"] = round(release_pressure ? release_pressure : 0)
|
||||
data["defaultReleasePressure"] = round(CAN_DEFAULT_RELEASE_PRESSURE)
|
||||
data["minReleasePressure"] = round(can_min_release_pressure)
|
||||
data["maxReleasePressure"] = round(can_max_release_pressure)
|
||||
data["valveOpen"] = valve_open ? 1 : 0
|
||||
. = list(
|
||||
"portConnected" = !!connected_port,
|
||||
"tankPressure" = round(air_contents.return_pressure()),
|
||||
"releasePressure" = round(release_pressure),
|
||||
"valveOpen" = !!valve_open,
|
||||
"isPrototype" = !!prototype,
|
||||
"hasHoldingTank" = !!holding
|
||||
)
|
||||
|
||||
data["isPrototype"] = prototype ? 1 : 0
|
||||
if (prototype)
|
||||
data["restricted"] = restricted
|
||||
data["timing"] = timing
|
||||
data["time_left"] = get_time_left()
|
||||
data["timer_set"] = timer_set
|
||||
data["timer_is_not_default"] = timer_set != default_timer_set
|
||||
data["timer_is_not_min"] = timer_set != minimum_timer_set
|
||||
data["timer_is_not_max"] = timer_set != maximum_timer_set
|
||||
. += list(
|
||||
"restricted" = restricted,
|
||||
"timing" = timing,
|
||||
"time_left" = get_time_left(),
|
||||
"timer_set" = timer_set,
|
||||
"timer_is_not_default" = timer_set != default_timer_set,
|
||||
"timer_is_not_min" = timer_set != minimum_timer_set,
|
||||
"timer_is_not_max" = timer_set != maximum_timer_set
|
||||
)
|
||||
|
||||
data["hasHoldingTank"] = holding ? 1 : 0
|
||||
if (holding)
|
||||
data["holdingTank"] = list()
|
||||
data["holdingTank"]["name"] = holding.name
|
||||
data["holdingTank"]["tankPressure"] = round(holding.air_contents.return_pressure())
|
||||
return data
|
||||
. += list(
|
||||
"holdingTank" = list(
|
||||
"name" = holding.name,
|
||||
"tankPressure" = round(holding.air_contents.return_pressure())
|
||||
)
|
||||
)
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/ui_act(action, params)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
switch(action)
|
||||
if("relabel")
|
||||
@@ -377,6 +394,7 @@
|
||||
var/newtype = label2types[label]
|
||||
if(newtype)
|
||||
var/obj/machinery/portable_atmospherics/canister/replacement = newtype
|
||||
investigate_log("was relabelled to [initial(replacement.name)] by [key_name(usr)].", INVESTIGATE_ATMOS)
|
||||
name = initial(replacement.name)
|
||||
desc = initial(replacement.desc)
|
||||
icon_state = initial(replacement.icon_state)
|
||||
@@ -458,9 +476,8 @@
|
||||
if("eject")
|
||||
if(holding)
|
||||
if(valve_open)
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] removed [holding] from [src] with valve still open at [ADMIN_VERBOSEJMP(src)] releasing contents into the <span class='boldannounce'>air</span><br>.")
|
||||
investigate_log("[key_name(usr)] removed the [holding], leaving the valve open and transferring into the <span class='boldannounce'>air</span><br>", INVESTIGATE_ATMOS)
|
||||
holding.forceMove(get_turf(src))
|
||||
holding = null
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] removed [holding] from [src] with valve still open at [ADMIN_VERBOSEJMP(src)] releasing contents into the <span class='boldannounce'>air</span>.")
|
||||
investigate_log("[key_name(usr)] removed the [holding], leaving the valve open and transferring into the <span class='boldannounce'>air</span>.", INVESTIGATE_ATMOS)
|
||||
replace_tank(usr, FALSE)
|
||||
. = TRUE
|
||||
update_icon()
|
||||
|
||||
@@ -190,11 +190,7 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
|
||||
to_chat(usr, "<span class='notice'>Sorry, tracking is currently disabled.</span>")
|
||||
return
|
||||
|
||||
var/list/body = list()
|
||||
body += "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Playtime for [key]</title></head><BODY><BR>Playtime:"
|
||||
body += get_exp_report()
|
||||
body += "</BODY></HTML>"
|
||||
usr << browse(body.Join(), "window=playerplaytime[ckey];size=550x615")
|
||||
new /datum/job_report_menu(src, usr)
|
||||
|
||||
/client/proc/ignore_key(client)
|
||||
var/client/C = client
|
||||
|
||||
@@ -156,11 +156,7 @@
|
||||
/obj/machinery/processor/slime
|
||||
name = "slime processor"
|
||||
desc = "An industrial grinder with a sticker saying appropriated for science department. Keep hands clear of intake area while operating."
|
||||
|
||||
/obj/machinery/processor/slime/Initialize()
|
||||
. = ..()
|
||||
var/obj/item/circuitboard/machine/B = new /obj/item/circuitboard/machine/processor/slime(null)
|
||||
B.apply_default_parts(src)
|
||||
circuit = /obj/item/circuitboard/machine/processor/slime
|
||||
|
||||
/obj/machinery/processor/slime/adjust_item_drop_location(atom/movable/AM)
|
||||
var/static/list/slimecores = subtypesof(/obj/item/slime_extract)
|
||||
|
||||
49
code/modules/jobs/job_report.dm
Normal file
@@ -0,0 +1,49 @@
|
||||
#define JOB_REPORT_MENU_FAIL_REASON_TRACKING_DISABLED 1
|
||||
#define JOB_REPORT_MENU_FAIL_REASON_NO_RECORDS 2
|
||||
|
||||
/datum/job_report_menu
|
||||
var/client/owner
|
||||
|
||||
/datum/job_report_menu/New(client/owner, mob/viewer)
|
||||
src.owner = owner
|
||||
ui_interact(viewer)
|
||||
|
||||
/datum/job_report_menu/ui_state()
|
||||
return GLOB.always_state
|
||||
|
||||
/datum/job_report_menu/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if (!ui)
|
||||
ui = new(user, src, "TrackedPlaytime")
|
||||
ui.open()
|
||||
|
||||
/datum/job_report_menu/ui_static_data()
|
||||
if (!CONFIG_GET(flag/use_exp_tracking))
|
||||
return list("failReason" = JOB_REPORT_MENU_FAIL_REASON_TRACKING_DISABLED)
|
||||
|
||||
var/list/play_records = owner.prefs.exp
|
||||
if (!play_records.len)
|
||||
owner.set_exp_from_db()
|
||||
play_records = owner.prefs.exp
|
||||
if (!play_records.len)
|
||||
return list("failReason" = JOB_REPORT_MENU_FAIL_REASON_NO_RECORDS)
|
||||
|
||||
var/list/data = list()
|
||||
data["jobPlaytimes"] = list()
|
||||
data["specialPlaytimes"] = list()
|
||||
|
||||
for (var/job_name in SSjob.name_occupations)
|
||||
var/playtime = play_records[job_name] ? text2num(play_records[job_name]) : 0
|
||||
data["jobPlaytimes"][job_name] = playtime
|
||||
|
||||
for (var/special_name in GLOB.exp_specialmap[EXP_TYPE_SPECIAL])
|
||||
var/playtime = play_records[special_name] ? text2num(play_records[special_name]) : 0
|
||||
data["specialPlaytimes"][special_name] = playtime
|
||||
|
||||
data["livingTime"] = play_records[EXP_TYPE_LIVING]
|
||||
data["ghostTime"] = play_records[EXP_TYPE_GHOST]
|
||||
|
||||
return data
|
||||
|
||||
#undef JOB_REPORT_MENU_FAIL_REASON_TRACKING_DISABLED
|
||||
#undef JOB_REPORT_MENU_FAIL_REASON_NO_RECORDS
|
||||
@@ -8,12 +8,12 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
icon = 'icons/obj/machines/mining_machines.dmi'
|
||||
icon_state = "console"
|
||||
density = FALSE
|
||||
|
||||
/// Connected stacking machine
|
||||
var/obj/machinery/mineral/stacking_machine/laborstacker/stacking_machine = null
|
||||
/// Direction of the stacking machine
|
||||
var/machinedir = SOUTH
|
||||
var/obj/machinery/door/airlock/release_door
|
||||
var/door_tag = "prisonshuttle"
|
||||
var/obj/item/radio/Radio //needed to send messages to sec radio
|
||||
/// Needed to send messages to sec radio
|
||||
var/obj/item/radio/Radio
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/Initialize()
|
||||
. = ..()
|
||||
@@ -39,15 +39,23 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
ui = new(user, src, "LaborClaimConsole", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["ores"] = GLOB.labor_sheet_values
|
||||
return data
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
var/can_go_home = FALSE
|
||||
|
||||
data["emagged"] = (obj_flags & EMAGGED) ? 1 : 0
|
||||
data["emagged"] = FALSE
|
||||
if(obj_flags & EMAGGED)
|
||||
data["emagged"] = TRUE
|
||||
can_go_home = TRUE
|
||||
|
||||
var/obj/item/card/id/I = user.get_idcard(TRUE)
|
||||
var/obj/item/card/id/I
|
||||
if(isliving(usr))
|
||||
var/mob/living/L = usr
|
||||
I = L.get_idcard(TRUE)
|
||||
if(istype(I, /obj/item/card/id/prisoner))
|
||||
var/obj/item/card/id/prisoner/P = I
|
||||
data["id_points"] = P.points
|
||||
@@ -63,43 +71,46 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
if(stacking_machine)
|
||||
data["unclaimed_points"] = stacking_machine.points
|
||||
|
||||
data["ores"] = GLOB.labor_sheet_values
|
||||
data["can_go_home"] = can_go_home
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/ui_act(action, params)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/mob/M = usr
|
||||
switch(action)
|
||||
if("claim_points")
|
||||
var/mob/M = usr
|
||||
var/obj/item/card/id/I = M.get_idcard(TRUE)
|
||||
var/obj/item/card/id/I
|
||||
if(isliving(M))
|
||||
var/mob/living/L = M
|
||||
I = L.get_idcard(TRUE)
|
||||
if(istype(I, /obj/item/card/id/prisoner))
|
||||
var/obj/item/card/id/prisoner/P = I
|
||||
P.points += stacking_machine.points
|
||||
stacking_machine.points = 0
|
||||
to_chat(usr, "<span class='notice'>Points transferred.</span>")
|
||||
. = TRUE
|
||||
to_chat(M, "<span class='notice'>Points transferred.</span>")
|
||||
return TRUE
|
||||
else
|
||||
to_chat(usr, "<span class='alert'>No valid id for point transfer detected.</span>")
|
||||
to_chat(M, "<span class='alert'>No valid id for point transfer detected.</span>")
|
||||
if("move_shuttle")
|
||||
if(!alone_in_area(get_area(src), usr))
|
||||
to_chat(usr, "<span class='alert'>Prisoners are only allowed to be released while alone.</span>")
|
||||
else
|
||||
switch(SSshuttle.moveShuttle("laborcamp", "laborcamp_home", TRUE))
|
||||
if(1)
|
||||
to_chat(usr, "<span class='alert'>Shuttle not found.</span>")
|
||||
if(2)
|
||||
to_chat(usr, "<span class='alert'>Shuttle already at station.</span>")
|
||||
if(3)
|
||||
to_chat(usr, "<span class='alert'>No permission to dock could be granted.</span>")
|
||||
else
|
||||
if(!(obj_flags & EMAGGED))
|
||||
Radio.set_frequency(FREQ_SECURITY)
|
||||
Radio.talk_into(src, "A prisoner has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY)
|
||||
to_chat(usr, "<span class='notice'>Shuttle received message and will be sent shortly.</span>")
|
||||
. = TRUE
|
||||
if(!alone_in_area(get_area(src), M))
|
||||
to_chat(M, "<span class='alert'>Prisoners are only allowed to be released while alone.</span>")
|
||||
return
|
||||
switch(SSshuttle.moveShuttle("laborcamp", "laborcamp_home", TRUE))
|
||||
if(1)
|
||||
to_chat(M, "<span class='alert'>Shuttle not found.</span>")
|
||||
if(2)
|
||||
to_chat(M, "<span class='alert'>Shuttle already at station.</span>")
|
||||
if(3)
|
||||
to_chat(M, "<span class='alert'>No permission to dock could be granted.</span>")
|
||||
else
|
||||
if(!(obj_flags & EMAGGED))
|
||||
Radio.set_frequency(FREQ_SECURITY)
|
||||
Radio.talk_into(src, "A prisoner has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY)
|
||||
to_chat(M, "<span class='notice'>Shuttle received message and will be sent shortly.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/proc/locate_stacking_machine()
|
||||
stacking_machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir))
|
||||
@@ -110,10 +121,9 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/emag_act(mob/user)
|
||||
. = ..()
|
||||
if((obj_flags & EMAGGED))
|
||||
return
|
||||
obj_flags |= EMAGGED
|
||||
to_chat(user, "<span class='warning'>PZZTTPFFFT</span>")
|
||||
if(!(obj_flags & EMAGGED))
|
||||
obj_flags |= EMAGGED
|
||||
to_chat(user, "<span class='warning'>PZZTTPFFFT</span>")
|
||||
return TRUE
|
||||
|
||||
/**********************Prisoner Collection Unit**************************/
|
||||
@@ -121,13 +131,13 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
/obj/machinery/mineral/stacking_machine/laborstacker
|
||||
force_connect = TRUE
|
||||
var/points = 0 //The unclaimed value of ore stacked.
|
||||
//damage_deflection = 21
|
||||
// damage_deflection = 21
|
||||
/obj/machinery/mineral/stacking_machine/laborstacker/process_sheet(obj/item/stack/sheet/inp)
|
||||
points += inp.point_value * inp.amount
|
||||
..()
|
||||
|
||||
/obj/machinery/mineral/stacking_machine/laborstacker/attackby(obj/item/I, mob/living/user)
|
||||
if(istype(I, /obj/item/stack/sheet) && user.canUnEquip(I))
|
||||
if(istype(I, /obj/item/stack/sheet) && user.canUnEquip(I) && user.a_intent == INTENT_HELP)
|
||||
var/obj/item/stack/sheet/inp = I
|
||||
points += inp.point_value * inp.amount
|
||||
return ..()
|
||||
@@ -141,7 +151,10 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
icon_state = "console"
|
||||
density = FALSE
|
||||
|
||||
/obj/machinery/mineral/labor_points_checker/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/machinery/mineral/labor_points_checker/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(. || user.is_blind())
|
||||
return
|
||||
user.examinate(src)
|
||||
|
||||
/obj/machinery/mineral/labor_points_checker/attackby(obj/item/I, mob/user, params)
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
desc = "A computer system running a deep neural network that processes arbitrary information to produce data useable in the development of new technologies. In layman's terms, it makes research points."
|
||||
icon = 'icons/obj/machines/research.dmi'
|
||||
icon_state = "server"
|
||||
req_access = list(ACCESS_RD) //ONLY THE R&D CAN CHANGE SERVER SETTINGS.
|
||||
circuit = /obj/item/circuitboard/machine/rdserver
|
||||
|
||||
var/datum/techweb/stored_research
|
||||
var/heat_health = 100
|
||||
//Code for point mining here.
|
||||
@@ -15,14 +18,11 @@
|
||||
var/temp_tolerance_low = 0
|
||||
var/temp_tolerance_high = T20C
|
||||
var/temp_penalty_coefficient = 0.5 //1 = -1 points per degree above high tolerance. 0.5 = -0.5 points per degree above high tolerance.
|
||||
req_access = list(ACCESS_RD) //ONLY THE R&D CAN CHANGE SERVER SETTINGS.
|
||||
|
||||
/obj/machinery/rnd/server/Initialize()
|
||||
. = ..()
|
||||
SSresearch.servers |= src
|
||||
stored_research = SSresearch.science_tech
|
||||
var/obj/item/circuitboard/machine/B = new /obj/item/circuitboard/machine/rdserver(null)
|
||||
B.apply_default_parts(src)
|
||||
|
||||
/obj/machinery/rnd/server/Destroy()
|
||||
SSresearch.servers -= src
|
||||
|
||||
@@ -33,14 +33,14 @@
|
||||
|
||||
/datum/station_goal/dna_vault/get_report()
|
||||
return {"Our long term prediction systems indicate a 99% chance of system-wide cataclysm in the near future.
|
||||
We need you to construct a DNA Vault aboard your station.
|
||||
We need you to construct a DNA Vault aboard your station.
|
||||
|
||||
The DNA Vault needs to contain samples of:
|
||||
[animal_count] unique animal data
|
||||
[plant_count] unique non-standard plant data
|
||||
[human_count] unique sapient humanoid DNA data
|
||||
The DNA Vault needs to contain samples of:
|
||||
[animal_count] unique animal data
|
||||
[plant_count] unique non-standard plant data
|
||||
[human_count] unique sapient humanoid DNA data
|
||||
|
||||
Base vault parts are available for shipping via cargo."}
|
||||
Base vault parts are available for shipping via cargo."}
|
||||
|
||||
|
||||
/datum/station_goal/dna_vault/on_report()
|
||||
@@ -87,7 +87,7 @@
|
||||
if(!H.myseed)
|
||||
return
|
||||
if(!H.harvest)// So it's bit harder.
|
||||
to_chat(user, "<span class='warning'>Plant needs to be ready to harvest to perform full data scan.</span>") //Because space dna is actually magic
|
||||
to_chat(user, "<span class='alert'>Plant needs to be ready to harvest to perform full data scan.</span>") //Because space dna is actually magic
|
||||
return
|
||||
if(plants[H.myseed.type])
|
||||
to_chat(user, "<span class='notice'>Plant data already present in local storage.</span>")
|
||||
@@ -101,10 +101,10 @@
|
||||
if(isanimal(target))
|
||||
var/mob/living/simple_animal/A = target
|
||||
if(!A.healable)//simple approximation of being animal not a robot or similar
|
||||
to_chat(user, "<span class='warning'>No compatible DNA detected</span>")
|
||||
to_chat(user, "<span class='alert'>No compatible DNA detected.</span>")
|
||||
return
|
||||
if(animals[target.type])
|
||||
to_chat(user, "<span class='notice'>Animal data already present in local storage.</span>")
|
||||
to_chat(user, "<span class='alert'>Animal data already present in local storage.</span>")
|
||||
return
|
||||
animals[target.type] = 1
|
||||
to_chat(user, "<span class='notice'>Animal data added to local storage.</span>")
|
||||
@@ -173,7 +173,6 @@
|
||||
qdel(filler)
|
||||
. = ..()
|
||||
|
||||
|
||||
/obj/machinery/dna_vault/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
@@ -204,15 +203,17 @@
|
||||
data["choiceB"] = ""
|
||||
if(user && completed)
|
||||
var/list/L = power_lottery[user]
|
||||
if(L && L.len)
|
||||
if(L?.len)
|
||||
data["used"] = FALSE
|
||||
data["choiceA"] = L[1]
|
||||
data["choiceB"] = L[2]
|
||||
return data
|
||||
|
||||
/obj/machinery/dna_vault/ui_act(action, params)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("gene")
|
||||
upgrade(usr,params["choice"])
|
||||
@@ -244,8 +245,6 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
|
||||
/obj/machinery/dna_vault/proc/upgrade(mob/living/carbon/human/H,upgrade_type)
|
||||
if(!(upgrade_type in power_lottery[H]))
|
||||
return
|
||||
|
||||
|
Before Width: | Height: | Size: 237 B After Width: | Height: | Size: 337 B |
|
Before Width: | Height: | Size: 392 B |
|
Before Width: | Height: | Size: 84 B |
|
Before Width: | Height: | Size: 454 B |
|
Before Width: | Height: | Size: 487 B |
|
Before Width: | Height: | Size: 491 B |
|
Before Width: | Height: | Size: 164 B |
|
Before Width: | Height: | Size: 275 B |
|
Before Width: | Height: | Size: 256 B |
|
Before Width: | Height: | Size: 326 B |
|
Before Width: | Height: | Size: 352 B |
|
Before Width: | Height: | Size: 468 B |
|
Before Width: | Height: | Size: 449 B |
|
Before Width: | Height: | Size: 503 B |
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 14 KiB |
@@ -2278,6 +2278,7 @@
|
||||
#include "code\modules\integrated_electronics\subtypes\weaponized.dm"
|
||||
#include "code\modules\jobs\access.dm"
|
||||
#include "code\modules\jobs\job_exp.dm"
|
||||
#include "code\modules\jobs\job_report.dm"
|
||||
#include "code\modules\jobs\jobs.dm"
|
||||
#include "code\modules\jobs\job_types\_job.dm"
|
||||
#include "code\modules\jobs\job_types\ai.dm"
|
||||
|
||||