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 {"