icons should exist

This commit is contained in:
Letter N
2021-02-14 11:39:56 +08:00
parent 45d6a5f87f
commit de67720a0a
43 changed files with 738 additions and 475 deletions

View File

@@ -117,8 +117,8 @@
#define ui_borg_camera "CENTER+3:21,SOUTH:5" #define ui_borg_camera "CENTER+3:21,SOUTH:5"
#define ui_borg_alerts "CENTER+4: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_language_menu "CENTER+4:21,SOUTH+1:5"
#define ui_borg_sensor "CENTER-3:15, SOUTH:5" //LEGACY #define ui_borg_sensor "CENTER-6:16, SOUTH:5" //LEGACY
#define ui_borg_thrusters "CENTER-5:15, SOUTH:5" //LEGACY #define ui_borg_thrusters "CENTER-5:16, SOUTH:5" //LEGACY
//Aliens //Aliens
#define ui_alien_health "EAST,CENTER-1:15" #define ui_alien_health "EAST,CENTER-1:15"

View File

@@ -676,7 +676,7 @@ SUBSYSTEM_DEF(shuttle)
if(!preview_shuttle) if(!preview_shuttle)
load_template(loading_template) load_template(loading_template)
preview_shuttle.linkup(loading_template, destination_port) // preview_shuttle.linkup(loading_template, destination_port)
preview_template = loading_template preview_template = loading_template
// get the existing shuttle information, if any // get the existing shuttle information, if any

View File

@@ -454,12 +454,12 @@
return SSshuttle.shuttle_purchase_requirements_met["emagged"] return SSshuttle.shuttle_purchase_requirements_met["emagged"]
/datum/map_template/shuttle/emergency/cruise // /datum/map_template/shuttle/emergency/cruise
suffix = "cruise" // suffix = "cruise"
name = "The NTSS Independence" // 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!" // 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." // admin_notes = "This motherfucker is BIG. You might need to force dock it."
credit_cost = 8000 // credit_cost = 8000
/datum/map_template/shuttle/emergency/monkey /datum/map_template/shuttle/emergency/monkey
suffix = "nature" suffix = "nature"

View File

@@ -1,3 +1,5 @@
#define DEFAULT_MAP_SIZE 15
/obj/machinery/computer/security /obj/machinery/computer/security
name = "security camera console" name = "security camera console"
desc = "Used to access the various cameras on the station." desc = "Used to access the various cameras on the station."
@@ -8,15 +10,19 @@
var/list/network = list("ss13") var/list/network = list("ss13")
var/obj/machinery/camera/active_camera var/obj/machinery/camera/active_camera
/// The turf where the camera was last updated.
var/turf/last_camera_turf
var/list/concurrent_users = list() var/list/concurrent_users = list()
// Stuff needed to render the map // Stuff needed to render the map
var/map_name var/map_name
var/const/default_map_size = 15 var/obj/screen/map_view/cam_screen
var/obj/screen/cam_screen /// All the plane masters that need to be applied.
var/obj/screen/plane_master/lighting/cam_plane_master var/list/cam_plane_masters
var/obj/screen/background/cam_background 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() /obj/machinery/computer/security/Initialize()
. = ..() . = ..()
// Map name has to start and end with an A-Z character, // Map name has to start and end with an A-Z character,
@@ -33,18 +39,20 @@
cam_screen.assigned_map = map_name cam_screen.assigned_map = map_name
cam_screen.del_on_map_removal = FALSE cam_screen.del_on_map_removal = FALSE
cam_screen.screen_loc = "[map_name]:1,1" cam_screen.screen_loc = "[map_name]:1,1"
cam_plane_master = new cam_plane_masters = list()
cam_plane_master.name = "plane_master" for(var/plane in subtypesof(/obj/screen/plane_master))
cam_plane_master.assigned_map = map_name var/obj/screen/instance = new plane()
cam_plane_master.del_on_map_removal = FALSE instance.assigned_map = map_name
cam_plane_master.screen_loc = "[map_name]:CENTER" instance.del_on_map_removal = FALSE
instance.screen_loc = "[map_name]:CENTER"
cam_plane_masters += instance
cam_background = new cam_background = new
cam_background.assigned_map = map_name cam_background.assigned_map = map_name
cam_background.del_on_map_removal = FALSE cam_background.del_on_map_removal = FALSE
/obj/machinery/computer/security/Destroy() /obj/machinery/computer/security/Destroy()
qdel(cam_screen) qdel(cam_screen)
qdel(cam_plane_master) QDEL_LIST(cam_plane_masters)
qdel(cam_background) qdel(cam_background)
return ..() return ..()
@@ -56,9 +64,10 @@
/obj/machinery/computer/security/ui_interact(mob/user, datum/tgui/ui) /obj/machinery/computer/security/ui_interact(mob/user, datum/tgui/ui)
// Update UI // Update UI
ui = SStgui.try_update_ui(user, src, ui) ui = SStgui.try_update_ui(user, src, ui)
// Show static if can't use the camera
if(!active_camera?.can_use()) // Update the camera, showing static if necessary and updating data if the location has moved.
show_camera_static() update_active_camera_screen()
if(!ui) if(!ui)
var/user_ref = REF(user) var/user_ref = REF(user)
var/is_living = isliving(user) var/is_living = isliving(user)
@@ -72,7 +81,7 @@
use_power(active_power_usage) use_power(active_power_usage)
// Register map objects // Register map objects
user.client.register_map_obj(cam_screen) 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(plane)
user.client.register_map_obj(cam_background) user.client.register_map_obj(cam_background)
// Open UI // Open UI
@@ -100,6 +109,7 @@
data["cameras"] += list(list( data["cameras"] += list(list(
name = C.c_tag, name = C.c_tag,
)) ))
return data return data
/obj/machinery/computer/security/ui_act(action, params) /obj/machinery/computer/security/ui_act(action, params)
@@ -110,20 +120,42 @@
if(action == "switch_camera") if(action == "switch_camera")
var/c_tag = params["name"] var/c_tag = params["name"]
var/list/cameras = get_available_cameras() var/list/cameras = get_available_cameras()
var/obj/machinery/camera/C = cameras[c_tag] var/obj/machinery/camera/selected_camera = cameras[c_tag]
active_camera = C active_camera = selected_camera
playsound(src, get_sfx("terminal_type"), 25, FALSE) playsound(src, get_sfx("terminal_type"), 25, FALSE)
if(!selected_camera)
return TRUE
update_active_camera_screen()
return TRUE
/obj/machinery/computer/security/proc/update_active_camera_screen()
// Show static if can't use the camera // Show static if can't use the camera
if(!active_camera?.can_use()) if(!active_camera?.can_use())
show_camera_static() show_camera_static()
return TRUE return
var/list/visible_turfs = list() var/list/visible_turfs = list()
for(var/turf/T in (C.isXRay() \
? range(C.view_range, C) \ // Is this camera located in or attached to a living thing? If so, assume the camera's loc is the living thing.
: view(C.view_range, C))) var/cam_location = isliving(active_camera.loc) ? active_camera.loc : active_camera
visible_turfs += T
// 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/list/bbox = get_bbox_of_atoms(visible_turfs)
var/size_x = bbox[3] - bbox[1] + 1 var/size_x = bbox[3] - bbox[1] + 1
@@ -133,8 +165,6 @@
cam_background.icon_state = "clear" cam_background.icon_state = "clear"
cam_background.fill_rect(1, 1, size_x, size_y) cam_background.fill_rect(1, 1, size_x, size_y)
return TRUE
/obj/machinery/computer/security/ui_close(mob/user) /obj/machinery/computer/security/ui_close(mob/user)
var/user_ref = REF(user) var/user_ref = REF(user)
var/is_living = isliving(user) var/is_living = isliving(user)
@@ -151,7 +181,7 @@
/obj/machinery/computer/security/proc/show_camera_static() /obj/machinery/computer/security/proc/show_camera_static()
cam_screen.vis_contents.Cut() cam_screen.vis_contents.Cut()
cam_background.icon_state = "scanline2" 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 // Returns the list of cameras accessible from this computer
/obj/machinery/computer/security/proc/get_available_cameras() /obj/machinery/computer/security/proc/get_available_cameras()
@@ -179,7 +209,7 @@
name = "security camera monitor" name = "security camera monitor"
desc = "An old TV hooked into the station's camera network." desc = "An old TV hooked into the station's camera network."
icon_state = "television" icon_state = "television"
icon_keyboard = null icon_keyboard = "no_keyboard"
icon_screen = "detective_tv" icon_screen = "detective_tv"
pass_flags = PASSTABLE pass_flags = PASSTABLE
@@ -211,7 +241,7 @@
/obj/machinery/computer/security/qm /obj/machinery/computer/security/qm
name = "\improper Quartermaster's camera console" 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") network = list("mine", "auxbase", "vault")
circuit = null circuit = null
@@ -222,17 +252,12 @@
desc = "Used for watching an empty arena." desc = "Used for watching an empty arena."
icon = 'icons/obj/stationobjs.dmi' icon = 'icons/obj/stationobjs.dmi'
icon_state = "telescreen" icon_state = "telescreen"
layer = SIGN_LAYER
network = list("thunder") network = list("thunder")
density = FALSE density = FALSE
circuit = null circuit = null
light_power = 0 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() /obj/machinery/computer/security/telescreen/update_icon_state()
icon_state = initial(icon_state) icon_state = initial(icon_state)
if(stat & BROKEN) if(stat & BROKEN)
@@ -246,21 +271,19 @@
network = list("thunder") network = list("thunder")
density = FALSE density = FALSE
circuit = null 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_off = "entertainment_blank"
var/icon_state_on = "entertainment" 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() /obj/machinery/computer/security/telescreen/entertainment/Initialize()
. = ..() . = ..()
RegisterSignal(src, COMSIG_CLICK, .proc/BigClick) RegisterSignal(src, COMSIG_CLICK, .proc/BigClick)
// Bypass clickchain to allow humans to use the telescreen from a distance // Bypass clickchain to allow humans to use the telescreen from a distance
/obj/machinery/computer/security/telescreen/entertainment/proc/BigClick() /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) /obj/machinery/computer/security/telescreen/entertainment/proc/notify(on)
if(on && icon_state == icon_state_off) if(on && icon_state == icon_state_off)
@@ -279,8 +302,8 @@
network = list("rd", "aicore", "aiupload", "minisat", "xeno", "test") network = list("rd", "aicore", "aiupload", "minisat", "xeno", "test")
/obj/machinery/computer/security/telescreen/circuitry /obj/machinery/computer/security/telescreen/circuitry
name = "circuitry telescreen" name = "research telescreen"
desc = "Used for watching the other eggheads from the safety of the circuitry lab." desc = "A telescreen with access to the research division's camera network."
network = list("rd") network = list("rd")
/obj/machinery/computer/security/telescreen/ce /obj/machinery/computer/security/telescreen/ce
@@ -324,8 +347,8 @@
network = list("prison") network = list("prison")
/obj/machinery/computer/security/telescreen/auxbase /obj/machinery/computer/security/telescreen/auxbase
name = "auxillary base monitor" name = "auxiliary base monitor"
desc = "A telescreen that connects to the auxillary base's camera." desc = "A telescreen that connects to the auxiliary base's camera."
network = list("auxbase") network = list("auxbase")
/obj/machinery/computer/security/telescreen/minisat /obj/machinery/computer/security/telescreen/minisat
@@ -346,3 +369,5 @@
for(var/i in network) for(var/i in network)
network -= i network -= i
network += "[idnum][i]" network += "[idnum][i]"
#undef DEFAULT_MAP_SIZE

View File

@@ -1,21 +1,37 @@
/obj/machinery/computer/pod /obj/machinery/computer/pod
name = "mass driver launch control" name = "mass driver launch control"
desc = "A combined blastdoor and mass driver control unit." 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/obj/machinery/mass_driver/connected = null
var/title = "Mass Driver Controls" /// ID of the launch control
var/id = 1 var/id = 1
var/timing = 0 /// If the launch timer counts down
var/timing = FALSE
/// Time before auto launch
var/time = 30 var/time = 30
/// Range in which we search for a mass drivers and poddoors nearby
var/range = 4 var/range = 4
/// Countdown timer for the mass driver's delayed launch functionality.
COOLDOWN_DECLARE(massdriver_countdown)
/obj/machinery/computer/pod/Initialize() /obj/machinery/computer/pod/Initialize()
. = ..() . = ..()
for(var/obj/machinery/mass_driver/M in range(range, src)) for(var/obj/machinery/mass_driver/M in range(range, src))
if(M.id == id) if(M.id == id)
connected = M 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() /obj/machinery/computer/pod/proc/alarm()
if(stat & (NOPOWER|BROKEN)) if(stat & (NOPOWER|BROKEN))
return return
@@ -39,92 +55,110 @@
if(M.id == id) if(M.id == id)
M.close() 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)) if(.)
to_chat(user, "<span class='warning'>Access denied.</span>") return
if(!allowed(usr))
to_chat(usr, "<span class='warning'>Access denied.</span>")
return return
var/dat = "" switch(action)
if(connected) if("set_power")
var/d2 if(!connected)
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] "
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 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) if(timing)
if(time > 0) COOLDOWN_START(src, massdriver_countdown, time SECONDS)
time = round(time) - 1 begin_processing()
else else
alarm() time = COOLDOWN_TIMELEFT(src, massdriver_countdown) * 0.1
time = 0 COOLDOWN_RESET(src, massdriver_countdown)
timing = 0 end_processing()
updateDialog() return TRUE
if("input")
var/value = text2num(params["adjust"])
/obj/machinery/computer/pod/Topic(href, href_list) if(!value)
if(..())
return return
if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || hasSiliconAccessInArea(usr)) value = round(time + value)
usr.set_machine(src) time = clamp(value, 0, 120)
if(href_list["power"]) return TRUE
var/t = text2num(href_list["power"]) if("door")
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"])
for(var/obj/machinery/door/poddoor/M in range(range, src)) for(var/obj/machinery/door/poddoor/M in range(range, src))
if(M.id == id) if(M.id == id)
if(M.density) if(M.density)
M.open() M.open()
else else
M.close() M.close()
if(href_list["drive"]) return TRUE
if("driver_test")
for(var/obj/machinery/mass_driver/M in range(range, src)) for(var/obj/machinery/mass_driver/M in range(range, src))
if(M.id == id) if(M.id == id)
M.power = connected.power M.power = connected?.power
M.drive() M.drive()
updateUsrDialog() return TRUE
/obj/machinery/computer/pod/old /obj/machinery/computer/pod/old
name = "\improper DoorMex control console" name = "\improper DoorMex control console"
title = "Door Controls"
icon_state = "oldcomp" icon_state = "oldcomp"
icon_screen = "library" 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 /obj/machinery/computer/pod/old/syndicate
name = "\improper ProComp Executive IIc" name = "\improper ProComp Executive IIc"
desc = "The Syndicate operate on a tight budget. Operates external airlocks." desc = "The Syndicate operate on a tight budget. Operates external airlocks."
title = "External Airlock Controls"
req_access = list(ACCESS_SYNDICATE) req_access = list(ACCESS_SYNDICATE)
/obj/machinery/computer/pod/old/swf /obj/machinery/computer/pod/old/swf

View File

@@ -11,8 +11,24 @@
var/id = 1 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. 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) // /obj/machinery/mass_driver/chapelgun
id = "[idnum][id]" // 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) /obj/machinery/mass_driver/proc/drive(amount)
if(stat & (BROKEN|NOPOWER)) if(stat & (BROKEN|NOPOWER))
@@ -22,6 +38,8 @@
var/atom/target = get_edge_target_turf(src, dir) var/atom/target = get_edge_target_turf(src, dir)
for(var/atom/movable/O in loc) for(var/atom/movable/O in loc)
if(!O.anchored || ismecha(O)) //Mechs need their launch platforms. if(!O.anchored || ismecha(O)) //Mechs need their launch platforms.
// if(ismob(O) && !isliving(O))
// continue
O_limit++ O_limit++
if(O_limit >= 20) 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>") 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) O.throw_at(target, drive_range * power, power)
flick("mass_driver1", src) flick("mass_driver1", src)
/obj/machinery/mass_driver/emp_act(severity) /obj/machinery/mass_driver/emp_act(severity)
. = ..() . = ..()
if (. & EMP_PROTECT_SELF) if (. & EMP_PROTECT_SELF)

View File

@@ -29,7 +29,7 @@
integrity = round((M.obj_integrity / M.max_integrity) * 100), integrity = round((M.obj_integrity / M.max_integrity) * 100),
charge = M.cell ? round(M.cell.percent()) : null, charge = M.cell ? round(M.cell.percent()) : null,
airtank = M.internal_tank ? M.return_pressure() : null, airtank = M.internal_tank ? M.return_pressure() : null,
pilot = M.occupant, pilot = list(M.occupant),
location = get_area_name(M, TRUE), location = get_area_name(M, TRUE),
active_equipment = M.selected, active_equipment = M.selected,
emp_recharging = MT.recharging, emp_recharging = MT.recharging,
@@ -38,7 +38,7 @@
if(istype(M, /obj/mecha/working/ripley)) if(istype(M, /obj/mecha/working/ripley))
var/obj/mecha/working/ripley/RM = M var/obj/mecha/working/ripley/RM = M
mech_data += list( 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) data["mechs"] += list(mech_data)
@@ -46,7 +46,8 @@
return data return data
/obj/machinery/computer/mecha/ui_act(action, params) /obj/machinery/computer/mecha/ui_act(action, params)
if(..()) . = ..()
if(.)
return return
switch(action) switch(action)
@@ -57,7 +58,7 @@
var/message = stripped_input(usr, "Input message", "Transmit message") var/message = stripped_input(usr, "Input message", "Transmit message")
var/obj/mecha/M = MT.chassis var/obj/mecha/M = MT.chassis
if(trim(message) && M) if(trim(message) && M)
M.occupant_message(message) to_chat(M.occupant, message)
to_chat(usr, "<span class='notice'>Message sent.</span>") to_chat(usr, "<span class='notice'>Message sent.</span>")
. = TRUE . = TRUE
if("shock") if("shock")
@@ -67,8 +68,8 @@
var/obj/mecha/M = MT.chassis var/obj/mecha/M = MT.chassis
if(M) if(M)
MT.shock() 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."] ") 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.occupant ? "being piloted by [key_name_admin(M.occupant)][ADMIN_FLW(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 . = TRUE
/obj/item/mecha_parts/mecha_tracking /obj/item/mecha_parts/mecha_tracking
@@ -101,7 +102,7 @@
<b>Active Equipment:</b> [chassis.selected || "None"]"} <b>Active Equipment:</b> [chassis.selected || "None"]"}
if(istype(chassis, /obj/mecha/working/ripley)) if(istype(chassis, /obj/mecha/working/ripley))
var/obj/mecha/working/ripley/RM = chassis 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 return answer

View File

@@ -439,6 +439,8 @@
if(zero_amount()) if(zero_amount())
return return
return split_stack(user, 1) return split_stack(user, 1)
else
. = ..()
/obj/item/stack/AltClick(mob/living/user) /obj/item/stack/AltClick(mob/living/user)
. = ..() . = ..()

View File

@@ -1,10 +1,12 @@
/obj/item/tank /obj/item/tank
name = "tank" name = "tank"
icon = 'icons/obj/tank.dmi' icon = 'icons/obj/tank.dmi'
icon_state = "generic"
lefthand_file = 'icons/mob/inhands/equipment/tanks_lefthand.dmi' lefthand_file = 'icons/mob/inhands/equipment/tanks_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tanks_righthand.dmi' righthand_file = 'icons/mob/inhands/equipment/tanks_righthand.dmi'
flags_1 = CONDUCT_1 flags_1 = CONDUCT_1
slot_flags = ITEM_SLOT_BACK 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' hitsound = 'sound/weapons/smash.ogg'
pressure_resistance = ONE_ATMOSPHERE * 5 pressure_resistance = ONE_ATMOSPHERE * 5
force = 5 force = 5
@@ -18,12 +20,14 @@
var/distribute_pressure = ONE_ATMOSPHERE var/distribute_pressure = ONE_ATMOSPHERE
var/integrity = 3 var/integrity = 3
var/volume = 70 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) /obj/item/tank/ui_action_click(mob/user)
toggle_internals(user) toggle_internals(user)
/obj/item/tank/proc/toggle_internals(mob/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)) if(!istype(H))
return return
@@ -84,11 +88,16 @@
/obj/item/tank/Destroy() /obj/item/tank/Destroy()
if(air_contents) if(air_contents)
qdel(air_contents) QDEL_NULL(air_contents)
STOP_PROCESSING(SSobj, src) 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) /obj/item/tank/examine(mob/user)
var/obj/icon = src var/obj/icon = src
. = ..() . = ..()
@@ -140,13 +149,13 @@
if(T) if(T)
T.assume_air(air_contents) T.assume_air(air_contents)
air_update_turf() 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) qdel(src)
/obj/item/tank/suicide_act(mob/user) /obj/item/tank/suicide_act(mob/user)
var/mob/living/carbon/human/H = 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>") 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) playsound(loc, 'sound/effects/spray.ogg', 10, TRUE, -3)
if(!QDELETED(H) && air_contents && air_contents.return_pressure() >= 1000) if(!QDELETED(H) && air_contents && air_contents.return_pressure() >= 1000)
for(var/obj/item/W in H) for(var/obj/item/W in H)
H.dropItemToGround(W) H.dropItemToGround(W)
@@ -159,12 +168,10 @@
H.spawn_gibs() H.spawn_gibs()
H.spill_organs() H.spill_organs()
H.spread_bodyparts() H.spread_bodyparts()
return MANUAL_SUICIDE
return (BRUTELOSS) else
to_chat(user, "<span class='warning'>There isn't enough pressure in [src] to commit suicide with...</span>")
/obj/item/tank/attack_ghost(mob/dead/observer/O) return SHAME
. = ..()
atmosanalyzer_scan(air_contents, O, src, FALSE)
/obj/item/tank/attackby(obj/item/W, mob/user, params) /obj/item/tank/attackby(obj/item/W, mob/user, params)
add_fingerprint(user) add_fingerprint(user)
@@ -182,27 +189,30 @@
ui = new(user, src, "Tank", name) ui = new(user, src, "Tank", name)
ui.open() 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) /obj/item/tank/ui_data(mob/user)
var/list/data = list() . = list(
data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0) "tankPressure" = round(air_contents.return_pressure()),
data["releasePressure"] = round(distribute_pressure ? distribute_pressure : 0) "releasePressure" = round(distribute_pressure)
data["defaultReleasePressure"] = round(TANK_DEFAULT_RELEASE_PRESSURE) )
data["minReleasePressure"] = round(TANK_MIN_RELEASE_PRESSURE)
data["maxReleasePressure"] = round(TANK_MAX_RELEASE_PRESSURE)
var/mob/living/carbon/C = user var/mob/living/carbon/C = user
if(!istype(C)) if(!istype(C))
C = loc.loc C = loc.loc
if(!istype(C)) if(istype(C) && C.internal == src)
return data .["connected"] = TRUE
if(C.internal == src)
data["connected"] = TRUE
return data
/obj/item/tank/ui_act(action, params) /obj/item/tank/ui_act(action, params)
if(..()) . = ..()
if(.)
return return
switch(action) switch(action)
if("pressure") if("pressure")
@@ -228,6 +238,9 @@
/obj/item/tank/return_air() /obj/item/tank/return_air()
return air_contents return air_contents
// /obj/item/tank/return_analyzable_air()
// return air_contents
/obj/item/tank/assume_air(datum/gas_mixture/giver) /obj/item/tank/assume_air(datum/gas_mixture/giver)
air_contents.merge(giver) air_contents.merge(giver)
@@ -239,10 +252,9 @@
return null return null
var/tank_pressure = air_contents.return_pressure() var/tank_pressure = air_contents.return_pressure()
if(tank_pressure < distribute_pressure) var/actual_distribute_pressure = clamp(tank_pressure, 0, distribute_pressure)
distribute_pressure = tank_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) return remove_air(moles_needed)
@@ -266,7 +278,7 @@
log_game("Explosive tank rupture! Last key to touch the tank was [src.fingerprintslast].") 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 //Give the gas a chance to build up more pressure through reacting
air_contents.react(src) air_contents.react(src)
air_contents.react(src) // air_contents.react(src)
//Citadel Edit: removing extra react for "balance" //Citadel Edit: removing extra react for "balance"
pressure = air_contents.return_pressure() pressure = air_contents.return_pressure()
var/range = (pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE var/range = (pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE
@@ -285,7 +297,7 @@
if(!T) if(!T)
return return
T.assume_air(air_contents) 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) qdel(src)
else else
integrity-- integrity--

View File

@@ -4,6 +4,11 @@ SAFES
FLOOR SAFES FLOOR SAFES
*/ */
/// Chance for a sound clue
#define SOUND_CHANCE 10
/// Explosion number threshold for opening safe
#define BROKEN_THRESHOLD 3
//SAFES //SAFES
/obj/structure/safe /obj/structure/safe
name = "safe" name = "safe"
@@ -14,31 +19,36 @@ FLOOR SAFES
density = TRUE density = TRUE
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT
var/open = FALSE //is the safe open? /// The maximum combined w_class of stuff in the safe
var/tumbler_1_pos //the tumbler position- from 0 to 72 var/maxspace = 24
var/tumbler_1_open //the tumbler position to open at- 0 to 72 /// The amount of tumblers that will be generated
var/tumbler_2_pos var/number_of_tumblers = 2
var/tumbler_2_open /// Whether the safe is open or not
var/dial = 0 //where is the dial pointing? var/open = FALSE
var/space = 0 //the combined w_class of everything in the safe /// Whether the safe is locked or not
var/maxspace = 24 //the maximum combined w_class of stuff in the safe var/locked = TRUE
var/explosion_count = 0 //Tough, but breakable /// The position the dial is pointing to
var/dial = 0
/obj/structure/safe/New() /// The list of tumbler dial positions that need to be hit
..() var/list/tumblers = list()
tumbler_1_pos = rand(0, 71) /// The index in the tumblers list of the tumbler dial position that needs to be hit
tumbler_1_open = rand(0, 71) var/current_tumbler_index = 1
/// The combined w_class of everything in the safe
tumbler_2_pos = rand(0, 71) var/space = 0
tumbler_2_open = rand(0, 71) /// Tough, but breakable if explosion counts reaches set value
var/explosion_count = 0
/obj/structure/safe/Initialize(mapload) /obj/structure/safe/Initialize(mapload)
. = ..() . = ..()
// Combination generation
for(var/i in 1 to number_of_tumblers)
tumblers.Add(rand(0, 99))
if(!mapload) if(!mapload)
return return
// Put as many items on our turf inside as possible
for(var/obj/item/I in loc) for(var/obj/item/I in loc)
if(space >= maxspace) if(space >= maxspace)
return return
@@ -46,141 +56,36 @@ FLOOR SAFES
space += I.w_class space += I.w_class
I.forceMove(src) 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() /obj/structure/safe/update_icon_state()
if(open) if(open)
icon_state = "[initial(icon_state)]-open" icon_state = "[initial(icon_state)]-open"
else else
icon_state = initial(icon_state) 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) /obj/structure/safe/attackby(obj/item/I, mob/user, params)
if(open) if(open)
. = 1 //no afterattack . = TRUE //no afterattack
if(I.w_class + space <= maxspace) if(I.w_class + space <= maxspace)
space += I.w_class space += I.w_class
if(!user.transferItemToLoc(I, src)) 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>") to_chat(user, "<span class='warning'>\The [I] is stuck to your hand, you cannot put it in the safe!</span>")
return return
to_chat(user, "<span class='notice'>You put [I] in [src].</span>") 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 return
else 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 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) /obj/structure/safe/blob_act(obj/structure/blob/B)
return return
/obj/structure/safe/ex_act(severity, target) /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++ explosion_count++
switch(explosion_count) switch(explosion_count)
if(1) if(1)
@@ -190,6 +95,144 @@ FLOOR SAFES
if(3) if(3)
desc = initial(desc) + "\nThe lock seems to be broken." 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 //FLOOR SAFES
/obj/structure/safe/floor /obj/structure/safe/floor
@@ -199,13 +242,11 @@ FLOOR SAFES
level = 1 //underfloor level = 1 //underfloor
layer = LOW_OBJ_LAYER layer = LOW_OBJ_LAYER
/obj/structure/safe/floor/Initialize(mapload) /obj/structure/safe/floor/Initialize(mapload)
. = ..() . = ..()
if(mapload) if(mapload)
var/turf/T = loc var/turf/T = loc
hide(T.intact) hide(T.intact)
#undef SOUND_CHANCE
/obj/structure/safe/floor/hide(var/intact) #undef BROKEN_THRESHOLD
invisibility = intact ? INVISIBILITY_MAXIMUM : 0

View File

@@ -1547,22 +1547,17 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
msg += "</UL></BODY></HTML>" msg += "</UL></BODY></HTML>"
src << browse(msg.Join(), "window=Player_playtime_check") 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)) if(!check_rights(R_ADMIN))
return return
if(!C) if(!client_to_check)
to_chat(usr, "<span class='danger'>ERROR: Client not found.</span>") to_chat(usr, "<span class='danger'>ERROR: Client not found.</span>", confidential = TRUE)
return return
if(!CONFIG_GET(flag/use_exp_tracking)) 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 return
var/list/body = list() new /datum/job_report_menu(client_to_check, usr)
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")
/datum/admins/proc/toggle_exempt_status(client/C) /datum/admins/proc/toggle_exempt_status(client/C)
if(!check_rights(R_ADMIN)) if(!check_rights(R_ADMIN))

View File

@@ -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, "Total time (new gas mixture): [total_time]ms")
to_chat(src, "Operations per second: [100000 / (total_time/1000)]") 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

View File

@@ -55,26 +55,7 @@ Passive gate is similar to the regular pump except:
var/datum/gas_mixture/air1 = airs[1] var/datum/gas_mixture/air1 = airs[1]
var/datum/gas_mixture/air2 = airs[2] var/datum/gas_mixture/air2 = airs[2]
if(air1.release_gas_to(air2, target_pressure))
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)
update_parents() update_parents()

View File

@@ -2,15 +2,18 @@
/obj/machinery/atmospherics/components/unary/tank /obj/machinery/atmospherics/components/unary/tank
icon = 'icons/obj/atmospherics/pipes/pressure_tank.dmi' icon = 'icons/obj/atmospherics/pipes/pressure_tank.dmi'
icon_state = "generic" icon_state = "generic"
name = "pressure tank" name = "pressure tank"
desc = "A large vessel containing pressurized gas." desc = "A large vessel containing pressurized gas."
max_integrity = 800 max_integrity = 800
density = TRUE density = TRUE
layer = ABOVE_WINDOW_LAYER layer = ABOVE_WINDOW_LAYER
plane = GAME_PLANE
pipe_flags = PIPING_ONE_PER_TURF pipe_flags = PIPING_ONE_PER_TURF
var/volume = 10000 //in liters 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() /obj/machinery/atmospherics/components/unary/tank/New()
..() ..()
@@ -20,6 +23,7 @@
if(gas_type) if(gas_type)
air_contents.set_moles(AIR_CONTENTS) air_contents.set_moles(AIR_CONTENTS)
name = "[name] ([GLOB.meta_gas_names[gas_type]])" name = "[name] ([GLOB.meta_gas_names[gas_type]])"
setPipingLayer(piping_layer)
/obj/machinery/atmospherics/components/unary/tank/air /obj/machinery/atmospherics/components/unary/tank/air
icon_state = "grey" icon_state = "grey"
@@ -38,15 +42,71 @@
icon_state = "orange" icon_state = "orange"
gas_type = /datum/gas/plasma 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 /obj/machinery/atmospherics/components/unary/tank/nitrogen
icon_state = "red" icon_state = "red"
gas_type = /datum/gas/nitrogen 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" icon_state = "red_white"
gas_type = /datum/gas/nitrous_oxide 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

View File

@@ -5,22 +5,28 @@
desc = "A canister for the storage of gas." desc = "A canister for the storage of gas."
icon_state = "yellow" icon_state = "yellow"
density = TRUE density = TRUE
var/valve_open = FALSE
var/obj/machinery/atmospherics/components/binary/passive_gate/pump
var/release_log = ""
volume = 1000 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) armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 100, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 50)
max_integrity = 250 max_integrity = 250
integrity_failure = 0.4 integrity_failure = 0.4
pressure_resistance = 7 * ONE_ATMOSPHERE 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/temperature_resistance = 1000 + T0C
var/starter_temp var/starter_temp
// Prototype vars // Prototype vars
@@ -32,6 +38,8 @@
var/maximum_timer_set = 300 var/maximum_timer_set = 300
var/timing = FALSE var/timing = FALSE
var/restricted = FALSE var/restricted = FALSE
///Set the tier of the canister and overlay used
// var/mode = CANISTER_TIER_1
req_access = list() req_access = list()
var/update = 0 var/update = 0
@@ -195,27 +203,19 @@
filled = 1 filled = 1
release_pressure = ONE_ATMOSPHERE*2 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) if(existing_mixture)
air_contents.copy_from(existing_mixture) air_contents.copy_from(existing_mixture)
else else
create_gas() create_gas()
pump = new(src, FALSE)
pump.on = TRUE
pump.stat = 0
SSair.add_to_rebuild_queue(pump)
update_icon() update_icon()
/obj/machinery/portable_atmospherics/canister/Destroy()
qdel(pump)
pump = null
return ..()
/obj/machinery/portable_atmospherics/canister/proc/create_gas() /obj/machinery/portable_atmospherics/canister/proc/create_gas()
if(gas_type) if(gas_type)
// air_contents.add_gas(gas_type)
if(starter_temp) if(starter_temp)
air_contents.set_temperature(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())) 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) if(user.a_intent == INTENT_HARM)
return FALSE return FALSE
if(stat & BROKEN)
if(!I.tool_start_check(user, amount=0)) if(!I.tool_start_check(user, amount=0))
return TRUE return TRUE
to_chat(user, "<span class='notice'>You begin cutting [src] apart...</span>") var/pressure = air_contents.return_pressure()
if(I.use_tool(src, user, 30, volume=50)) 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) deconstruct(TRUE)
else
to_chat(user, "<span class='notice'>You cannot slice [src] apart when it isn't broken.</span>")
return TRUE return TRUE
@@ -317,18 +320,19 @@
valve_open = !valve_open valve_open = !valve_open
timing = FALSE timing = FALSE
if(!valve_open) if(!valve_open)
pump.airs[1] = null
pump.airs[2] = null
return
var/turf/T = get_turf(src) var/turf/T = get_turf(src)
pump.airs[1] = air_contents var/datum/gas_mixture/target_air = holding ? holding.air_contents : T.return_air()
pump.airs[2] = holding ? holding.air_contents : T.return_air()
pump.target_pressure = release_pressure
pump.process_atmos() // Pump gas. if(air_contents.release_gas_to(target_air, release_pressure) && !holding)
if(!holding) air_update_turf()
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() update_icon()
/obj/machinery/portable_atmospherics/canister/ui_state(mob/user) /obj/machinery/portable_atmospherics/canister/ui_state(mob/user)
@@ -340,35 +344,48 @@
ui = new(user, src, "Canister", name) ui = new(user, src, "Canister", name)
ui.open() 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() /obj/machinery/portable_atmospherics/canister/ui_data()
var/data = list() . = list(
data["portConnected"] = connected_port ? 1 : 0 "portConnected" = !!connected_port,
data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0) "tankPressure" = round(air_contents.return_pressure()),
data["releasePressure"] = round(release_pressure ? release_pressure : 0) "releasePressure" = round(release_pressure),
data["defaultReleasePressure"] = round(CAN_DEFAULT_RELEASE_PRESSURE) "valveOpen" = !!valve_open,
data["minReleasePressure"] = round(can_min_release_pressure) "isPrototype" = !!prototype,
data["maxReleasePressure"] = round(can_max_release_pressure) "hasHoldingTank" = !!holding
data["valveOpen"] = valve_open ? 1 : 0 )
data["isPrototype"] = prototype ? 1 : 0
if (prototype) if (prototype)
data["restricted"] = restricted . += list(
data["timing"] = timing "restricted" = restricted,
data["time_left"] = get_time_left() "timing" = timing,
data["timer_set"] = timer_set "time_left" = get_time_left(),
data["timer_is_not_default"] = timer_set != default_timer_set "timer_set" = timer_set,
data["timer_is_not_min"] = timer_set != minimum_timer_set "timer_is_not_default" = timer_set != default_timer_set,
data["timer_is_not_max"] = timer_set != maximum_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) if (holding)
data["holdingTank"] = list() . += list(
data["holdingTank"]["name"] = holding.name "holdingTank" = list(
data["holdingTank"]["tankPressure"] = round(holding.air_contents.return_pressure()) "name" = holding.name,
return data "tankPressure" = round(holding.air_contents.return_pressure())
)
)
/obj/machinery/portable_atmospherics/canister/ui_act(action, params) /obj/machinery/portable_atmospherics/canister/ui_act(action, params)
if(..()) . = ..()
if(.)
return return
switch(action) switch(action)
if("relabel") if("relabel")
@@ -377,6 +394,7 @@
var/newtype = label2types[label] var/newtype = label2types[label]
if(newtype) if(newtype)
var/obj/machinery/portable_atmospherics/canister/replacement = 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) name = initial(replacement.name)
desc = initial(replacement.desc) desc = initial(replacement.desc)
icon_state = initial(replacement.icon_state) icon_state = initial(replacement.icon_state)
@@ -458,9 +476,8 @@
if("eject") if("eject")
if(holding) if(holding)
if(valve_open) 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>.") 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><br>", INVESTIGATE_ATMOS) investigate_log("[key_name(usr)] removed the [holding], leaving the valve open and transferring into the <span class='boldannounce'>air</span>.", INVESTIGATE_ATMOS)
holding.forceMove(get_turf(src)) replace_tank(usr, FALSE)
holding = null
. = TRUE . = TRUE
update_icon() update_icon()

View File

@@ -190,11 +190,7 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
to_chat(usr, "<span class='notice'>Sorry, tracking is currently disabled.</span>") to_chat(usr, "<span class='notice'>Sorry, tracking is currently disabled.</span>")
return return
var/list/body = list() new /datum/job_report_menu(src, usr)
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")
/client/proc/ignore_key(client) /client/proc/ignore_key(client)
var/client/C = client var/client/C = client

View File

@@ -156,11 +156,7 @@
/obj/machinery/processor/slime /obj/machinery/processor/slime
name = "slime processor" name = "slime processor"
desc = "An industrial grinder with a sticker saying appropriated for science department. Keep hands clear of intake area while operating." desc = "An industrial grinder with a sticker saying appropriated for science department. Keep hands clear of intake area while operating."
circuit = /obj/item/circuitboard/machine/processor/slime
/obj/machinery/processor/slime/Initialize()
. = ..()
var/obj/item/circuitboard/machine/B = new /obj/item/circuitboard/machine/processor/slime(null)
B.apply_default_parts(src)
/obj/machinery/processor/slime/adjust_item_drop_location(atom/movable/AM) /obj/machinery/processor/slime/adjust_item_drop_location(atom/movable/AM)
var/static/list/slimecores = subtypesof(/obj/item/slime_extract) var/static/list/slimecores = subtypesof(/obj/item/slime_extract)

View 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

View File

@@ -8,12 +8,12 @@ GLOBAL_LIST(labor_sheet_values)
icon = 'icons/obj/machines/mining_machines.dmi' icon = 'icons/obj/machines/mining_machines.dmi'
icon_state = "console" icon_state = "console"
density = FALSE density = FALSE
/// Connected stacking machine
var/obj/machinery/mineral/stacking_machine/laborstacker/stacking_machine = null var/obj/machinery/mineral/stacking_machine/laborstacker/stacking_machine = null
/// Direction of the stacking machine
var/machinedir = SOUTH var/machinedir = SOUTH
var/obj/machinery/door/airlock/release_door /// Needed to send messages to sec radio
var/door_tag = "prisonshuttle" var/obj/item/radio/Radio
var/obj/item/radio/Radio //needed to send messages to sec radio
/obj/machinery/mineral/labor_claim_console/Initialize() /obj/machinery/mineral/labor_claim_console/Initialize()
. = ..() . = ..()
@@ -39,15 +39,23 @@ GLOBAL_LIST(labor_sheet_values)
ui = new(user, src, "LaborClaimConsole", name) ui = new(user, src, "LaborClaimConsole", name)
ui.open() 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) /obj/machinery/mineral/labor_claim_console/ui_data(mob/user)
var/list/data = list() var/list/data = list()
var/can_go_home = FALSE var/can_go_home = FALSE
data["emagged"] = (obj_flags & EMAGGED) ? 1 : 0 data["emagged"] = FALSE
if(obj_flags & EMAGGED) if(obj_flags & EMAGGED)
data["emagged"] = TRUE
can_go_home = TRUE can_go_home = TRUE
var/obj/item/card/id/I
var/obj/item/card/id/I = user.get_idcard(TRUE) if(isliving(usr))
var/mob/living/L = usr
I = L.get_idcard(TRUE)
if(istype(I, /obj/item/card/id/prisoner)) if(istype(I, /obj/item/card/id/prisoner))
var/obj/item/card/id/prisoner/P = I var/obj/item/card/id/prisoner/P = I
data["id_points"] = P.points data["id_points"] = P.points
@@ -63,43 +71,46 @@ GLOBAL_LIST(labor_sheet_values)
if(stacking_machine) if(stacking_machine)
data["unclaimed_points"] = stacking_machine.points data["unclaimed_points"] = stacking_machine.points
data["ores"] = GLOB.labor_sheet_values
data["can_go_home"] = can_go_home data["can_go_home"] = can_go_home
return data return data
/obj/machinery/mineral/labor_claim_console/ui_act(action, params) /obj/machinery/mineral/labor_claim_console/ui_act(action, params)
if(..()) . = ..()
if(.)
return return
var/mob/M = usr
switch(action) switch(action)
if("claim_points") if("claim_points")
var/mob/M = usr var/obj/item/card/id/I
var/obj/item/card/id/I = M.get_idcard(TRUE) if(isliving(M))
var/mob/living/L = M
I = L.get_idcard(TRUE)
if(istype(I, /obj/item/card/id/prisoner)) if(istype(I, /obj/item/card/id/prisoner))
var/obj/item/card/id/prisoner/P = I var/obj/item/card/id/prisoner/P = I
P.points += stacking_machine.points P.points += stacking_machine.points
stacking_machine.points = 0 stacking_machine.points = 0
to_chat(usr, "<span class='notice'>Points transferred.</span>") to_chat(M, "<span class='notice'>Points transferred.</span>")
. = TRUE return TRUE
else 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("move_shuttle")
if(!alone_in_area(get_area(src), usr)) if(!alone_in_area(get_area(src), M))
to_chat(usr, "<span class='alert'>Prisoners are only allowed to be released while alone.</span>") to_chat(M, "<span class='alert'>Prisoners are only allowed to be released while alone.</span>")
else return
switch(SSshuttle.moveShuttle("laborcamp", "laborcamp_home", TRUE)) switch(SSshuttle.moveShuttle("laborcamp", "laborcamp_home", TRUE))
if(1) if(1)
to_chat(usr, "<span class='alert'>Shuttle not found.</span>") to_chat(M, "<span class='alert'>Shuttle not found.</span>")
if(2) if(2)
to_chat(usr, "<span class='alert'>Shuttle already at station.</span>") to_chat(M, "<span class='alert'>Shuttle already at station.</span>")
if(3) if(3)
to_chat(usr, "<span class='alert'>No permission to dock could be granted.</span>") to_chat(M, "<span class='alert'>No permission to dock could be granted.</span>")
else else
if(!(obj_flags & EMAGGED)) if(!(obj_flags & EMAGGED))
Radio.set_frequency(FREQ_SECURITY) 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) 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>") to_chat(M, "<span class='notice'>Shuttle received message and will be sent shortly.</span>")
. = TRUE return TRUE
/obj/machinery/mineral/labor_claim_console/proc/locate_stacking_machine() /obj/machinery/mineral/labor_claim_console/proc/locate_stacking_machine()
stacking_machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir)) stacking_machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir))
@@ -110,8 +121,7 @@ GLOBAL_LIST(labor_sheet_values)
/obj/machinery/mineral/labor_claim_console/emag_act(mob/user) /obj/machinery/mineral/labor_claim_console/emag_act(mob/user)
. = ..() . = ..()
if((obj_flags & EMAGGED)) if(!(obj_flags & EMAGGED))
return
obj_flags |= EMAGGED obj_flags |= EMAGGED
to_chat(user, "<span class='warning'>PZZTTPFFFT</span>") to_chat(user, "<span class='warning'>PZZTTPFFFT</span>")
return TRUE return TRUE
@@ -127,7 +137,7 @@ GLOBAL_LIST(labor_sheet_values)
..() ..()
/obj/machinery/mineral/stacking_machine/laborstacker/attackby(obj/item/I, mob/living/user) /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 var/obj/item/stack/sheet/inp = I
points += inp.point_value * inp.amount points += inp.point_value * inp.amount
return ..() return ..()
@@ -141,7 +151,10 @@ GLOBAL_LIST(labor_sheet_values)
icon_state = "console" icon_state = "console"
density = FALSE 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) user.examinate(src)
/obj/machinery/mineral/labor_points_checker/attackby(obj/item/I, mob/user, params) /obj/machinery/mineral/labor_points_checker/attackby(obj/item/I, mob/user, params)

View File

@@ -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." 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 = 'icons/obj/machines/research.dmi'
icon_state = "server" 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/datum/techweb/stored_research
var/heat_health = 100 var/heat_health = 100
//Code for point mining here. //Code for point mining here.
@@ -15,14 +18,11 @@
var/temp_tolerance_low = 0 var/temp_tolerance_low = 0
var/temp_tolerance_high = T20C 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. 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() /obj/machinery/rnd/server/Initialize()
. = ..() . = ..()
SSresearch.servers |= src SSresearch.servers |= src
stored_research = SSresearch.science_tech 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() /obj/machinery/rnd/server/Destroy()
SSresearch.servers -= src SSresearch.servers -= src

View File

@@ -87,7 +87,7 @@
if(!H.myseed) if(!H.myseed)
return return
if(!H.harvest)// So it's bit harder. 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 return
if(plants[H.myseed.type]) if(plants[H.myseed.type])
to_chat(user, "<span class='notice'>Plant data already present in local storage.</span>") to_chat(user, "<span class='notice'>Plant data already present in local storage.</span>")
@@ -101,10 +101,10 @@
if(isanimal(target)) if(isanimal(target))
var/mob/living/simple_animal/A = target var/mob/living/simple_animal/A = target
if(!A.healable)//simple approximation of being animal not a robot or similar 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 return
if(animals[target.type]) 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 return
animals[target.type] = 1 animals[target.type] = 1
to_chat(user, "<span class='notice'>Animal data added to local storage.</span>") to_chat(user, "<span class='notice'>Animal data added to local storage.</span>")
@@ -173,7 +173,6 @@
qdel(filler) qdel(filler)
. = ..() . = ..()
/obj/machinery/dna_vault/ui_interact(mob/user, datum/tgui/ui) /obj/machinery/dna_vault/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui) ui = SStgui.try_update_ui(user, src, ui)
if(!ui) if(!ui)
@@ -204,15 +203,17 @@
data["choiceB"] = "" data["choiceB"] = ""
if(user && completed) if(user && completed)
var/list/L = power_lottery[user] var/list/L = power_lottery[user]
if(L && L.len) if(L?.len)
data["used"] = FALSE data["used"] = FALSE
data["choiceA"] = L[1] data["choiceA"] = L[1]
data["choiceB"] = L[2] data["choiceB"] = L[2]
return data return data
/obj/machinery/dna_vault/ui_act(action, params) /obj/machinery/dna_vault/ui_act(action, params)
if(..()) . = ..()
if(.)
return return
switch(action) switch(action)
if("gene") if("gene")
upgrade(usr,params["choice"]) upgrade(usr,params["choice"])
@@ -244,8 +245,6 @@
else else
return ..() return ..()
/obj/machinery/dna_vault/proc/upgrade(mob/living/carbon/human/H,upgrade_type) /obj/machinery/dna_vault/proc/upgrade(mob/living/carbon/human/H,upgrade_type)
if(!(upgrade_type in power_lottery[H])) if(!(upgrade_type in power_lottery[H]))
return return

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 B

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -2278,6 +2278,7 @@
#include "code\modules\integrated_electronics\subtypes\weaponized.dm" #include "code\modules\integrated_electronics\subtypes\weaponized.dm"
#include "code\modules\jobs\access.dm" #include "code\modules\jobs\access.dm"
#include "code\modules\jobs\job_exp.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\jobs.dm"
#include "code\modules\jobs\job_types\_job.dm" #include "code\modules\jobs\job_types\_job.dm"
#include "code\modules\jobs\job_types\ai.dm" #include "code\modules\jobs\job_types\ai.dm"