diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm index 5a69f26460..a1b7a74384 100644 --- a/code/_onclick/hud/_defines.dm +++ b/code/_onclick/hud/_defines.dm @@ -117,8 +117,8 @@ #define ui_borg_camera "CENTER+3:21,SOUTH:5" #define ui_borg_alerts "CENTER+4:21,SOUTH:5" #define ui_borg_language_menu "CENTER+4:21,SOUTH+1:5" -#define ui_borg_sensor "CENTER-3:15, SOUTH:5" //LEGACY -#define ui_borg_thrusters "CENTER-5:15, SOUTH:5" //LEGACY +#define ui_borg_sensor "CENTER-6:16, SOUTH:5" //LEGACY +#define ui_borg_thrusters "CENTER-5:16, SOUTH:5" //LEGACY //Aliens #define ui_alien_health "EAST,CENTER-1:15" diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 66aa12ac1a..92620f597b 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -676,7 +676,7 @@ SUBSYSTEM_DEF(shuttle) if(!preview_shuttle) load_template(loading_template) - preview_shuttle.linkup(loading_template, destination_port) + // preview_shuttle.linkup(loading_template, destination_port) preview_template = loading_template // get the existing shuttle information, if any diff --git a/code/datums/shuttles.dm b/code/datums/shuttles.dm index 17116b922b..f8fe430961 100644 --- a/code/datums/shuttles.dm +++ b/code/datums/shuttles.dm @@ -454,12 +454,12 @@ return SSshuttle.shuttle_purchase_requirements_met["emagged"] -/datum/map_template/shuttle/emergency/cruise - suffix = "cruise" - name = "The NTSS Independence" - description = "Ordinarily reserved for special functions and events, the Cruise Shuttle Independence can bring a summery cheer to your next station evacuation for a 'modest' fee!" - admin_notes = "This motherfucker is BIG. You might need to force dock it." - credit_cost = 8000 +// /datum/map_template/shuttle/emergency/cruise +// suffix = "cruise" +// name = "The NTSS Independence" +// description = "Ordinarily reserved for special functions and events, the Cruise Shuttle Independence can bring a summery cheer to your next station evacuation for a 'modest' fee!" +// admin_notes = "This motherfucker is BIG. You might need to force dock it." +// credit_cost = 8000 /datum/map_template/shuttle/emergency/monkey suffix = "nature" diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 03a5a17493..74d50117ac 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -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 diff --git a/code/game/machinery/computer/pod.dm b/code/game/machinery/computer/pod.dm index ca64d538b9..2eb1aab925 100644 --- a/code/game/machinery/computer/pod.dm +++ b/code/game/machinery/computer/pod.dm @@ -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, "Access denied.") + if(.) + return + if(!allowed(usr)) + to_chat(usr, "Access denied.") return - var/dat = "" - if(connected) - var/d2 - if(timing) //door controls do not need timers. - d2 = "Stop Time Launch" - else - d2 = "Initiate Time Launch" - dat += "
\nTimer System: [d2]\nTime Left: [DisplayTimeText(time)] - - + +" - 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 += "[t] " - dat += "
\nPower Level: [temp]
\nFiring Sequence
\nTest Fire Driver
\nToggle Outer Door
" - else - dat += "
\nToggle Outer Door
" - dat += "

Close" - 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 diff --git a/code/game/machinery/mass_driver.dm b/code/game/machinery/mass_driver.dm index b39c6d350f..d42c955115 100644 --- a/code/game/machinery/mass_driver.dm +++ b/code/game/machinery/mass_driver.dm @@ -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("[src] lets out a screech, it doesn't seem to be able to handle the load.") @@ -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) diff --git a/code/game/mecha/mecha_control_console.dm b/code/game/mecha/mecha_control_console.dm index 0e47872221..29298247cd 100644 --- a/code/game/mecha/mecha_control_console.dm +++ b/code/game/mecha/mecha_control_console.dm @@ -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, "Message sent.") . = 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 @@ Active Equipment: [chassis.selected || "None"]"} if(istype(chassis, /obj/mecha/working/ripley)) var/obj/mecha/working/ripley/RM = chassis - answer += "
Used Cargo Space: [round((RM.cargo.len / RM.cargo_capacity * 100), 0.01)]%" + answer += "
Used Cargo Space: [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 diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 503a183064..b79d1d3cbc 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -439,6 +439,8 @@ if(zero_amount()) return return split_stack(user, 1) + else + . = ..() /obj/item/stack/AltClick(mob/living/user) . = ..() diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm index d57f0cc51f..5bd1f67bee 100644 --- a/code/game/objects/items/tanks/tanks.dm +++ b/code/game/objects/items/tanks/tanks.dm @@ -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) . += "If you want any more information you'll need to get closer." 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("[user] is putting [src]'s valve to [user.p_their()] lips! It looks like [user.p_theyre()] trying to commit suicide!") - 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, "There isn't enough pressure in [src] to commit suicide with...") + 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-- diff --git a/code/game/objects/structures/safe.dm b/code/game/objects/structures/safe.dm index e6f77c85a1..55eb100b21 100644 --- a/code/game/objects/structures/safe.dm +++ b/code/game/objects/structures/safe.dm @@ -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, "You hear a [pick("tonk", "krunk", "plunk")] from [src].") - if(tumbler_2_pos == tumbler_2_open) - to_chat(user, "You hear a [pick("tink", "krink", "plink")] from [src].") - if(tumbler_1_pos == tumbler_1_open && tumbler_2_pos == tumbler_2_open) - if(user) - visible_message("[pick("Spring", "Sprang", "Sproing", "Clunk", "Krunk")]!") - 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 = "
" - dat += "[open ? "Close" : "Open"] [src] | - [dial] +" - if(open) - dat += "" - for(var/i = contents.len, i>=1, i--) - var/obj/item/P = contents[i] - dat += "" - dat += "
[P.name]
" - user << browse("[name][dat]", "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, "You [open ? "close" : "open"] [src].") - open = !open - update_icon() - updateUsrDialog() - return - else - to_chat(user, "You can't [open ? "close" : "open"] [src], the lock is engaged!") - 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, "You hear a [pick("clack", "scrape", "clank")] from [src].") - 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, "You hear a [pick("click", "chink", "clink")] from [src].") - 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, "You hear a [pick("clack", "scrape", "clank")] from [src].") - 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, "You hear a [pick("click", "chink", "clink")] from [src].") - 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, "\The [I] is stuck to your hand, you cannot put it in the safe!") return to_chat(user, "You put [I] in [src].") - updateUsrDialog() + else + to_chat(user, "[I] won't fit in [src].") + else + if(istype(I, /obj/item/clothing/neck/stethoscope)) + attack_hand(user) return else - to_chat(user, "[I] won't fit in [src].") + to_chat(user, "You can't put [I] into the safe while it is closed!") return - else if(istype(I, /obj/item/clothing/neck/stethoscope)) - to_chat(user, "Hold [I] in one of your hands while you manipulate the dial!") - 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, "You cannot open [src], as its lock is engaged!") + return + to_chat(user, "You [open ? "close" : "open"] [src].") + open = !open + update_icon() + return TRUE + if("turnright") + if(open) + return + if(broken) + to_chat(user, "The dial will not turn, as the mechanism is destroyed!") + 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, "The dial will not turn, as the mechanism is destroyed!") + 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("[pick("Spring", "Sprang", "Sproing", "Clunk", "Krunk")]!") + 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, "The sounds from [src] are too fast and blend together.") + if(total_ticks == 1 || prob(SOUND_CHANCE)) + to_chat(user, "You hear a [pick(sounds)] from [src].") //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 diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 84702898ec..e5390bc457 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -1547,22 +1547,17 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits msg += "" src << browse(msg.Join(), "window=Player_playtime_check") -/datum/admins/proc/cmd_show_exp_panel(client/C) +/datum/admins/proc/cmd_show_exp_panel(client/client_to_check) if(!check_rights(R_ADMIN)) return - if(!C) - to_chat(usr, "ERROR: Client not found.") + if(!client_to_check) + to_chat(usr, "ERROR: Client not found.", confidential = TRUE) return if(!CONFIG_GET(flag/use_exp_tracking)) - to_chat(usr, "Tracking is disabled in the server configuration file.") + to_chat(usr, "Tracking is disabled in the server configuration file.", confidential = TRUE) return - var/list/body = list() - body += "Playtime for [C.key]
Playtime:" - body += C.get_exp_report() - body += "Toggle Exempt status" - body += "" - usr << browse(body.Join(), "window=playerplaytime[C.ckey];size=550x615") + new /datum/job_report_menu(client_to_check, usr) /datum/admins/proc/toggle_exempt_status(client/C) if(!check_rights(R_ADMIN)) diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm index 4c71815c9c..0e1f4ae065 100644 --- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm +++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm @@ -359,3 +359,27 @@ get_true_breath_pressure(pp) --> gas_pp = pp/breath_pp*total_moles() to_chat(src, "Total time (new gas mixture): [total_time]ms") to_chat(src, "Operations per second: [100000 / (total_time/1000)]") */ + +/// Releases gas from src to output air. This means that it can not transfer air to gas mixture with higher pressure. +/datum/gas_mixture/proc/release_gas_to(datum/gas_mixture/output_air, target_pressure) + var/output_starting_pressure = output_air.return_pressure() + var/input_starting_pressure = return_pressure() + + if(output_starting_pressure >= min(target_pressure,input_starting_pressure-10)) + //No need to pump gas if target is already reached or input pressure is too low + //Need at least 10 KPa difference to overcome friction in the mechanism + return FALSE + + //Calculate necessary moles to transfer using PV = nRT + if((total_moles() > 0) && (return_temperature()>0)) + var/pressure_delta = min(target_pressure - output_starting_pressure, (input_starting_pressure - output_starting_pressure)/2) + //Can not have a pressure delta that would cause output_pressure > input_pressure + + var/transfer_moles = pressure_delta*output_air.return_volume()/(return_temperature() * R_IDEAL_GAS_EQUATION) + + //Actually transfer the gas + var/datum/gas_mixture/removed = remove(transfer_moles) + output_air.merge(removed) + + return TRUE + return FALSE diff --git a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm index 00a085c31b..07573fb2b7 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm @@ -55,26 +55,7 @@ Passive gate is similar to the regular pump except: var/datum/gas_mixture/air1 = airs[1] var/datum/gas_mixture/air2 = airs[2] - - var/output_starting_pressure = air2.return_pressure() - var/input_starting_pressure = air1.return_pressure() - - if(output_starting_pressure >= min(target_pressure,input_starting_pressure-10)) - //No need to pump gas if target is already reached or input pressure is too low - //Need at least 10 KPa difference to overcome friction in the mechanism - return - - //Calculate necessary moles to transfer using PV = nRT - if((air1.total_moles() > 0) && (air1.return_temperature()>0)) - var/pressure_delta = min(target_pressure - output_starting_pressure, (input_starting_pressure - output_starting_pressure)/2) - //Can not have a pressure delta that would cause output_pressure > input_pressure - - var/transfer_moles = pressure_delta*air2.return_volume()/(air1.return_temperature() * R_IDEAL_GAS_EQUATION) - - //Actually transfer the gas - var/datum/gas_mixture/removed = air1.remove(transfer_moles) - air2.merge(removed) - + if(air1.release_gas_to(air2, target_pressure)) update_parents() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm b/code/modules/atmospherics/machinery/components/unary_devices/tank.dm index 2f3372462d..4817b9fd57 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/tank.dm @@ -2,15 +2,18 @@ /obj/machinery/atmospherics/components/unary/tank icon = 'icons/obj/atmospherics/pipes/pressure_tank.dmi' icon_state = "generic" + name = "pressure tank" desc = "A large vessel containing pressurized gas." + max_integrity = 800 density = TRUE layer = ABOVE_WINDOW_LAYER - plane = GAME_PLANE pipe_flags = PIPING_ONE_PER_TURF + var/volume = 10000 //in liters - var/gas_type = 0 + /// The typepath of the gas this tank should be filled with. + var/gas_type = null /obj/machinery/atmospherics/components/unary/tank/New() ..() @@ -20,6 +23,7 @@ if(gas_type) air_contents.set_moles(AIR_CONTENTS) name = "[name] ([GLOB.meta_gas_names[gas_type]])" + setPipingLayer(piping_layer) /obj/machinery/atmospherics/components/unary/tank/air icon_state = "grey" @@ -38,15 +42,71 @@ icon_state = "orange" gas_type = /datum/gas/plasma -/obj/machinery/atmospherics/components/unary/tank/oxygen - icon_state = "blue" - gas_type = /datum/gas/oxygen - /obj/machinery/atmospherics/components/unary/tank/nitrogen icon_state = "red" gas_type = /datum/gas/nitrogen -/obj/machinery/atmospherics/components/unary/tank/nitrous_oxide +/obj/machinery/atmospherics/components/unary/tank/oxygen + icon_state = "blue" + gas_type = /datum/gas/oxygen + +/obj/machinery/atmospherics/components/unary/tank/nitrous icon_state = "red_white" gas_type = /datum/gas/nitrous_oxide +/obj/machinery/atmospherics/components/unary/tank/bz + gas_type = /datum/gas/bz + +// /obj/machinery/atmospherics/components/unary/tank/freon +// icon_state = "blue" +// gas_type = /datum/gas/freon + +// /obj/machinery/atmospherics/components/unary/tank/halon +// icon_state = "blue" +// gas_type = /datum/gas/halon + +// /obj/machinery/atmospherics/components/unary/tank/healium +// icon_state = "red" +// gas_type = /datum/gas/healium + +// /obj/machinery/atmospherics/components/unary/tank/hydrogen +// icon_state = "grey" +// gas_type = /datum/gas/hydrogen + +/obj/machinery/atmospherics/components/unary/tank/hypernoblium + icon_state = "blue" + gas_type = /datum/gas/hypernoblium + +/obj/machinery/atmospherics/components/unary/tank/miasma + gas_type = /datum/gas/miasma + +/obj/machinery/atmospherics/components/unary/tank/nitryl + gas_type = /datum/gas/nitryl + +/obj/machinery/atmospherics/components/unary/tank/pluoxium + icon_state = "blue" + gas_type = /datum/gas/pluoxium + +// /obj/machinery/atmospherics/components/unary/tank/proto_nitrate +// icon_state = "red" +// gas_type = /datum/gas/proto_nitrate + +/obj/machinery/atmospherics/components/unary/tank/stimulum + icon_state = "red" + gas_type = /datum/gas/stimulum + +/obj/machinery/atmospherics/components/unary/tank/tritium + gas_type = /datum/gas/tritium + +/obj/machinery/atmospherics/components/unary/tank/water_vapor + icon_state = "grey" + gas_type = /datum/gas/water_vapor + +// /obj/machinery/atmospherics/components/unary/tank/zauker +// gas_type = /datum/gas/zauker + +// /obj/machinery/atmospherics/components/unary/tank/helium +// gas_type = /datum/gas/helium + +// /obj/machinery/atmospherics/components/unary/tank/antinoblium +// gas_type = /datum/gas/antinoblium diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm index 2690ad555b..03119d050c 100644 --- a/code/modules/atmospherics/machinery/portable/canister.dm +++ b/code/modules/atmospherics/machinery/portable/canister.dm @@ -5,22 +5,28 @@ desc = "A canister for the storage of gas." icon_state = "yellow" density = TRUE - - var/valve_open = FALSE - var/obj/machinery/atmospherics/components/binary/passive_gate/pump - var/release_log = "" - volume = 1000 - var/filled = 0.5 - var/gas_type - var/release_pressure = ONE_ATMOSPHERE - var/can_max_release_pressure = (ONE_ATMOSPHERE * 10) - var/can_min_release_pressure = (ONE_ATMOSPHERE / 10) - armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 100, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 50) max_integrity = 250 integrity_failure = 0.4 pressure_resistance = 7 * ONE_ATMOSPHERE + + var/valve_open = FALSE + var/release_log = "" + + var/filled = 0.5 + var/gas_type + + var/release_pressure = ONE_ATMOSPHERE + var/can_max_release_pressure = (ONE_ATMOSPHERE * 10) + var/can_min_release_pressure = (ONE_ATMOSPHERE / 10) + + // this removes atmos fusion cans** + ///Max amount of heat allowed inside of the canister before it starts to melt (different tiers have different limits) + // var/heat_limit = 5000 + ///Max amount of pressure allowed inside of the canister before it starts to break (different tiers have different limits) + // var/pressure_limit = 50000 + var/temperature_resistance = 1000 + T0C var/starter_temp // Prototype vars @@ -32,6 +38,8 @@ var/maximum_timer_set = 300 var/timing = FALSE var/restricted = FALSE + ///Set the tier of the canister and overlay used + // var/mode = CANISTER_TIER_1 req_access = list() var/update = 0 @@ -195,27 +203,19 @@ filled = 1 release_pressure = ONE_ATMOSPHERE*2 -/obj/machinery/portable_atmospherics/canister/New(loc, datum/gas_mixture/existing_mixture) - ..() +/obj/machinery/portable_atmospherics/canister/Initialize(mapload, datum/gas_mixture/existing_mixture) + . = ..() if(existing_mixture) air_contents.copy_from(existing_mixture) else create_gas() - pump = new(src, FALSE) - pump.on = TRUE - pump.stat = 0 - SSair.add_to_rebuild_queue(pump) update_icon() -/obj/machinery/portable_atmospherics/canister/Destroy() - qdel(pump) - pump = null - return ..() - /obj/machinery/portable_atmospherics/canister/proc/create_gas() if(gas_type) + // air_contents.add_gas(gas_type) if(starter_temp) air_contents.set_temperature(starter_temp) air_contents.set_moles(gas_type,(maximum_pressure * filled) * air_contents.return_volume() / (R_IDEAL_GAS_EQUATION * air_contents.return_temperature())) @@ -266,14 +266,17 @@ if(user.a_intent == INTENT_HARM) return FALSE - if(stat & BROKEN) - if(!I.tool_start_check(user, amount=0)) - return TRUE - to_chat(user, "You begin cutting [src] apart...") - if(I.use_tool(src, user, 30, volume=50)) - deconstruct(TRUE) - else - to_chat(user, "You cannot slice [src] apart when it isn't broken.") + if(!I.tool_start_check(user, amount=0)) + return TRUE + var/pressure = air_contents.return_pressure() + if(pressure > 300) + to_chat(user, "The pressure gauge on \the [src] indicates a high pressure inside... maybe you want to reconsider?") + message_admins("[src] deconstructed by [ADMIN_LOOKUPFLW(user)]") + log_game("[src] deconstructed by [key_name(user)]") + to_chat(user, "You begin cutting \the [src] apart...") + if(I.use_tool(src, user, 3 SECONDS, volume=50)) + to_chat(user, "You cut \the [src] apart.") + deconstruct(TRUE) return TRUE @@ -317,18 +320,19 @@ valve_open = !valve_open timing = FALSE if(!valve_open) - pump.airs[1] = null - pump.airs[2] = null - return + var/turf/T = get_turf(src) + var/datum/gas_mixture/target_air = holding ? holding.air_contents : T.return_air() - var/turf/T = get_turf(src) - pump.airs[1] = air_contents - pump.airs[2] = holding ? holding.air_contents : T.return_air() - pump.target_pressure = release_pressure + if(air_contents.release_gas_to(target_air, release_pressure) && !holding) + air_update_turf() - pump.process_atmos() // Pump gas. - if(!holding) - air_update_turf() // Update the environment if needed. + // var/our_pressure = air_contents.return_pressure() + // var/our_temperature = air_contents.return_temperature() + + ///function used to check the limit of the canisters and also set the amount of damage that the canister can receive, if the heat and pressure are way higher than the limit the more damage will be done + // currently unused + // if(our_temperature > heat_limit || our_pressure > pressure_limit) + // take_damage(clamp((our_temperature/heat_limit) * (our_pressure/pressure_limit) * delta_time * 2, 5, 50), BURN, 0) update_icon() /obj/machinery/portable_atmospherics/canister/ui_state(mob/user) @@ -340,35 +344,48 @@ ui = new(user, src, "Canister", name) ui.open() +/obj/machinery/portable_atmospherics/canister/ui_static_data(mob/user) + return list( + "defaultReleasePressure" = round(CAN_DEFAULT_RELEASE_PRESSURE), + "minReleasePressure" = round(can_min_release_pressure), + "maxReleasePressure" = round(can_max_release_pressure), + "pressureLimit" = round(1e14), + "holdingTankLeakPressure" = round(TANK_LEAK_PRESSURE), + "holdingTankFragPressure" = round(TANK_FRAGMENT_PRESSURE) + ) + /obj/machinery/portable_atmospherics/canister/ui_data() - var/data = list() - data["portConnected"] = connected_port ? 1 : 0 - data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0) - data["releasePressure"] = round(release_pressure ? release_pressure : 0) - data["defaultReleasePressure"] = round(CAN_DEFAULT_RELEASE_PRESSURE) - data["minReleasePressure"] = round(can_min_release_pressure) - data["maxReleasePressure"] = round(can_max_release_pressure) - data["valveOpen"] = valve_open ? 1 : 0 + . = list( + "portConnected" = !!connected_port, + "tankPressure" = round(air_contents.return_pressure()), + "releasePressure" = round(release_pressure), + "valveOpen" = !!valve_open, + "isPrototype" = !!prototype, + "hasHoldingTank" = !!holding + ) - data["isPrototype"] = prototype ? 1 : 0 if (prototype) - data["restricted"] = restricted - data["timing"] = timing - data["time_left"] = get_time_left() - data["timer_set"] = timer_set - data["timer_is_not_default"] = timer_set != default_timer_set - data["timer_is_not_min"] = timer_set != minimum_timer_set - data["timer_is_not_max"] = timer_set != maximum_timer_set + . += list( + "restricted" = restricted, + "timing" = timing, + "time_left" = get_time_left(), + "timer_set" = timer_set, + "timer_is_not_default" = timer_set != default_timer_set, + "timer_is_not_min" = timer_set != minimum_timer_set, + "timer_is_not_max" = timer_set != maximum_timer_set + ) - data["hasHoldingTank"] = holding ? 1 : 0 if (holding) - data["holdingTank"] = list() - data["holdingTank"]["name"] = holding.name - data["holdingTank"]["tankPressure"] = round(holding.air_contents.return_pressure()) - return data + . += list( + "holdingTank" = list( + "name" = holding.name, + "tankPressure" = round(holding.air_contents.return_pressure()) + ) + ) /obj/machinery/portable_atmospherics/canister/ui_act(action, params) - if(..()) + . = ..() + if(.) return switch(action) if("relabel") @@ -377,6 +394,7 @@ var/newtype = label2types[label] if(newtype) var/obj/machinery/portable_atmospherics/canister/replacement = newtype + investigate_log("was relabelled to [initial(replacement.name)] by [key_name(usr)].", INVESTIGATE_ATMOS) name = initial(replacement.name) desc = initial(replacement.desc) icon_state = initial(replacement.icon_state) @@ -458,9 +476,8 @@ if("eject") if(holding) if(valve_open) - message_admins("[ADMIN_LOOKUPFLW(usr)] removed [holding] from [src] with valve still open at [ADMIN_VERBOSEJMP(src)] releasing contents into the air
.") - investigate_log("[key_name(usr)] removed the [holding], leaving the valve open and transferring into the air
", INVESTIGATE_ATMOS) - holding.forceMove(get_turf(src)) - holding = null + message_admins("[ADMIN_LOOKUPFLW(usr)] removed [holding] from [src] with valve still open at [ADMIN_VERBOSEJMP(src)] releasing contents into the air.") + investigate_log("[key_name(usr)] removed the [holding], leaving the valve open and transferring into the air.", INVESTIGATE_ATMOS) + replace_tank(usr, FALSE) . = TRUE update_icon() diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm index c242509344..e6663f8bb2 100644 --- a/code/modules/client/verbs/ooc.dm +++ b/code/modules/client/verbs/ooc.dm @@ -190,11 +190,7 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8") to_chat(usr, "Sorry, tracking is currently disabled.") return - var/list/body = list() - body += "Playtime for [key]
Playtime:" - body += get_exp_report() - body += "" - usr << browse(body.Join(), "window=playerplaytime[ckey];size=550x615") + new /datum/job_report_menu(src, usr) /client/proc/ignore_key(client) var/client/C = client diff --git a/code/modules/food_and_drinks/kitchen_machinery/processor.dm b/code/modules/food_and_drinks/kitchen_machinery/processor.dm index 9a3df0a92b..ef2676fe83 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/processor.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/processor.dm @@ -156,11 +156,7 @@ /obj/machinery/processor/slime name = "slime processor" desc = "An industrial grinder with a sticker saying appropriated for science department. Keep hands clear of intake area while operating." - -/obj/machinery/processor/slime/Initialize() - . = ..() - var/obj/item/circuitboard/machine/B = new /obj/item/circuitboard/machine/processor/slime(null) - B.apply_default_parts(src) + circuit = /obj/item/circuitboard/machine/processor/slime /obj/machinery/processor/slime/adjust_item_drop_location(atom/movable/AM) var/static/list/slimecores = subtypesof(/obj/item/slime_extract) diff --git a/code/modules/jobs/job_report.dm b/code/modules/jobs/job_report.dm new file mode 100644 index 0000000000..88c7f7ad19 --- /dev/null +++ b/code/modules/jobs/job_report.dm @@ -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 diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm index 2ca4d5fd2e..6ef4684921 100644 --- a/code/modules/mining/laborcamp/laborstacker.dm +++ b/code/modules/mining/laborcamp/laborstacker.dm @@ -8,12 +8,12 @@ GLOBAL_LIST(labor_sheet_values) icon = 'icons/obj/machines/mining_machines.dmi' icon_state = "console" density = FALSE - + /// Connected stacking machine var/obj/machinery/mineral/stacking_machine/laborstacker/stacking_machine = null + /// Direction of the stacking machine var/machinedir = SOUTH - var/obj/machinery/door/airlock/release_door - var/door_tag = "prisonshuttle" - var/obj/item/radio/Radio //needed to send messages to sec radio + /// Needed to send messages to sec radio + var/obj/item/radio/Radio /obj/machinery/mineral/labor_claim_console/Initialize() . = ..() @@ -39,15 +39,23 @@ GLOBAL_LIST(labor_sheet_values) ui = new(user, src, "LaborClaimConsole", name) ui.open() +/obj/machinery/mineral/labor_claim_console/ui_static_data(mob/user) + var/list/data = list() + data["ores"] = GLOB.labor_sheet_values + return data + /obj/machinery/mineral/labor_claim_console/ui_data(mob/user) var/list/data = list() var/can_go_home = FALSE - data["emagged"] = (obj_flags & EMAGGED) ? 1 : 0 + data["emagged"] = FALSE if(obj_flags & EMAGGED) + data["emagged"] = TRUE can_go_home = TRUE - - var/obj/item/card/id/I = user.get_idcard(TRUE) + var/obj/item/card/id/I + if(isliving(usr)) + var/mob/living/L = usr + I = L.get_idcard(TRUE) if(istype(I, /obj/item/card/id/prisoner)) var/obj/item/card/id/prisoner/P = I data["id_points"] = P.points @@ -63,43 +71,46 @@ GLOBAL_LIST(labor_sheet_values) if(stacking_machine) data["unclaimed_points"] = stacking_machine.points - data["ores"] = GLOB.labor_sheet_values data["can_go_home"] = can_go_home - return data /obj/machinery/mineral/labor_claim_console/ui_act(action, params) - if(..()) + . = ..() + if(.) return + + var/mob/M = usr switch(action) if("claim_points") - var/mob/M = usr - var/obj/item/card/id/I = M.get_idcard(TRUE) + var/obj/item/card/id/I + if(isliving(M)) + var/mob/living/L = M + I = L.get_idcard(TRUE) if(istype(I, /obj/item/card/id/prisoner)) var/obj/item/card/id/prisoner/P = I P.points += stacking_machine.points stacking_machine.points = 0 - to_chat(usr, "Points transferred.") - . = TRUE + to_chat(M, "Points transferred.") + return TRUE else - to_chat(usr, "No valid id for point transfer detected.") + to_chat(M, "No valid id for point transfer detected.") if("move_shuttle") - if(!alone_in_area(get_area(src), usr)) - to_chat(usr, "Prisoners are only allowed to be released while alone.") - else - switch(SSshuttle.moveShuttle("laborcamp", "laborcamp_home", TRUE)) - if(1) - to_chat(usr, "Shuttle not found.") - if(2) - to_chat(usr, "Shuttle already at station.") - if(3) - to_chat(usr, "No permission to dock could be granted.") - else - if(!(obj_flags & EMAGGED)) - Radio.set_frequency(FREQ_SECURITY) - Radio.talk_into(src, "A prisoner has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY) - to_chat(usr, "Shuttle received message and will be sent shortly.") - . = TRUE + if(!alone_in_area(get_area(src), M)) + to_chat(M, "Prisoners are only allowed to be released while alone.") + return + switch(SSshuttle.moveShuttle("laborcamp", "laborcamp_home", TRUE)) + if(1) + to_chat(M, "Shuttle not found.") + if(2) + to_chat(M, "Shuttle already at station.") + if(3) + to_chat(M, "No permission to dock could be granted.") + else + if(!(obj_flags & EMAGGED)) + Radio.set_frequency(FREQ_SECURITY) + Radio.talk_into(src, "A prisoner has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY) + to_chat(M, "Shuttle received message and will be sent shortly.") + return TRUE /obj/machinery/mineral/labor_claim_console/proc/locate_stacking_machine() stacking_machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir)) @@ -110,10 +121,9 @@ GLOBAL_LIST(labor_sheet_values) /obj/machinery/mineral/labor_claim_console/emag_act(mob/user) . = ..() - if((obj_flags & EMAGGED)) - return - obj_flags |= EMAGGED - to_chat(user, "PZZTTPFFFT") + if(!(obj_flags & EMAGGED)) + obj_flags |= EMAGGED + to_chat(user, "PZZTTPFFFT") return TRUE /**********************Prisoner Collection Unit**************************/ @@ -121,13 +131,13 @@ GLOBAL_LIST(labor_sheet_values) /obj/machinery/mineral/stacking_machine/laborstacker force_connect = TRUE var/points = 0 //The unclaimed value of ore stacked. - //damage_deflection = 21 + // damage_deflection = 21 /obj/machinery/mineral/stacking_machine/laborstacker/process_sheet(obj/item/stack/sheet/inp) points += inp.point_value * inp.amount ..() /obj/machinery/mineral/stacking_machine/laborstacker/attackby(obj/item/I, mob/living/user) - if(istype(I, /obj/item/stack/sheet) && user.canUnEquip(I)) + if(istype(I, /obj/item/stack/sheet) && user.canUnEquip(I) && user.a_intent == INTENT_HELP) var/obj/item/stack/sheet/inp = I points += inp.point_value * inp.amount return ..() @@ -141,7 +151,10 @@ GLOBAL_LIST(labor_sheet_values) icon_state = "console" density = FALSE -/obj/machinery/mineral/labor_points_checker/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) +/obj/machinery/mineral/labor_points_checker/attack_hand(mob/user) + . = ..() + if(. || user.is_blind()) + return user.examinate(src) /obj/machinery/mineral/labor_points_checker/attackby(obj/item/I, mob/user, params) diff --git a/code/modules/research/server.dm b/code/modules/research/server.dm index 6f8ea50f05..657d3b2e12 100644 --- a/code/modules/research/server.dm +++ b/code/modules/research/server.dm @@ -3,6 +3,9 @@ desc = "A computer system running a deep neural network that processes arbitrary information to produce data useable in the development of new technologies. In layman's terms, it makes research points." icon = 'icons/obj/machines/research.dmi' icon_state = "server" + req_access = list(ACCESS_RD) //ONLY THE R&D CAN CHANGE SERVER SETTINGS. + circuit = /obj/item/circuitboard/machine/rdserver + var/datum/techweb/stored_research var/heat_health = 100 //Code for point mining here. @@ -15,14 +18,11 @@ var/temp_tolerance_low = 0 var/temp_tolerance_high = T20C var/temp_penalty_coefficient = 0.5 //1 = -1 points per degree above high tolerance. 0.5 = -0.5 points per degree above high tolerance. - req_access = list(ACCESS_RD) //ONLY THE R&D CAN CHANGE SERVER SETTINGS. /obj/machinery/rnd/server/Initialize() . = ..() SSresearch.servers |= src stored_research = SSresearch.science_tech - var/obj/item/circuitboard/machine/B = new /obj/item/circuitboard/machine/rdserver(null) - B.apply_default_parts(src) /obj/machinery/rnd/server/Destroy() SSresearch.servers -= src diff --git a/code/modules/station_goals/dna_vault.dm b/code/modules/station_goals/dna_vault.dm index 4ac3777a41..b13c2df770 100644 --- a/code/modules/station_goals/dna_vault.dm +++ b/code/modules/station_goals/dna_vault.dm @@ -33,14 +33,14 @@ /datum/station_goal/dna_vault/get_report() return {"Our long term prediction systems indicate a 99% chance of system-wide cataclysm in the near future. - We need you to construct a DNA Vault aboard your station. + We need you to construct a DNA Vault aboard your station. - The DNA Vault needs to contain samples of: - [animal_count] unique animal data - [plant_count] unique non-standard plant data - [human_count] unique sapient humanoid DNA data + The DNA Vault needs to contain samples of: + [animal_count] unique animal data + [plant_count] unique non-standard plant data + [human_count] unique sapient humanoid DNA data - Base vault parts are available for shipping via cargo."} + Base vault parts are available for shipping via cargo."} /datum/station_goal/dna_vault/on_report() @@ -87,7 +87,7 @@ if(!H.myseed) return if(!H.harvest)// So it's bit harder. - to_chat(user, "Plant needs to be ready to harvest to perform full data scan.") //Because space dna is actually magic + to_chat(user, "Plant needs to be ready to harvest to perform full data scan.") //Because space dna is actually magic return if(plants[H.myseed.type]) to_chat(user, "Plant data already present in local storage.") @@ -101,10 +101,10 @@ if(isanimal(target)) var/mob/living/simple_animal/A = target if(!A.healable)//simple approximation of being animal not a robot or similar - to_chat(user, "No compatible DNA detected") + to_chat(user, "No compatible DNA detected.") return if(animals[target.type]) - to_chat(user, "Animal data already present in local storage.") + to_chat(user, "Animal data already present in local storage.") return animals[target.type] = 1 to_chat(user, "Animal data added to local storage.") @@ -173,7 +173,6 @@ qdel(filler) . = ..() - /obj/machinery/dna_vault/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) @@ -204,15 +203,17 @@ data["choiceB"] = "" if(user && completed) var/list/L = power_lottery[user] - if(L && L.len) + if(L?.len) data["used"] = FALSE data["choiceA"] = L[1] data["choiceB"] = L[2] return data /obj/machinery/dna_vault/ui_act(action, params) - if(..()) + . = ..() + if(.) return + switch(action) if("gene") upgrade(usr,params["choice"]) @@ -244,8 +245,6 @@ else return ..() - - /obj/machinery/dna_vault/proc/upgrade(mob/living/carbon/human/H,upgrade_type) if(!(upgrade_type in power_lottery[H])) return diff --git a/icons/UI_Icons/chat/chat_icons.dmi b/icons/UI_Icons/chat/chat_icons.dmi index 7040b3966f..8cc4b2c559 100644 Binary files a/icons/UI_Icons/chat/chat_icons.dmi and b/icons/UI_Icons/chat/chat_icons.dmi differ diff --git a/icons/UI_Icons/minesweeper_tiles/eight.png b/icons/UI_Icons/minesweeper_tiles/eight.png deleted file mode 100644 index 3a5c4179ef..0000000000 Binary files a/icons/UI_Icons/minesweeper_tiles/eight.png and /dev/null differ diff --git a/icons/UI_Icons/minesweeper_tiles/empty.png b/icons/UI_Icons/minesweeper_tiles/empty.png deleted file mode 100644 index 8a4fb536bb..0000000000 Binary files a/icons/UI_Icons/minesweeper_tiles/empty.png and /dev/null differ diff --git a/icons/UI_Icons/minesweeper_tiles/five.png b/icons/UI_Icons/minesweeper_tiles/five.png deleted file mode 100644 index dacf837f9b..0000000000 Binary files a/icons/UI_Icons/minesweeper_tiles/five.png and /dev/null differ diff --git a/icons/UI_Icons/minesweeper_tiles/flag.png b/icons/UI_Icons/minesweeper_tiles/flag.png deleted file mode 100644 index e71d8685ed..0000000000 Binary files a/icons/UI_Icons/minesweeper_tiles/flag.png and /dev/null differ diff --git a/icons/UI_Icons/minesweeper_tiles/four.png b/icons/UI_Icons/minesweeper_tiles/four.png deleted file mode 100644 index 17a2bdfeb4..0000000000 Binary files a/icons/UI_Icons/minesweeper_tiles/four.png and /dev/null differ diff --git a/icons/UI_Icons/minesweeper_tiles/hidden.png b/icons/UI_Icons/minesweeper_tiles/hidden.png deleted file mode 100644 index 8d34a2a7f3..0000000000 Binary files a/icons/UI_Icons/minesweeper_tiles/hidden.png and /dev/null differ diff --git a/icons/UI_Icons/minesweeper_tiles/mine.png b/icons/UI_Icons/minesweeper_tiles/mine.png deleted file mode 100644 index e16c89c2a8..0000000000 Binary files a/icons/UI_Icons/minesweeper_tiles/mine.png and /dev/null differ diff --git a/icons/UI_Icons/minesweeper_tiles/minehit.png b/icons/UI_Icons/minesweeper_tiles/minehit.png deleted file mode 100644 index f0c9699d97..0000000000 Binary files a/icons/UI_Icons/minesweeper_tiles/minehit.png and /dev/null differ diff --git a/icons/UI_Icons/minesweeper_tiles/one.png b/icons/UI_Icons/minesweeper_tiles/one.png deleted file mode 100644 index a84e6010a3..0000000000 Binary files a/icons/UI_Icons/minesweeper_tiles/one.png and /dev/null differ diff --git a/icons/UI_Icons/minesweeper_tiles/seven.png b/icons/UI_Icons/minesweeper_tiles/seven.png deleted file mode 100644 index 10d71c427e..0000000000 Binary files a/icons/UI_Icons/minesweeper_tiles/seven.png and /dev/null differ diff --git a/icons/UI_Icons/minesweeper_tiles/six.png b/icons/UI_Icons/minesweeper_tiles/six.png deleted file mode 100644 index fe2ba800f4..0000000000 Binary files a/icons/UI_Icons/minesweeper_tiles/six.png and /dev/null differ diff --git a/icons/UI_Icons/minesweeper_tiles/three.png b/icons/UI_Icons/minesweeper_tiles/three.png deleted file mode 100644 index 1c128d88ee..0000000000 Binary files a/icons/UI_Icons/minesweeper_tiles/three.png and /dev/null differ diff --git a/icons/UI_Icons/minesweeper_tiles/two.png b/icons/UI_Icons/minesweeper_tiles/two.png deleted file mode 100644 index ff74af5c82..0000000000 Binary files a/icons/UI_Icons/minesweeper_tiles/two.png and /dev/null differ diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi index 75ee2b35e6..450269eda0 100644 Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ diff --git a/icons/mob/screen_cyborg.dmi b/icons/mob/screen_cyborg.dmi index 632443036e..13aa792944 100644 Binary files a/icons/mob/screen_cyborg.dmi and b/icons/mob/screen_cyborg.dmi differ diff --git a/icons/mob/screen_ghost.dmi b/icons/mob/screen_ghost.dmi index 5c49bedcad..d83cc34355 100644 Binary files a/icons/mob/screen_ghost.dmi and b/icons/mob/screen_ghost.dmi differ diff --git a/icons/obj/modular_console.dmi b/icons/obj/modular_console.dmi index 5d3cd0312c..71fb225b97 100644 Binary files a/icons/obj/modular_console.dmi and b/icons/obj/modular_console.dmi differ diff --git a/icons/obj/modular_laptop.dmi b/icons/obj/modular_laptop.dmi index fd24d27a97..4c7f838db4 100644 Binary files a/icons/obj/modular_laptop.dmi and b/icons/obj/modular_laptop.dmi differ diff --git a/icons/obj/modular_tablet.dmi b/icons/obj/modular_tablet.dmi index 32edb57475..9ccbef928b 100644 Binary files a/icons/obj/modular_tablet.dmi and b/icons/obj/modular_tablet.dmi differ diff --git a/icons/obj/tank.dmi b/icons/obj/tank.dmi index aa24883656..be89e9314b 100644 Binary files a/icons/obj/tank.dmi and b/icons/obj/tank.dmi differ diff --git a/tgstation.dme b/tgstation.dme index f9de8bc0a0..fa8a01908d 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2278,6 +2278,7 @@ #include "code\modules\integrated_electronics\subtypes\weaponized.dm" #include "code\modules\jobs\access.dm" #include "code\modules\jobs\job_exp.dm" +#include "code\modules\jobs\job_report.dm" #include "code\modules\jobs\jobs.dm" #include "code\modules\jobs\job_types\_job.dm" #include "code\modules\jobs\job_types\ai.dm"