diff --git a/_maps/Prefab/Departments.dmm b/_maps/Prefab/Departments.dmm index 5753cc34f25c1..1744efc1167e4 100644 --- a/_maps/Prefab/Departments.dmm +++ b/_maps/Prefab/Departments.dmm @@ -340,7 +340,7 @@ /turf/open/floor/plating, /area/space) "iP" = ( -/obj/machinery/door_timer, +/obj/machinery/status_display/door_timer, /turf/open/floor/iron, /area/space) "jm" = ( diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index 61e05c1584277..6756883d429d5 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -45065,7 +45065,7 @@ /area/engine/engineering) "oMf" = ( /obj/structure/toilet, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Solitary confinement timer"; pixel_y = 32 @@ -57072,7 +57072,7 @@ /turf/open/floor/iron, /area/quartermaster/qm) "tUj" = ( -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Solitary confinement timer"; pixel_y = 32 diff --git a/_maps/map_files/CorgStation/CorgStation.dmm b/_maps/map_files/CorgStation/CorgStation.dmm index ea6161c73c61c..ef223a0ef1dfc 100644 --- a/_maps/map_files/CorgStation/CorgStation.dmm +++ b/_maps/map_files/CorgStation/CorgStation.dmm @@ -9744,7 +9744,7 @@ /obj/machinery/light/small{ dir = 1 }, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ pixel_y = 32 }, /obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer2{ @@ -32106,7 +32106,7 @@ /obj/effect/turf_decal/tile/red/half/contrasted{ dir = 4 }, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Solitary confinement timer"; pixel_y = 32 @@ -72907,7 +72907,7 @@ /obj/effect/turf_decal/tile/red/half/contrasted{ dir = 4 }, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ pixel_y = 32 }, /obj/machinery/computer/arcade/orion_trail, diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 7de1e97e0fac8..20828e1cee4f2 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -39980,7 +39980,7 @@ /obj/structure/cable/yellow{ icon_state = "0-4" }, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "scicell"; name = "Science Cell"; pixel_x = -32; @@ -41622,7 +41622,7 @@ /area/science/xenobiology) "gzR" = ( /obj/structure/closet/secure_closet/security/engine, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "engcell"; name = "Engineering Cell"; pixel_x = 32; @@ -51247,7 +51247,7 @@ /obj/structure/cable/yellow{ icon_state = "0-4" }, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cargocell"; name = "Cargo Cell"; pixel_x = -32; @@ -70382,7 +70382,7 @@ /turf/open/floor/iron, /area/science/research) "qnj" = ( -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Solitary confinement timer"; pixel_y = 32 @@ -79510,7 +79510,7 @@ /obj/structure/table/reinforced, /obj/item/restraints/handcuffs, /obj/item/implant/radio, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "medcell"; name = "Medical Cell"; pixel_y = -32 diff --git a/_maps/map_files/EchoStation/EchoStation.dmm b/_maps/map_files/EchoStation/EchoStation.dmm index de3787324a6c0..79bc539b4158e 100644 --- a/_maps/map_files/EchoStation/EchoStation.dmm +++ b/_maps/map_files/EchoStation/EchoStation.dmm @@ -20760,7 +20760,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "Cell 1"; name = "Cell 1"; pixel_y = 32 diff --git a/_maps/map_files/FlandStation/FlandStation.dmm b/_maps/map_files/FlandStation/FlandStation.dmm index 8dbf4af27ce4d..27bbb6de8d958 100644 --- a/_maps/map_files/FlandStation/FlandStation.dmm +++ b/_maps/map_files/FlandStation/FlandStation.dmm @@ -1626,7 +1626,7 @@ /obj/effect/turf_decal/trimline/red/filled/line{ dir = 10 }, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "arrdoor"; name = "Arrival Cell"; pixel_y = -32 @@ -12873,7 +12873,7 @@ /obj/machinery/recharger{ pixel_x = -4 }, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "medcell"; name = "Medical Cell"; pixel_y = 32 @@ -87147,7 +87147,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 10 }, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Medical Cell"; pixel_x = 32; diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index 6d9777691fd90..95d0a6b4a2675 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -82540,7 +82540,7 @@ /obj/effect/turf_decal/stripes/corner{ dir = 1 }, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Solitary confinement timer"; pixel_y = 32 diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index d1017c4555e51..3ab1ea118f162 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -31175,7 +31175,7 @@ /obj/machinery/light{ dir = 1 }, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Solitary confinement timer"; pixel_y = 32 diff --git a/_maps/map_files/RadStation/RadStation.dmm b/_maps/map_files/RadStation/RadStation.dmm index 2c6cbec8a9542..5ed66c2f5e82c 100644 --- a/_maps/map_files/RadStation/RadStation.dmm +++ b/_maps/map_files/RadStation/RadStation.dmm @@ -6155,7 +6155,7 @@ /turf/open/floor/plating, /area/maintenance/port/aft) "caA" = ( -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Solitary confinement timer"; pixel_x = 32 @@ -18864,7 +18864,7 @@ /obj/effect/turf_decal/guideline/guideline_half_edge/red{ dir = 5 }, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Solitary confinement timer"; pixel_x = 32 @@ -23204,7 +23204,7 @@ dir = 9; network = list("ss13","prison") }, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Solitary confinement timer"; pixel_x = 32 @@ -25616,7 +25616,7 @@ /turf/open/floor/iron/dark, /area/hallway/primary/central) "hRZ" = ( -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Solitary confinement timer"; pixel_x = -32 @@ -40844,7 +40844,7 @@ dir = 8 }, /obj/machinery/light/small, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Solitary confinement timer"; pixel_y = 32 @@ -48339,7 +48339,7 @@ /area/security/brig/dock) "pbr" = ( /obj/effect/turf_decal/tile/red/fourcorners/contrasted, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Solitary confinement timer"; pixel_y = -32 @@ -52405,7 +52405,7 @@ /turf/open/floor/iron/dark, /area/security/checkpoint/engineering) "qpo" = ( -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Solitary confinement timer"; pixel_y = 32 @@ -56254,7 +56254,7 @@ icon_state = "4-8" }, /obj/effect/turf_decal/tile/red/fourcorners/contrasted, -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Solitary confinement timer"; pixel_y = -32 @@ -67753,7 +67753,7 @@ /turf/open/floor/engine/air, /area/engine/atmos) "vgF" = ( -/obj/machinery/door_timer{ +/obj/machinery/status_display/door_timer{ id = "cell"; name = "Solitary confinement timer"; pixel_y = 32 diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index abcd962fe16f7..be10e350a6a82 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -140,7 +140,6 @@ GLOBAL_LIST_INIT(WALLITEMS_INTERIOR, typecacheof(list( /obj/machinery/computer/security/telescreen, /obj/machinery/embedded_controller/radio/simple_vent_controller, /obj/item/storage/secure/safe, - /obj/machinery/door_timer, /obj/machinery/flasher, /obj/machinery/keycard_auth, /obj/structure/mirror, diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index 0cc40beca53d7..bf39144f4064e 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -349,6 +349,22 @@ GLOBAL_LIST_INIT(admiral_messages, list( GLOBAL_LIST_INIT(junkmail_messages, world.file2list("strings/junkmail.txt")) +// All valid inputs to status display post_status +GLOBAL_LIST_INIT(status_display_approved_pictures, list( + "blank", + "shuttle", + "default", + "biohazard", + "lockdown", + "redalert", +)) + +// Members of status_display_approved_pictures that are actually states and not alert values +GLOBAL_LIST_INIT(status_display_state_pictures, list( + "blank", + "shuttle", +)) + GLOBAL_LIST_INIT(pAI_faces_list, list( "Angry" = "angry", "Cat" = "cat", diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index ede58d6987c77..987db2e5a8f9e 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -271,11 +271,10 @@ if ("setStatusMessage") if (!authenticated(usr)) return - var/line_one = reject_bad_text(params["lineOne"] || "", MAX_STATUS_LINE_LENGTH) - var/line_two = reject_bad_text(params["lineTwo"] || "", MAX_STATUS_LINE_LENGTH) + var/line_one = reject_bad_text(params["upperText"] || "", MAX_STATUS_LINE_LENGTH) + var/line_two = reject_bad_text(params["lowerText"] || "", MAX_STATUS_LINE_LENGTH) message_admins("[ADMIN_LOOKUPFLW(usr)] changed the Status Message to - [line_one], [line_two] - From a Communications Console.") log_game("[key_name(usr)] changed the Status Message to - [line_one], [line_two] - From a Communications Console.") - post_status("alert", "blank") post_status("message", line_one, line_two) last_status_display = list(line_one, line_two) playsound(src, "terminal_type", 50, FALSE) @@ -284,9 +283,12 @@ if (!authenticated(usr)) return var/picture = params["picture"] - if (!(picture in GLOB.approved_status_pictures)) + if (!(picture in GLOB.status_display_approved_pictures)) return - post_status("alert", picture) + if(picture in GLOB.status_display_state_pictures) + post_status(picture) + else + post_status("alert", picture) playsound(src, "terminal_type", 50, FALSE) . = TRUE if ("toggleAuthentication") @@ -424,8 +426,8 @@ data["budget"] = bank_account.account_balance data["shuttles"] = shuttles if (STATE_CHANGING_STATUS) - data["lineOne"] = last_status_display ? last_status_display[1] : "" - data["lineTwo"] = last_status_display ? last_status_display[2] : "" + data["upperText"] = last_status_display ? last_status_display[1] : "" + data["lowerText"] = last_status_display ? last_status_display[2] : "" return data @@ -511,8 +513,8 @@ var/datum/signal/status_signal = new(list("command" = command)) switch(command) if("message") - status_signal.data["msg1"] = data1 - status_signal.data["msg2"] = data2 + status_signal.data["top_text"] = data1 + status_signal.data["bottom_text"] = data2 if("alert") status_signal.data["picture_state"] = data1 diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index 27fc2faf3b6e4..54e53ac14a274 100644 --- a/code/game/machinery/doors/brigdoors.dm +++ b/code/game/machinery/doors/brigdoors.dm @@ -1,27 +1,16 @@ -#define CHARS_PER_LINE 5 -#define FONT_SIZE "5pt" -#define FONT_COLOR "#09f" -#define FONT_STYLE "Small Fonts" - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////// -// Brig Door control displays. -// Description: This is a controls the timer for the brig doors, displays the timer on itself and -// has a popup window when used, allowing to set the timer. -// Code Notes: Combination of old brigdoor.dm code from rev4407 and the status_display.dm code -// Date: 01/September/2010 -// Programmer: Veryinky -///////////////////////////////////////////////////////////////////////////////////////////////// -/obj/machinery/door_timer +/** + * Brig Door control displays. + * + * This is a controls the timer for the brig doors, displays the timer on itself and + * has a popup window when used, allowing to set the timer. + */ +/obj/machinery/status_display/door_timer name = "door timer" - icon = 'icons/obj/status_display.dmi' - icon_state = "frame" desc = "A remote control for a door." + current_mode = SD_MESSAGE req_access = list(ACCESS_SECURITY) - density = FALSE + text_color = "#F44" + header_text_color = "#F88" layer = ABOVE_WINDOW_LAYER var/id = null // id of linked machinery/lockers @@ -35,23 +24,15 @@ var/list/flashers = list() ///List of weakrefs to nearby closets var/list/closets = list() + ///needed to send messages to sec radio + var/obj/item/radio/sec_radio - var/obj/item/radio/sec_radio //needed to send messages to sec radio - - maptext_height = 26 - maptext_width = 32 - maptext_y = -1 - - - -/obj/machinery/door_timer/Initialize(mapload) +/obj/machinery/status_display/door_timer/Initialize(mapload) . = ..() sec_radio = new/obj/item/radio(src) sec_radio.listening = FALSE -/obj/machinery/door_timer/Initialize(mapload) - . = ..() if(id != null) for(var/obj/machinery/door/window/brigdoor/M in urange(20, src)) if (M.id == id) @@ -66,30 +47,49 @@ closets += WEAKREF(C) if(!length(doors) && !length(flashers) && length(closets)) - set_machine_stat(machine_stat | BROKEN) - update_icon() - + obj_break() //Main door timer loop, if it's timing and time is >0 reduce time by 1. // if it's less than 0, open door, reset timer // update the door_timer window and the icon -/obj/machinery/door_timer/process() +/obj/machinery/status_display/door_timer/process() if(machine_stat & (NOPOWER|BROKEN)) + // No power, no processing. + update_appearance() + return PROCESS_KILL + + if(!timing) + return PROCESS_KILL + + if(REALTIMEOFDAY - activation_time >= timer_duration) + timer_end() // open doors, reset timer, clear status screen + update_content() + +/** + * Update the display content. + */ +/obj/machinery/status_display/door_timer/proc/update_content() + var/time_left = time_left(seconds = TRUE) + + if(time_left == 0) + set_messages("", "") return - if(timing) - if(REALTIMEOFDAY - activation_time >= timer_duration) - timer_end() // open doors, reset timer, clear status screen - update_icon() + var/disp1 = name + var/disp2 = "[add_leading(num2text((time_left / 60) % 60), 2, "0")]:[add_leading(num2text(time_left % 60), 2, "0")]" + set_messages(disp1, disp2) -// open/closedoor checks if door_timer has power, if so it checks if the -// linked door is open/closed (by density) then opens it/closes it. -/obj/machinery/door_timer/proc/timer_start() +/** + * Starts counting down the timer and closes linked the door. + * The timer is expected to have already been set by set_timer() + */ +/obj/machinery/status_display/door_timer/proc/timer_start() if(machine_stat & (NOPOWER|BROKEN)) return 0 activation_time = REALTIMEOFDAY timing = TRUE + begin_processing() for(var/datum/weakref/door_ref as anything in doors) var/obj/machinery/door/window/brigdoor/door = door_ref.resolve() @@ -110,12 +110,15 @@ if(closet.opened && !closet.close()) continue closet.locked = TRUE - closet.update_icon() + closet.update_appearance() return 1 - -/obj/machinery/door_timer/proc/timer_end(forced = FALSE) - +/** + * Stops the timer and resets the timer to 0, and opens the linked door. + * Arguments: + * * forced - TRUE if it was forced to stop rather than timing out. Will skip radioing, etc. + */ +/obj/machinery/status_display/door_timer/proc/timer_end(forced = FALSE) if(machine_stat & (NOPOWER|BROKEN)) return 0 @@ -126,13 +129,13 @@ timing = FALSE activation_time = null set_timer(0) - update_icon() + end_processing() ui_update() for(var/datum/weakref/door_ref as anything in doors) var/obj/machinery/door/window/brigdoor/door = door_ref.resolve() if(!door) - doors -= door_ref + doors -= door_ref continue if(!door.density) continue @@ -148,80 +151,46 @@ if(closet.opened) continue closet.locked = FALSE - closet.update_icon() + closet.update_appearance() return 1 - -/obj/machinery/door_timer/proc/time_left(seconds = FALSE) - . = max(0,timer_duration - (activation_time ? REALTIMEOFDAY - activation_time : 0)) +/** + * Return time left. + * Arguments: + * * seconds - return time in seconds it TRUE, else deciseconds. + */ +/obj/machinery/status_display/door_timer/proc/time_left(seconds = FALSE) + . = max(0, timer_duration - (activation_time ? REALTIMEOFDAY - activation_time : 0)) if(seconds) . /= 10 -/obj/machinery/door_timer/proc/set_timer(value) - var/new_time = clamp(value,0,CONFIG_GET(number/brig_timer_max) MINUTES) +/** + * Set the timer. Does NOT automatically start counting down, but does update the display. + * + * returns TRUE if no change occurred + * + * Arguments: + * value - time in deciseconds to set the timer for. + */ +/obj/machinery/status_display/door_timer/proc/set_timer(value) + var/new_time = clamp(value, 0, CONFIG_GET(number/brig_timer_max) MINUTES) . = new_time == timer_duration //return 1 on no change timer_duration = new_time + update_content() - -/obj/machinery/door_timer/ui_requires_update(mob/user, datum/tgui/ui) +/obj/machinery/status_display/door_timer/ui_requires_update(mob/user, datum/tgui/ui) . = ..() if(timing) . = TRUE // Autoupdate while timer is counting down -/obj/machinery/door_timer/ui_state(mob/user) - return GLOB.default_state - -/obj/machinery/door_timer/ui_interact(mob/user, datum/tgui/ui) +/obj/machinery/status_display/door_timer/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, "BrigTimer") + ui = new(user, src, "BrigTimer", name) ui.open() -//icon update function -// if NOPOWER, display blank -// if BROKEN, display blue screen of death icon AI uses -// if timing=true, run update display function -/obj/machinery/door_timer/update_icon() - if(machine_stat & (NOPOWER)) - icon_state = "frame" - return - - if(machine_stat & (BROKEN)) - set_picture("ai_bsod") - return - - if(timing) - var/disp1 = id - var/time_left = time_left(seconds = TRUE) - var/disp2 = "[add_leading(num2text((time_left / 60) % 60), 2, "0")]:[add_leading(num2text(time_left % 60), 2, "0")]" - if(length(disp2) > CHARS_PER_LINE) - disp2 = "Error" - update_display(disp1, disp2) - else - if(maptext) - maptext = "" - return - - -// Adds an icon in case the screen is broken/off, stolen from status_display.dm -/obj/machinery/door_timer/proc/set_picture(state) - if(maptext) - maptext = "" - cut_overlays() - add_overlay(mutable_appearance('icons/obj/status_display.dmi', state)) - - -//Checks to see if there's 1 line or 2, adds text-icons-numbers/letters over display -// Stolen from status_display -/obj/machinery/door_timer/proc/update_display(line1, line2) - line1 = uppertext(line1) - line2 = uppertext(line2) - var/new_text = {"
[line1]
[line2]
"} - if(maptext != new_text) - maptext = new_text - -/obj/machinery/door_timer/ui_data() +/obj/machinery/status_display/door_timer/ui_data() var/list/data = list() var/time_left = time_left(seconds = TRUE) data["seconds"] = round(time_left % 60) @@ -238,9 +207,9 @@ break return data - -/obj/machinery/door_timer/ui_act(action, params) - if(..()) +/obj/machinery/status_display/door_timer/ui_act(action, params) + . = ..() + if(.) return . = TRUE @@ -291,11 +260,3 @@ activation_time = REALTIMEOFDAY else . = FALSE - - - - -#undef FONT_SIZE -#undef FONT_COLOR -#undef FONT_STYLE -#undef CHARS_PER_LINE diff --git a/code/game/machinery/newscaster/newscaster_machine.dm b/code/game/machinery/newscaster/newscaster_machine.dm index b779bd9ba2d65..3e884f72694be 100644 --- a/code/game/machinery/newscaster/newscaster_machine.dm +++ b/code/game/machinery/newscaster/newscaster_machine.dm @@ -5,6 +5,7 @@ desc = "A standard Nanotrasen-licensed newsfeed handler for use in commercial space stations. All the news you absolutely have no use for, in one place!" icon = 'icons/obj/terminals.dmi' icon_state = "newscaster_off" + base_icon_state = "newscaster" verb_say = "beeps" verb_ask = "beeps" verb_exclaim = "beeps" @@ -70,7 +71,7 @@ active_request = null return ..() -/obj/machinery/newscaster/update_icon() +/obj/machinery/newscaster/update_appearance(updates=ALL) . = ..() if(machine_stat & (NOPOWER|BROKEN)) set_light(0) @@ -80,22 +81,29 @@ /obj/machinery/newscaster/update_overlays() . = ..() if(!(machine_stat & (NOPOWER|BROKEN))) - var/state = "newscaster_[GLOB.news_network.wanted_issue.active ? "wanted" : "normal"]" + var/state = "[base_icon_state]_[GLOB.news_network.wanted_issue.active ? "wanted" : "normal"]" . += mutable_appearance(icon, state) + . += emissive_appearance(icon, state, layer, alpha = src.alpha) + ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY) - if(GLOB.news_network.wanted_issue.active && alert) - . += mutable_appearance(icon, "newscaster_alert") + if(!GLOB.news_network.wanted_issue.active && alert) + . += mutable_appearance(icon, "[base_icon_state]_alert") + . += emissive_appearance(icon, "[base_icon_state]_alert", layer, alpha = src.alpha) + ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY) var/hp_percent = (obj_integrity * 100) / max_integrity switch(hp_percent) if(75 to 100) return if(50 to 75) - . += mutable_appearance(icon, "crack1") + . += "crack1" + . += emissive_blocker(icon, "crack1", alpha = src.alpha) if(25 to 50) - . += mutable_appearance(icon, "crack2") + . += "crack2" + . += emissive_blocker(icon, "crack2", alpha = src.alpha) else - . += mutable_appearance(icon, "crack3") + . += "crack3" + . += emissive_blocker(icon, "crack3", alpha = src.alpha) /obj/machinery/newscaster/ui_interact(mob/user, datum/tgui/ui) . = ..() diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index 630854a3998d2..2b323f3dcaf75 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -28,7 +28,8 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) name = "requests console" desc = "A console intended to send requests to different departments on the station." icon = 'icons/obj/terminals.dmi' - icon_state = "req_comp0" + icon_state = "req_comp_off" + base_icon_state = "req_comp" layer = ABOVE_WINDOW_LAYER var/department = "Unknown" //The list of all departments on the station (Determined from this variable on each unit) Set this to the same thing if you want several consoles in one department var/list/messages = list() //List of all messages @@ -71,31 +72,40 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) max_integrity = 300 armor = list(MELEE = 70, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 0, BIO = 0, RAD = 0, FIRE = 90, ACID = 90, STAMINA = 0) - light_color = LIGHT_COLOR_GREEN - light_power = 1.5 - -/obj/machinery/requests_console/update_icon() +/obj/machinery/requests_console/update_appearance(updates=ALL) + . = ..() if(machine_stat & NOPOWER) set_light(0) - else - set_light(1)//green light + return + set_light(1.4,0.7,"#34D352")//green light + +/obj/machinery/requests_console/update_icon_state() if(open) - if(!hackState) - icon_state="req_comp_open" - else - icon_state="req_comp_rewired" - else if(machine_stat & NOPOWER) - if(icon_state != "req_comp_off") - icon_state = "req_comp_off" + icon_state = "[base_icon_state]_[hackState ? "rewired" : "open"]" + return ..() + icon_state = "[base_icon_state]_off" + return ..() + +/obj/machinery/requests_console/update_overlays() + . = ..() + + if(open || (machine_stat & NOPOWER)) + return + + var/screen_state + + if(emergency || (newmessagepriority == REQ_EXTREME_MESSAGE_PRIORITY)) + screen_state = "[base_icon_state]3" + else if(newmessagepriority == REQ_HIGH_MESSAGE_PRIORITY) + screen_state = "[base_icon_state]2" + else if(newmessagepriority == REQ_NORMAL_MESSAGE_PRIORITY) + screen_state = "[base_icon_state]1" else - if(emergency || (newmessagepriority == REQ_EXTREME_MESSAGE_PRIORITY)) - icon_state = "req_comp3" - else if(newmessagepriority == REQ_HIGH_MESSAGE_PRIORITY) - icon_state = "req_comp2" - else if(newmessagepriority == REQ_NORMAL_MESSAGE_PRIORITY) - icon_state = "req_comp1" - else - icon_state = "req_comp0" + screen_state = "[base_icon_state]0" + + . += mutable_appearance(icon, screen_state) + . += emissive_appearance(icon, screen_state, layer, alpha = src.alpha) + ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY) /obj/machinery/requests_console/Initialize(mapload) . = ..() diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 65282321d467d..38dc7cc00b3a8 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -1,10 +1,8 @@ // Status display // (formerly Countdown timer display) -#define CHARS_PER_LINE 5 -#define FONT_SIZE "5pt" -#define FONT_COLOR "#09f" -#define FONT_STYLE "Small Fonts" +#define MAX_STATIC_WIDTH 25 +#define FONT_STYLE "5pt 'Small Fonts'" #define SCROLL_RATE (0.04 SECONDS) // time per pixel #define LINE1_Y -8 #define LINE2_Y -15 @@ -20,6 +18,9 @@ desc = null icon = 'icons/obj/status_display.dmi' icon_state = "frame" + verb_say = "beeps" + verb_ask = "beeps" + verb_exclaim = "beeps" density = FALSE use_power = IDLE_POWER_USE idle_power_usage = 10 @@ -27,45 +28,117 @@ var/obj/effect/overlay/status_display_text/message1_overlay var/obj/effect/overlay/status_display_text/message2_overlay - -/// Immediately blank the display. -/obj/machinery/status_display/proc/remove_display() - cut_overlays() - vis_contents.Cut() - if(message1_overlay) - QDEL_NULL(message1_overlay) - if(message2_overlay) - QDEL_NULL(message2_overlay) + var/current_picture = "" + var/current_mode = SD_BLANK + var/message1 = "" + var/message2 = "" + + /// Normal text color + var/text_color = "#09F" + /// Color for headers, eg. "- ETA -" + var/header_text_color = "#2CF" + +//makes it go on the wall when built +/obj/machinery/status_display/Initialize(mapload, ndir, building) + . = ..() + update_appearance() /// Immediately change the display to the given picture. /obj/machinery/status_display/proc/set_picture(state) - remove_display() - add_overlay(state) + if(state != current_picture) + current_picture = state + + update_appearance() /// Immediately change the display to the given two lines. -/obj/machinery/status_display/proc/update_display(line1, line2) +/obj/machinery/status_display/proc/set_messages(line1, line2) line1 = uppertext(line1) line2 = uppertext(line2) + if(line1 != message1) + message1 = line1 + + if(line2 != message2) + message2 = line2 + + update_appearance() + +/** + * Remove both message objs and null the fields. + * Don't call this in subclasses. + */ +/obj/machinery/status_display/proc/remove_messages() + if(message1_overlay) + QDEL_NULL(message1_overlay) + if(message2_overlay) + QDEL_NULL(message2_overlay) + +/** + * Create/update message overlay. + * They must be handled as real objects for the animation to run. + * Don't call this in subclasses. + * Arguments: + * * overlay - the current /obj/effect/overlay/status_display_text instance + * * line_y - The Y offset to render the text. + * * message - the new message text. + * Returns new /obj/effect/overlay/status_display_text or null if unchanged. + */ +/obj/machinery/status_display/proc/update_message(obj/effect/overlay/status_display_text/overlay, line_y, message) + if(overlay && message == overlay.message) + return null + + if(overlay) + qdel(overlay) + + var/obj/effect/overlay/status_display_text/new_status_display_text = new(src, line_y, message, text_color, header_text_color) + vis_contents += new_status_display_text + return new_status_display_text + +/obj/machinery/status_display/update_appearance(updates=ALL) + . = ..() if( \ - (message1_overlay && message1_overlay.message == line1) && \ - (message2_overlay && message2_overlay.message == line2) \ + (machine_stat & (NOPOWER|BROKEN)) || \ + (current_mode == SD_BLANK) || \ + (current_mode != SD_PICTURE && message1 == "" && message2 == "") \ ) + set_light(0) return + set_light(1.4, 0.7, LIGHT_COLOR_BLUE) // blue light - remove_display() +/obj/machinery/status_display/update_overlays() + . = ..() - message1_overlay = new(LINE1_Y, line1) - vis_contents += message1_overlay + if(machine_stat & (NOPOWER|BROKEN)) + remove_messages() + return - message2_overlay = new(LINE2_Y, line2) - vis_contents += message2_overlay + switch(current_mode) + if(SD_BLANK) + remove_messages() + // Turn off backlight. + return + if(SD_PICTURE) + remove_messages() + . += mutable_appearance(icon, current_picture) + else + var/overlay = update_message(message1_overlay, LINE1_Y, message1) + if(overlay) + message1_overlay = overlay + overlay = update_message(message2_overlay, LINE2_Y, message2) + if(overlay) + message2_overlay = overlay + + // Turn off backlight if message is blank + if(message1 == "" && message2 == "") + return + + . += emissive_appearance(icon, "outline", alpha = src.alpha) // Timed process - performs nothing in the base class /obj/machinery/status_display/process() if(machine_stat & NOPOWER) // No power, no processing. - remove_display() + update_appearance() return PROCESS_KILL @@ -82,6 +155,7 @@ . = ..() if(machine_stat & (NOPOWER|BROKEN) || . & EMP_PROTECT_SELF) return + current_mode = SD_PICTURE set_picture("ai_bsod") /obj/machinery/status_display/examine(mob/user) @@ -89,38 +163,28 @@ if (message1_overlay || message2_overlay) . += "The display says:" if (message1_overlay.message) - . += "
\t[html_encode(message1_overlay.message)]" + . += "\t[html_encode(message1_overlay.message)]" if (message2_overlay.message) - . += "
\t[html_encode(message2_overlay.message)]" + . += "\t[html_encode(message2_overlay.message)]" // Helper procs for child display types. /obj/machinery/status_display/proc/display_shuttle_status(obj/docking_port/mobile/shuttle) if(!shuttle) // the shuttle is missing - no processing - update_display("shutl?","") + set_messages("shutl?","") return PROCESS_KILL else if(shuttle.timer) - var/line1 = "-[shuttle.getModeStr()]-" + var/line1 = "- [shuttle.getModeStr()] -" var/line2 = shuttle.getTimerStr() - if(length_char(line2) > CHARS_PER_LINE) - line2 = "error" - update_display(line1, line2) + set_messages(line1, line2) else // don't kill processing, the timer might turn back on - remove_display() - -/obj/machinery/status_display/proc/examine_shuttle(mob/user, obj/docking_port/mobile/shuttle) - if (shuttle) - var/modestr = shuttle.getModeStr() - if (modestr) - if (shuttle.timer) - modestr = "
\t[modestr]: [shuttle.getTimerStr()]" - else - modestr = "
\t[modestr]" - return "The display says:
\t[shuttle.name][modestr]" - else - return "The display says:
\tShuttle missing!" + set_messages("", "") + +/obj/machinery/status_display/Destroy() + remove_messages() + return ..() /** * Nice overlay to make text smoothly scroll with no client updates after setup. @@ -129,42 +193,98 @@ icon = 'icons/obj/status_display.dmi' vis_flags = VIS_INHERIT_LAYER | VIS_INHERIT_PLANE | VIS_INHERIT_ID - var/message = "" + /// The message this overlay is displaying. + var/message + + // If the line is short enough to not marquee, and it matches this, it's a header. + var/static/regex/header_regex = regex("^-.*-$") + + /// Width of each character, including kerning gap afterwards. + /// We don't use rich text or anything fancy, so we can bake these values. + var/static/list/char_widths = list( + // ! " # $ % & ' ( ) * + , - . / + 1, 2, 3, 5, 4, 5, 5, 2, 3, 3, 3, 4, 2, 3, 2, 3, + // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? + 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 3, 3, 3, 3, + // @ A B C D E F G H I J K L M N O + 7, 5, 5, 5, 5, 4, 4, 5, 5, 2, 4, 5, 4, 6, 5, 5, + // P Q R S T U V W X Y Z [ \ ] ^ _ + 5, 5, 5, 5, 4, 5, 4, 6, 4, 4, 4, 3, 3, 3, 4, 4, + // ` a b c d e f g h i j k l m n o + 3, 5, 5, 5, 5, 4, 4, 5, 5, 2, 4, 5, 4, 6, 5, 5, + // p q r s t u v w x y z { | } ~ + 5, 5, 5, 5, 4, 5, 4, 6, 4, 4, 4, 3, 2, 3, 4, + ) + +/obj/effect/overlay/status_display_text/Initialize(mapload, yoffset, line, text_color, header_text_color) + . = ..() -/obj/effect/overlay/status_display_text/New(yoffset, line) maptext_y = yoffset message = line - var/line_length = length_char(line) + var/line_width = measure_width(line) - if(line_length > CHARS_PER_LINE) + if(line_width > MAX_STATIC_WIDTH) // Marquee text - var/marquee_message = "[line] • [line] • [line]" - var/marqee_length = line_length * 3 + 6 - maptext = generate_text(marquee_message, center = FALSE) - maptext_width = 6 * marqee_length - maptext_x = 32 + var/marquee_message = "[line] - [line] - [line]" + + // Width of full content. Must of these is never revealed unless the user inputted a single character. + var/full_marquee_width = measure_width(marquee_message) + // We loop after only this much has passed. + var/looping_marquee_width = measure_width("[line] - ") + + maptext = generate_text(marquee_message, center = FALSE, text_color = text_color) + maptext_width = full_marquee_width + maptext_x = 0 // Mask off to fit in screen. add_filter("mask", 1, alpha_mask_filter(icon = icon(icon, "outline"))) // Scroll. - var/width = 4 * marqee_length - var/time = (width + 32) * SCROLL_RATE - animate(src, maptext_x = -width, time = time, loop = -1) - animate(maptext_x = 32, time = 0) + var/time = looping_marquee_width * SCROLL_RATE + animate(src, maptext_x = -looping_marquee_width, time = time, loop = -1) + animate(maptext_x = 0, time = 0) else // Centered text - maptext = generate_text(line, center = TRUE) + var/color = header_regex.Find(line) ? header_text_color : text_color + maptext = generate_text(line, center = TRUE, text_color = color) maptext_x = 0 -/obj/effect/overlay/status_display_text/proc/generate_text(text, center) - return {"
[text]
"} +/** + * A hyper-streamlined version of MeasureText that doesn't support different fonts, rich formatting, or multiline. + * But it also doesn't require a client. + * + * Returns the width in pixels + * + * Arguments: + * * text - the text to measure + */ +/obj/effect/overlay/status_display_text/proc/measure_width(text) + var/width = 0 + for(var/text_idx in 1 to length(text)) + var/ascii = text2ascii(text, text_idx) + if(!(ascii in 0x20 to 0x7E)) + // So we can't possibly runtime, even though the input should be in range already. + width += 3 + continue + width += char_widths[ascii - 0x1F] + + return width + +/** + * Generate the actual maptext. + * Arguments: + * * text - the text to display + * * center - center the text if TRUE, otherwise left-align + * * text_color - the text color + */ +/obj/effect/overlay/status_display_text/proc/generate_text(text, center, text_color) + return {"
[text]
"} /// Evac display which shows shuttle timer or message set by Command. /obj/machinery/status_display/evac + current_mode = SD_EMERGENCY var/frequency = FREQ_STATUS_DISPLAYS - var/mode = SD_EMERGENCY var/friendc = FALSE // track if Friend Computer mode var/last_picture // For when Friend Computer mode is undone @@ -172,6 +292,10 @@ . = ..() // register for radio system SSradio.add_object(src, frequency) + // Circuit USB + AddComponent(/datum/component/usb_port, list( + /obj/item/circuit_component/status_display, + )) /obj/machinery/status_display/evac/Destroy() SSradio.remove_object(src,frequency) @@ -180,16 +304,16 @@ /obj/machinery/status_display/evac/process() if(machine_stat & NOPOWER) // No power, no processing. - remove_display() + update_appearance() return PROCESS_KILL if(friendc) //Makes all status displays except supply shuttle timer display the eye -- Urist + current_mode = SD_PICTURE set_picture("ai_friend") return PROCESS_KILL - switch(mode) + switch(current_mode) if(SD_BLANK) - remove_display() return PROCESS_KILL if(SD_EMERGENCY) @@ -202,26 +326,19 @@ set_picture(last_picture) return PROCESS_KILL -/obj/machinery/status_display/evac/examine(mob/user) - . = ..() - if(mode == SD_EMERGENCY) - . += examine_shuttle(user, SSshuttle.emergency) - else if(!message1_overlay && !message2_overlay) - . += "The display is blank." - /obj/machinery/status_display/evac/receive_signal(datum/signal/signal) switch(signal.data["command"]) if("blank") - mode = SD_BLANK - remove_display() + current_mode = SD_BLANK + update_appearance() if("shuttle") - mode = SD_EMERGENCY - remove_display() + current_mode = SD_EMERGENCY + set_messages("", "") if("message") - mode = SD_MESSAGE - update_display(signal.data["msg1"], signal.data["msg2"]) + current_mode = SD_MESSAGE + set_messages(signal.data["top_text"] || "", signal.data["bottom_text"] || "") if("alert") - mode = SD_PICTURE + current_mode = SD_PICTURE last_picture = signal.data["picture_state"] set_picture(last_picture) if("friendcomputer") @@ -232,11 +349,14 @@ /// Supply display which shows the status of the supply shuttle. /obj/machinery/status_display/supply name = "supply display" + current_mode = SD_MESSAGE + text_color = "#F90" + header_text_color = "#FC2" /obj/machinery/status_display/supply/process() if(machine_stat & NOPOWER) // No power, no processing. - remove_display() + update_appearance() return PROCESS_KILL var/line1 @@ -250,48 +370,31 @@ if(is_station_level(SSshuttle.supply.z)) line1 = "CARGO" line2 = "Docked" + else + line1 = "" + line2 = "" else - line1 = "CARGO" + line1 = "- [SSshuttle.supply.getModeStr()] -" line2 = SSshuttle.supply.getTimerStr() - if(length_char(line2) > CHARS_PER_LINE) - line2 = "Error" - update_display(line1, line2) - -/obj/machinery/status_display/supply/examine(mob/user) - . = ..() - var/obj/docking_port/mobile/shuttle = SSshuttle.supply - var/shuttleMsg = null - if (shuttle.mode == SHUTTLE_IDLE) - if (is_station_level(shuttle.z)) - shuttleMsg = "Docked" - else - shuttleMsg = "[shuttle.getModeStr()]: [shuttle.getTimerStr()]" - if (shuttleMsg) - . += "The display says:
\t[shuttleMsg]" - else - . += "The display is blank." - + set_messages(line1, line2) /// General-purpose shuttle status display. /obj/machinery/status_display/shuttle name = "shuttle display" + current_mode = SD_MESSAGE var/shuttle_id + text_color = "#0F5" + header_text_color = "#2FC" + /obj/machinery/status_display/shuttle/process() if(!shuttle_id || (machine_stat & NOPOWER)) // No power, no processing. - remove_display() + update_appearance() return PROCESS_KILL return display_shuttle_status(SSshuttle.getShuttle(shuttle_id)) -/obj/machinery/status_display/shuttle/examine(mob/user) - . = ..() - if(shuttle_id) - . += examine_shuttle(user, SSshuttle.getShuttle(shuttle_id)) - else - . += "The display is blank." - /obj/machinery/status_display/shuttle/vv_edit_var(var_name, var_value) . = ..() if(!.) @@ -310,6 +413,7 @@ /obj/machinery/status_display/ai name = "\improper AI display" desc = "A small screen which the AI can use to present itself." + current_mode = SD_PICTURE var/emotion = AI_EMOTION_BLANK @@ -358,16 +462,88 @@ /obj/machinery/status_display/ai/process() if(machine_stat & NOPOWER) - remove_display() + update_appearance() return PROCESS_KILL set_picture(emotion_map[emotion]) return PROCESS_KILL +/obj/item/circuit_component/status_display + display_name = "Status Display" + desc = "Output text and pictures to a status display." + circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL + + var/datum/port/input/option/command + var/datum/port/input/option/picture + var/datum/port/input/message1 + var/datum/port/input/message2 + + var/obj/machinery/status_display/connected_display + + var/list/command_map + var/list/picture_map + +/obj/item/circuit_component/status_display/populate_ports() + message1 = add_input_port("Message 1", PORT_TYPE_STRING) + message2 = add_input_port("Message 2", PORT_TYPE_STRING) + +/obj/item/circuit_component/status_display/populate_options() + var/static/list/command_options = list( + "Blank" = "blank", + "Shuttle" = "shuttle", + "Message" = "message", + "Alert" = "alert" + ) + + var/static/list/picture_options = list( + "Default" = "default", + "Red Alert" = "redalert", + "Biohazard" = "biohazard", + "Lockdown" = "lockdown", + "Happy" = "ai_happy", + "Neutral" = "ai_neutral", + "Very Happy" = "ai_veryhappy", + "Sad" = "ai_sad", + "Unsure" = "ai_unsure", + "Confused" = "ai_confused", + "Surprised" = "ai_surprised", + "BSOD" = "ai_bsod" + ) + + command = add_option_port("Command", command_options) + command_map = command_options + + picture = add_option_port("Picture", picture_options) + picture_map = picture_options + +/obj/item/circuit_component/status_display/register_usb_parent(atom/movable/shell) + . = ..() + if(istype(shell, /obj/machinery/status_display)) + connected_display = shell + +/obj/item/circuit_component/status_display/unregister_usb_parent(atom/movable/parent) + connected_display = null + return ..() + +/obj/item/circuit_component/status_display/input_received(datum/port/input/port) + // Just use command handling built into status display. + // The option inputs thankfully sanitize command and picture for us. + + if(!connected_display) + return + + var/command_value = command_map[command.value] + var/datum/signal/status_signal = new(list("command" = command_value)) + switch(command_value) + if("message") + status_signal.data["top_text"] = message1.value + status_signal.data["bottom_text"] = message2.value + if("alert") + status_signal.data["picture_state"] = picture_map[picture.value] + + connected_display.receive_signal(status_signal) -#undef CHARS_PER_LINE -#undef FONT_SIZE -#undef FONT_COLOR +#undef MAX_STATIC_WIDTH #undef FONT_STYLE #undef SCROLL_RATE #undef LINE1_Y diff --git a/code/modules/events/prison_break.dm b/code/modules/events/prison_break.dm index 3a0fbbdb1630f..404dfbc56741f 100644 --- a/code/modules/events/prison_break.dm +++ b/code/modules/events/prison_break.dm @@ -53,7 +53,6 @@ if(temp.critical_machine) //Skip doors in critical positions, such as the SM chamber. continue temp.prison_open() - else if(istype(O, /obj/machinery/door_timer)) - var/obj/machinery/door_timer/temp = O + else if(istype(O, /obj/machinery/status_display/door_timer)) + var/obj/machinery/status_display/door_timer/temp = O temp.timer_end(forced = TRUE) - diff --git a/code/modules/mob/living/silicon/ai/emote.dm b/code/modules/mob/living/silicon/ai/emote.dm index c48fefbe1f2d9..7114c04d502c3 100644 --- a/code/modules/mob/living/silicon/ai/emote.dm +++ b/code/modules/mob/living/silicon/ai/emote.dm @@ -14,8 +14,7 @@ var/mob/living/silicon/ai/ai = user var/turf/ai_turf = get_turf(ai) - for(var/_display in GLOB.ai_status_displays) - var/obj/machinery/status_display/ai/ai_display = _display + for(var/obj/machinery/status_display/ai/ai_display as anything in GLOB.ai_status_displays) var/turf/display_turf = get_turf(ai_display) // Derelict AIs can't affect station displays. diff --git a/code/modules/modular_computers/file_system/programs/statusdisplay.dm b/code/modules/modular_computers/file_system/programs/statusdisplay.dm index d063716bf8f93..a5724379b1121 100644 --- a/code/modules/modular_computers/file_system/programs/statusdisplay.dm +++ b/code/modules/modular_computers/file_system/programs/statusdisplay.dm @@ -12,36 +12,54 @@ usage_flags = PROGRAM_ALL available_on_ntnet = FALSE - var/upper_text - var/lower_text - var/picture + var/upper_text = "" + var/lower_text = "" -/datum/computer_file/program/status/proc/SendSignal(type) +/** + * Post status display radio packet. + * Arguments: + * * command - the status display command + * * data1 - the data1 value, as defined by status displays + * * data2 - the data2 value, as defined by status displays + */ +/datum/computer_file/program/status/proc/post_status(command, data1, data2) var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS) - if(!frequency) return - var/datum/signal/status_signal = new(list("command" = type)) - switch(type) + var/datum/signal/status_signal = new(list("command" = command)) + switch(command) if("message") - var/data1 = reject_bad_text(upper_text || "", MAX_STATUS_LINE_LENGTH) - var/data2 = reject_bad_text(lower_text || "", MAX_STATUS_LINE_LENGTH) - status_signal.data["msg1"] = data1 - status_signal.data["msg2"] = data2 + status_signal.data["top_text"] = data1 + status_signal.data["bottom_text"] = data2 message_admins("[ADMIN_LOOKUPFLW(usr)] changed the Status Message to - [data1], [data2] - From the Status Display app.") log_game("[key_name(usr)] changed the Status Message to - [data1], [data2] - From the Status Display app.") if("alert") - status_signal.data["picture_state"] = picture + status_signal.data["picture_state"] = data1 + + frequency.post_signal(src, status_signal) - frequency.post_signal(computer, status_signal) +/** + * Post a message to status displays + * Arguments: + * * upper - Top text + * * lower - Bottom text + */ +/datum/computer_file/program/status/proc/post_message(upper, lower) + post_status("message", upper, lower) -/datum/computer_file/program/status/proc/SetText(position, text) - switch(position) - if("upper") - upper_text = text - if("lower") - lower_text = text +/** + * Post a picture to status displays + * Arguments: + * * picture - The picture name + */ +/datum/computer_file/program/status/proc/post_picture(picture) + if (!(picture in GLOB.status_display_approved_pictures)) + return + if(picture in GLOB.status_display_state_pictures) + post_status(picture) + else + post_status("alert", picture) /datum/computer_file/program/status/ui_act(action, list/params, datum/tgui/ui) . = ..() @@ -49,21 +67,24 @@ return switch(action) - if("stat_send") - SendSignal("message") - if("stat_update") - SetText(params["position"], params["text"]) - if("stat_pic") - var/chosen_picture = params["picture"] - if (!(chosen_picture in GLOB.approved_status_pictures)) - return - picture = chosen_picture - SendSignal("alert") + if("setStatusMessage") + upper_text = reject_bad_text(params["upperText"] || "", MAX_STATUS_LINE_LENGTH) + lower_text = reject_bad_text(params["lowerText"] || "", MAX_STATUS_LINE_LENGTH) + + post_message(upper_text, lower_text) + if("setStatusPicture") + post_picture(params["picture"]) + +/datum/computer_file/program/status/ui_static_data(mob/user) + var/list/data = list() + data["maxStatusLineLength"] = MAX_STATUS_LINE_LENGTH + + return data /datum/computer_file/program/status/ui_data(mob/user) var/list/data = list() - data["upper"] = upper_text - data["lower"] = lower_text + data["upperText"] = upper_text + data["lowerText"] = lower_text return data diff --git a/icons/obj/terminals.dmi b/icons/obj/terminals.dmi index f15d847482fc1..c539594daf568 100644 Binary files a/icons/obj/terminals.dmi and b/icons/obj/terminals.dmi differ diff --git a/tgui/packages/tgui/interfaces/CommunicationsConsole.js b/tgui/packages/tgui/interfaces/CommunicationsConsole.js index 941d5616bc03a..552ca665bbd40 100644 --- a/tgui/packages/tgui/interfaces/CommunicationsConsole.js +++ b/tgui/packages/tgui/interfaces/CommunicationsConsole.js @@ -2,6 +2,7 @@ import { sortBy } from 'common/collections'; import { capitalize } from 'common/string'; import { useBackend, useLocalState } from '../backend'; import { Blink, Box, Button, Dimmer, Flex, Icon, Input, Modal, NoticeBox, Section, Stack, Tabs, TextArea, Tooltip } from '../components'; +import { StatusDisplayControls } from './common/StatusDisplayControls'; import { Window } from '../layouts'; import { sanitizeText } from '../sanitize'; @@ -207,75 +208,11 @@ const PageBuyingShuttle = (props, context) => { }; const PageChangingStatus = (props, context) => { - const { act, data } = useBackend(context); - const { maxStatusLineLength } = data; - - const [lineOne, setLineOne] = useLocalState(context, 'lineOne', data.lineOne); - const [lineTwo, setLineTwo] = useLocalState(context, 'lineTwo', data.lineTwo); + const { act } = useBackend(context); return ( -
- - -
- -
- - - setLineOne(value)} /> - - - - setLineTwo(value)} /> - - - -
+
); }; diff --git a/tgui/packages/tgui/interfaces/NtosStatus.js b/tgui/packages/tgui/interfaces/NtosStatus.js deleted file mode 100644 index 4f2d370a96115..0000000000000 --- a/tgui/packages/tgui/interfaces/NtosStatus.js +++ /dev/null @@ -1,58 +0,0 @@ -import { useBackend } from '../backend'; -import { NtosWindow } from '../layouts'; -import { Input, Section, Button, Flex } from '../components'; - -export const NtosStatus = (props, context) => { - const { act, data } = useBackend(context); - const { upper, lower } = data; - - return ( - - -
- - -
-
- - act('stat_update', { - position: 'upper', - text: value, - }) - } - /> -
- - act('stat_update', { - position: 'lower', - text: value, - }) - } - /> -
-
-
-
- ); -}; diff --git a/tgui/packages/tgui/interfaces/NtosStatus.tsx b/tgui/packages/tgui/interfaces/NtosStatus.tsx new file mode 100644 index 0000000000000..d3ed9e16a4b8e --- /dev/null +++ b/tgui/packages/tgui/interfaces/NtosStatus.tsx @@ -0,0 +1,12 @@ +import { NtosWindow } from '../layouts'; +import { StatusDisplayControls } from './common/StatusDisplayControls'; + +export const NtosStatus = () => { + return ( + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/common/StatusDisplayControls.tsx b/tgui/packages/tgui/interfaces/common/StatusDisplayControls.tsx new file mode 100644 index 0000000000000..e3ff6ffcb6c3b --- /dev/null +++ b/tgui/packages/tgui/interfaces/common/StatusDisplayControls.tsx @@ -0,0 +1,60 @@ +import { useBackend, useSharedState } from '../../backend'; +import { Flex, Input, Section, Button } from '../../components'; + +type Data = { + upperText: string; + lowerText: string; + maxStatusLineLength: number; +}; + +export const StatusDisplayControls = (props, context) => { + const { act, data } = useBackend(context); + const { upperText: initialUpper, lowerText: initialLower, maxStatusLineLength } = data; + + const [upperText, setUpperText] = useSharedState(context, 'statusUpperText', initialUpper); + const [lowerText, setLowerText] = useSharedState(context, 'statusLowerText', initialLower); + + return ( + <> +
+
+ +
+
+ +
+ + + setUpperText(value)} /> + + + + setLowerText(value)} /> + + + +
+ + ); +}; diff --git a/tools/UpdatePaths/Scripts/x_brigtimers.txt b/tools/UpdatePaths/Scripts/x_brigtimers.txt new file mode 100644 index 0000000000000..f8edc45416346 --- /dev/null +++ b/tools/UpdatePaths/Scripts/x_brigtimers.txt @@ -0,0 +1 @@ +/obj/machinery/door_timer : /obj/machinery/status_display/door_timer{@OLD}