icons should exist
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user