From 634585ba22cc2095ab5f47acc4a785999cecbc11 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Sun, 14 Apr 2024 12:01:11 -0400 Subject: [PATCH 01/11] emissives done :> --- .../game/machinery/computer/communications.dm | 6 +- .../newscaster/newscaster_machine.dm | 20 ++- code/game/machinery/requests_console.dm | 46 ++--- code/game/machinery/status_display.dm | 159 +++++++++++++----- icons/obj/terminals.dmi | Bin 12124 -> 16732 bytes 5 files changed, 160 insertions(+), 71 deletions(-) diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index ede58d6987c77..788a1aae57328 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -76,6 +76,7 @@ /obj/machinery/computer/communications/ui_act(action, list/params) var/static/list/approved_states = list(STATE_BUYING_SHUTTLE, STATE_CHANGING_STATUS, STATE_MESSAGES) + var/static/list/state_status_pictures = list("blank", "shuttle") . = ..() if (.) @@ -286,7 +287,10 @@ var/picture = params["picture"] if (!(picture in GLOB.approved_status_pictures)) return - post_status("alert", picture) + if(picture in state_status_pictures) + post_status(picture) + else + post_status("alert", picture) playsound(src, "terminal_type", 50, FALSE) . = TRUE if ("toggleAuthentication") diff --git a/code/game/machinery/newscaster/newscaster_machine.dm b/code/game/machinery/newscaster/newscaster_machine.dm index b779bd9ba2d65..876317a1e2926 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,27 @@ /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, alpha = src.alpha) - 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", alpha = src.alpha) 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..d0d4c23f579c3 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -28,7 +28,7 @@ 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" 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 @@ -74,28 +74,32 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) light_color = LIGHT_COLOR_GREEN light_power = 1.5 -/obj/machinery/requests_console/update_icon() - if(machine_stat & NOPOWER) - set_light(0) - else - set_light(1)//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, alpha = src.alpha) /obj/machinery/requests_console/Initialize(mapload) . = ..() diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 65282321d467d..b9c070f36e03b 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -27,45 +27,105 @@ 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 = "" /// 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) + + return new/obj/effect/overlay/status_display_text(src, line_y, message) + +/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 +142,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) @@ -97,7 +158,7 @@ /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()]-" @@ -105,10 +166,10 @@ 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() + set_messages("", "") /obj/machinery/status_display/proc/examine_shuttle(mob/user, obj/docking_port/mobile/shuttle) if (shuttle) @@ -129,11 +190,13 @@ icon = 'icons/obj/status_display.dmi' vis_flags = VIS_INHERIT_LAYER | VIS_INHERIT_PLANE | VIS_INHERIT_ID - var/message = "" + var/message + var/obj/sd_parent -/obj/effect/overlay/status_display_text/New(yoffset, line) +/obj/effect/overlay/status_display_text/New(obj/parent, yoffset, line) maptext_y = yoffset message = line + sd_parent = parent var/line_length = length_char(line) @@ -158,13 +221,19 @@ maptext = generate_text(line, center = TRUE) maptext_x = 0 + parent.vis_contents += src + +/obj/effect/overlay/status_display_text/Destroy() + sd_parent.vis_contents -= src + return ..() + /obj/effect/overlay/status_display_text/proc/generate_text(text, center) 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 @@ -180,16 +249,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) @@ -204,24 +273,24 @@ /obj/machinery/status_display/evac/examine(mob/user) . = ..() - if(mode == SD_EMERGENCY) + if(current_mode == SD_EMERGENCY) . += examine_shuttle(user, SSshuttle.emergency) - else if(!message1_overlay && !message2_overlay) + else if(!message1 && !message2) . += "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["msg1"] || "", signal.data["msg2"] || "") if("alert") - mode = SD_PICTURE + current_mode = SD_PICTURE last_picture = signal.data["picture_state"] set_picture(last_picture) if("friendcomputer") @@ -232,11 +301,12 @@ /// Supply display which shows the status of the supply shuttle. /obj/machinery/status_display/supply name = "supply display" + current_mode = SD_MESSAGE /obj/machinery/status_display/supply/process() if(machine_stat & NOPOWER) // No power, no processing. - remove_display() + update_appearance() return PROCESS_KILL var/line1 @@ -250,12 +320,15 @@ if(is_station_level(SSshuttle.supply.z)) line1 = "CARGO" line2 = "Docked" + else + line1 = "" + line2 = "" else line1 = "CARGO" line2 = SSshuttle.supply.getTimerStr() if(length_char(line2) > CHARS_PER_LINE) line2 = "Error" - update_display(line1, line2) + set_messages(line1, line2) /obj/machinery/status_display/supply/examine(mob/user) . = ..() @@ -275,12 +348,13 @@ /// General-purpose shuttle status display. /obj/machinery/status_display/shuttle name = "shuttle display" + current_mode = SD_MESSAGE var/shuttle_id /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)) @@ -310,6 +384,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,7 +433,7 @@ /obj/machinery/status_display/ai/process() if(machine_stat & NOPOWER) - remove_display() + update_appearance() return PROCESS_KILL set_picture(emotion_map[emotion]) diff --git a/icons/obj/terminals.dmi b/icons/obj/terminals.dmi index f15d847482fc143379cafa5f64f64cc78228d373..c539594daf56851bc70f6757b918f965ba6224f1 100644 GIT binary patch literal 16732 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 TUc;sUC_kNthMLt69A5ojk0bfB literal 12124 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 NYTdqG@~2(I{{kK4-Uk2x From 946157717a298b29cb989becf9589899c1a38922 Mon Sep 17 00:00:00 2001 From: RKz Date: Sun, 14 Apr 2024 12:10:04 -0400 Subject: [PATCH 02/11] circuits --- code/game/machinery/status_display.dm | 78 +++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index b9c070f36e03b..4a0cdf8fb4567 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -241,6 +241,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) @@ -439,6 +443,80 @@ 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["msg1"] = message1.value + status_signal.data["msg2"] = 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 From 611eb7675b13ba1e53cf56a89b341f1d9fb76140 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Sun, 14 Apr 2024 12:27:02 -0400 Subject: [PATCH 03/11] new status display UIs --- code/_globalvars/lists/flavor_misc.dm | 16 +++ .../game/machinery/computer/communications.dm | 18 ++- code/game/machinery/status_display.dm | 6 +- .../file_system/programs/statusdisplay.dm | 83 ++++++++------ .../tgui/interfaces/CommunicationsConsole.js | 69 +----------- tgui/packages/tgui/interfaces/NtosStatus.js | 54 +-------- .../common/StatusDisplayControls.tsx | 103 ++++++++++++++++++ 7 files changed, 189 insertions(+), 160 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/common/StatusDisplayControls.tsx 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 788a1aae57328..987db2e5a8f9e 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -76,7 +76,6 @@ /obj/machinery/computer/communications/ui_act(action, list/params) var/static/list/approved_states = list(STATE_BUYING_SHUTTLE, STATE_CHANGING_STATUS, STATE_MESSAGES) - var/static/list/state_status_pictures = list("blank", "shuttle") . = ..() if (.) @@ -272,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) @@ -285,9 +283,9 @@ if (!authenticated(usr)) return var/picture = params["picture"] - if (!(picture in GLOB.approved_status_pictures)) + if (!(picture in GLOB.status_display_approved_pictures)) return - if(picture in state_status_pictures) + if(picture in GLOB.status_display_state_pictures) post_status(picture) else post_status("alert", picture) @@ -428,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 @@ -515,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/status_display.dm b/code/game/machinery/status_display.dm index 4a0cdf8fb4567..df5891caf5df0 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -292,7 +292,7 @@ set_messages("", "") if("message") current_mode = SD_MESSAGE - set_messages(signal.data["msg1"] || "", signal.data["msg2"] || "") + set_messages(signal.data["top_text"] || "", signal.data["bottom_text"] || "") if("alert") current_mode = SD_PICTURE last_picture = signal.data["picture_state"] @@ -511,8 +511,8 @@ var/datum/signal/status_signal = new(list("command" = command_value)) switch(command_value) if("message") - status_signal.data["msg1"] = message1.value - status_signal.data["msg2"] = message2.value + 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] 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/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 index 4f2d370a96115..d3ed9e16a4b8e 100644 --- a/tgui/packages/tgui/interfaces/NtosStatus.js +++ b/tgui/packages/tgui/interfaces/NtosStatus.js @@ -1,57 +1,11 @@ -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; +import { StatusDisplayControls } from './common/StatusDisplayControls'; +export const NtosStatus = () => { return ( - + -
- - -
-
- - act('stat_update', { - position: 'upper', - text: value, - }) - } - /> -
- - act('stat_update', { - position: 'lower', - text: value, - }) - } - /> -
-
+
); diff --git a/tgui/packages/tgui/interfaces/common/StatusDisplayControls.tsx b/tgui/packages/tgui/interfaces/common/StatusDisplayControls.tsx new file mode 100644 index 0000000000000..f5d5cad689b1c --- /dev/null +++ b/tgui/packages/tgui/interfaces/common/StatusDisplayControls.tsx @@ -0,0 +1,103 @@ +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)} + /> + + + +
+ + ); +}; From 7aedbe7530810bbf9ec39acb866fcf417503e2ac Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Sun, 14 Apr 2024 12:42:22 -0400 Subject: [PATCH 04/11] status displays harddels --- code/game/machinery/status_display.dm | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index df5891caf5df0..69f9705b04c58 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -79,7 +79,9 @@ if(overlay) qdel(overlay) - return new/obj/effect/overlay/status_display_text(src, line_y, message) + var/obj/effect/overlay/status_display_text/new_status_display_text = new(src, line_y, message) + vis_contents += new_status_display_text + return new_status_display_text /obj/machinery/status_display/update_appearance(updates=ALL) . = ..() @@ -183,6 +185,10 @@ else return "The display says:
\tShuttle missing!" +/obj/machinery/status_display/Destroy() + remove_messages() + return ..() + /** * Nice overlay to make text smoothly scroll with no client updates after setup. */ @@ -191,28 +197,28 @@ vis_flags = VIS_INHERIT_LAYER | VIS_INHERIT_PLANE | VIS_INHERIT_ID var/message - var/obj/sd_parent -/obj/effect/overlay/status_display_text/New(obj/parent, yoffset, line) +/obj/effect/overlay/status_display_text/Initialize(mapload, yoffset, line) + . = ..() + maptext_y = yoffset message = line - sd_parent = parent var/line_length = length_char(line) if(line_length > CHARS_PER_LINE) // Marquee text var/marquee_message = "[line] • [line] • [line]" - var/marqee_length = line_length * 3 + 6 + var/marquee_length = line_length * 3 + 6 maptext = generate_text(marquee_message, center = FALSE) - maptext_width = 6 * marqee_length + maptext_width = 6 * marquee_length maptext_x = 32 // Mask off to fit in screen. add_filter("mask", 1, alpha_mask_filter(icon = icon(icon, "outline"))) // Scroll. - var/width = 4 * marqee_length + var/width = 4 * marquee_length var/time = (width + 32) * SCROLL_RATE animate(src, maptext_x = -width, time = time, loop = -1) animate(maptext_x = 32, time = 0) @@ -221,12 +227,6 @@ maptext = generate_text(line, center = TRUE) maptext_x = 0 - parent.vis_contents += src - -/obj/effect/overlay/status_display_text/Destroy() - sd_parent.vis_contents -= src - return ..() - /obj/effect/overlay/status_display_text/proc/generate_text(text, center) return {"
[text]
"} From b3d60e28df0840c8c9d59f19f2a589686bd3d76e Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Sun, 14 Apr 2024 12:47:40 -0400 Subject: [PATCH 05/11] brig timers & colored texts --- code/__HELPERS/global_lists.dm | 1 - code/game/machinery/doors/brigdoors.dm | 180 ++++++++------------- code/game/machinery/status_display.dm | 167 ++++++++++--------- code/modules/events/prison_break.dm | 5 +- tools/UpdatePaths/Scripts/x_brigtimers.txt | 1 + 5 files changed, 169 insertions(+), 185 deletions(-) create mode 100644 tools/UpdatePaths/Scripts/x_brigtimers.txt 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/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index 27fc2faf3b6e4..dcb1c86a34478 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,50 @@ 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_icon() + +/** + * 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() @@ -114,8 +115,12 @@ 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,7 +131,7 @@ timing = FALSE activation_time = null set_timer(0) - update_icon() + end_processing() ui_update() for(var/datum/weakref/door_ref as anything in doors) @@ -152,76 +157,42 @@ 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) . = ..() 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.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,8 +209,7 @@ break return data - -/obj/machinery/door_timer/ui_act(action, params) +/obj/machinery/status_display/door_timer/ui_act(action, params) if(..()) return . = TRUE @@ -291,11 +261,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/status_display.dm b/code/game/machinery/status_display.dm index 69f9705b04c58..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 @@ -32,6 +33,16 @@ 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) if(state != current_picture) @@ -79,7 +90,7 @@ if(overlay) qdel(overlay) - var/obj/effect/overlay/status_display_text/new_status_display_text = new(src, line_y, message) + 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 @@ -152,9 +163,9 @@ 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) @@ -163,28 +174,14 @@ 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" set_messages(line1, line2) else // don't kill processing, the timer might turn back on set_messages("", "") -/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!" - /obj/machinery/status_display/Destroy() remove_messages() return ..() @@ -196,39 +193,93 @@ icon = 'icons/obj/status_display.dmi' vis_flags = VIS_INHERIT_LAYER | VIS_INHERIT_PLANE | VIS_INHERIT_ID + /// The message this overlay is displaying. var/message -/obj/effect/overlay/status_display_text/Initialize(mapload, yoffset, line) + // 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) . = ..() 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/marquee_length = line_length * 3 + 6 - maptext = generate_text(marquee_message, center = FALSE) - maptext_width = 6 * marquee_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 * marquee_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 @@ -275,13 +326,6 @@ set_picture(last_picture) return PROCESS_KILL -/obj/machinery/status_display/evac/examine(mob/user) - . = ..() - if(current_mode == SD_EMERGENCY) - . += examine_shuttle(user, SSshuttle.emergency) - else if(!message1 && !message2) - . += "The display is blank." - /obj/machinery/status_display/evac/receive_signal(datum/signal/signal) switch(signal.data["command"]) if("blank") @@ -306,6 +350,8 @@ /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) @@ -328,33 +374,19 @@ line1 = "" line2 = "" else - line1 = "CARGO" + line1 = "- [SSshuttle.supply.getModeStr()] -" line2 = SSshuttle.supply.getTimerStr() - if(length_char(line2) > CHARS_PER_LINE) - line2 = "Error" set_messages(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." - - /// 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. @@ -363,13 +395,6 @@ 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(!.) @@ -518,9 +543,7 @@ 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/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} From 253ad2ae107bb8600856c89f61ca4c6f16422d42 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Sun, 14 Apr 2024 12:52:48 -0400 Subject: [PATCH 06/11] script --- _maps/Prefab/Departments.dmm | 2 +- _maps/map_files/BoxStation/BoxStation.dmm | 4 ++-- _maps/map_files/CorgStation/CorgStation.dmm | 6 +++--- _maps/map_files/Deltastation/DeltaStation2.dmm | 10 +++++----- _maps/map_files/EchoStation/EchoStation.dmm | 2 +- _maps/map_files/FlandStation/FlandStation.dmm | 6 +++--- _maps/map_files/KiloStation/KiloStation.dmm | 2 +- _maps/map_files/MetaStation/MetaStation.dmm | 2 +- _maps/map_files/RadStation/RadStation.dmm | 18 +++++++++--------- code/game/machinery/doors/brigdoors.dm | 2 +- 10 files changed, 27 insertions(+), 27 deletions(-) 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/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index dcb1c86a34478..4027dfbb4cf4e 100644 --- a/code/game/machinery/doors/brigdoors.dm +++ b/code/game/machinery/doors/brigdoors.dm @@ -181,7 +181,7 @@ 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 From 45ee75ff3d7432ee2189387d47b4eeafb10cfcaa Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Sun, 14 Apr 2024 14:06:22 -0400 Subject: [PATCH 07/11] fix bad timer update --- code/game/machinery/doors/brigdoors.dm | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index 4027dfbb4cf4e..54e53ac14a274 100644 --- a/code/game/machinery/doors/brigdoors.dm +++ b/code/game/machinery/doors/brigdoors.dm @@ -49,7 +49,6 @@ if(!length(doors) && !length(flashers) && length(closets)) 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 @@ -64,7 +63,7 @@ if(REALTIMEOFDAY - activation_time >= timer_duration) timer_end() // open doors, reset timer, clear status screen - update_icon() + update_content() /** * Update the display content. @@ -111,10 +110,9 @@ if(closet.opened && !closet.close()) continue closet.locked = TRUE - closet.update_icon() + closet.update_appearance() return 1 - /** * Stops the timer and resets the timer to 0, and opens the linked door. * Arguments: @@ -137,7 +135,7 @@ 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 @@ -153,7 +151,7 @@ if(closet.opened) continue closet.locked = FALSE - closet.update_icon() + closet.update_appearance() return 1 @@ -189,7 +187,7 @@ /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() /obj/machinery/status_display/door_timer/ui_data() @@ -210,7 +208,8 @@ return data /obj/machinery/status_display/door_timer/ui_act(action, params) - if(..()) + . = ..() + if(.) return . = TRUE From 21968df2845ff894db34a4f798eb498446f79104 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Sun, 14 Apr 2024 14:55:17 -0400 Subject: [PATCH 08/11] oops, I fackin broke req consoles --- code/game/machinery/requests_console.dm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index d0d4c23f579c3..26558957db448 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -29,6 +29,7 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) desc = "A console intended to send requests to different departments on the station." icon = 'icons/obj/terminals.dmi' 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,8 +72,12 @@ 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_appearance(updates=ALL) + . = ..() + if(machine_stat & NOPOWER) + set_light(0) + return + set_light(1.4,0.7,"#34D352")//green light /obj/machinery/requests_console/update_icon_state() if(open) From 20d1f297e81b247276059bc4dec1825f4f276323 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Sun, 14 Apr 2024 15:17:15 -0400 Subject: [PATCH 09/11] prettier --- .../common/StatusDisplayControls.tsx | 63 +++---------------- 1 file changed, 10 insertions(+), 53 deletions(-) diff --git a/tgui/packages/tgui/interfaces/common/StatusDisplayControls.tsx b/tgui/packages/tgui/interfaces/common/StatusDisplayControls.tsx index f5d5cad689b1c..e3ff6ffcb6c3b 100644 --- a/tgui/packages/tgui/interfaces/common/StatusDisplayControls.tsx +++ b/tgui/packages/tgui/interfaces/common/StatusDisplayControls.tsx @@ -9,32 +9,15 @@ type Data = { export const StatusDisplayControls = (props, context) => { const { act, data } = useBackend(context); - const { - upperText: initialUpper, - lowerText: initialLower, - maxStatusLineLength, - } = data; + const { upperText: initialUpper, lowerText: initialLower, maxStatusLineLength } = data; - const [upperText, setUpperText] = useSharedState( - context, - 'statusUpperText', - initialUpper - ); - const [lowerText, setLowerText] = useSharedState( - context, - 'statusLowerText', - initialLower - ); + const [upperText, setUpperText] = useSharedState(context, 'statusUpperText', initialUpper); + const [lowerText, setLowerText] = useSharedState(context, 'statusLowerText', initialLower); return ( <>
-
-
- setUpperText(value)} - /> + setUpperText(value)} /> - setLowerText(value)} - /> + setLowerText(value)} /> -
From 94282e0906f2e98caa35f816fd069f81aa109362 Mon Sep 17 00:00:00 2001 From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Date: Wed, 17 Apr 2024 22:56:45 -0400 Subject: [PATCH 10/11] convert to tsx --- code/modules/mob/living/silicon/ai/emote.dm | 3 +-- .../packages/tgui/interfaces/{NtosStatus.js => NtosStatus.tsx} | 0 2 files changed, 1 insertion(+), 2 deletions(-) rename tgui/packages/tgui/interfaces/{NtosStatus.js => NtosStatus.tsx} (100%) 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/tgui/packages/tgui/interfaces/NtosStatus.js b/tgui/packages/tgui/interfaces/NtosStatus.tsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosStatus.js rename to tgui/packages/tgui/interfaces/NtosStatus.tsx From 2f6a57a9dfafb0fffd67f507c1efba649fae8095 Mon Sep 17 00:00:00 2001 From: RKz Date: Sun, 28 Apr 2024 01:48:25 -0400 Subject: [PATCH 11/11] lum --- code/game/machinery/newscaster/newscaster_machine.dm | 6 ++++-- code/game/machinery/requests_console.dm | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/code/game/machinery/newscaster/newscaster_machine.dm b/code/game/machinery/newscaster/newscaster_machine.dm index 876317a1e2926..3e884f72694be 100644 --- a/code/game/machinery/newscaster/newscaster_machine.dm +++ b/code/game/machinery/newscaster/newscaster_machine.dm @@ -83,11 +83,13 @@ if(!(machine_stat & (NOPOWER|BROKEN))) var/state = "[base_icon_state]_[GLOB.news_network.wanted_issue.active ? "wanted" : "normal"]" . += mutable_appearance(icon, state) - . += emissive_appearance(icon, state, alpha = src.alpha) + . += 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, "[base_icon_state]_alert") - . += emissive_appearance(icon, "[base_icon_state]_alert", alpha = src.alpha) + . += 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) diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index 26558957db448..2b323f3dcaf75 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -104,7 +104,8 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) screen_state = "[base_icon_state]0" . += mutable_appearance(icon, screen_state) - . += emissive_appearance(icon, screen_state, alpha = src.alpha) + . += emissive_appearance(icon, screen_state, layer, alpha = src.alpha) + ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY) /obj/machinery/requests_console/Initialize(mapload) . = ..()