Skip to content

Commit

Permalink
Adds Custom Announcement Dividers (#79071)
Browse files Browse the repository at this point in the history
This ports a whole bunch of various PRs and commits from
https://github.com/effigy-se/effigy-se , with heavy refactoring to keep
it fresh for /tg/'s code standards.

## About The Pull Request

The whole slew of announcement touchups lately (as in #78995
(37db1ec) / #79052
(12308db)) have made me realize how
much this stuff sucks. The author of these new spans was advertising
these in coding general, so I sat down and coded it. Look at the spans,
they're much nicer than what we had going on:

(ignore the capitalized alert status names, this was removed)

<details>
<summary>Dark Mode</summary>


![image](https://github.com/tgstation/tgstation/assets/34697715/107b8efb-b7a1-41ff-9d16-358c4dc3738d)

![image](https://github.com/tgstation/tgstation/assets/34697715/9e730dfe-7ba3-4edd-96bb-0630fe5e85cf)
</details>

<details>
<summary>Light Mode</summary>


![image](https://github.com/tgstation/tgstation/assets/34697715/57f642f9-ee17-4b16-8027-00a9350e9059)

![image](https://github.com/tgstation/tgstation/assets/34697715/b28b7f49-fd4f-420a-9313-e16b9781c07c)
</details>

This PR also features

* Major announcement code handling cleanup and refactor! There was a lot
of copypasta so let's distill it all down into one proc
* Better cacheing! We were doing a shit load of new string generation
needlessly! That's fixed now.
* Better string concatenation! Lists are better for string tree reasons.
It still works just as well, as you can see from the screenshots above.
Best of all, no fucking `<br>` dogshit everywhere!
* We don't use string equivalency in order to figure out the "type" of
an announcement. It's all defines now. This was a bonus that I just
coded in since it irritated me.
* Minor spellcheck of "announcement".
* All of our HTML string mangling stuff is now all span macros! I love
macros.

## Why It's Good For The Game

In the same vein of adding examine blocks (#67937
(b864589)) because old examinations
tended to blend in with the chat and everything chat-wise used to suck
really hard- I think this is a really nice way to draw attention to
announcements in the chat box without needing a shit load of line breaks
that just really look ugly and have no real consistency. You can look at
the PRs/commits I linked above for an idea of just how ugly it could be
getting.

I haven't audited every announcement in this PR, we can tweak this down
the line.

## Changelog

:cl: LT3, san7890
add: Announcements have gotten a fresh coat of paint! They should be
popping with splendid new colors and should have a lot less ugly
linebreaks, while still managing to keep your attention at the screen.
/:cl:

I know we didn't need to port all the CSS themes but I added them
anyways in case admins wanna have some fun.
There can probably be more code improvements, just figured I'd crack it
out while I had time.
The colors also seem fine, let me know if we need more redness or
something. It's okay for stuff to be toned down a bit imo, but that
should be done after a hot second.

---------

Co-authored-by: lessthanthree <83487515+lessthnthree@users.noreply.github.com>
  • Loading branch information
san7890 and lessthnthree committed Oct 20, 2023
1 parent 00ae97e commit 30bac3a
Show file tree
Hide file tree
Showing 10 changed files with 266 additions and 67 deletions.
7 changes: 7 additions & 0 deletions code/__DEFINES/announcements.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Priority-type announcement messages for `priority_announcement()`
/// Prefix this announcement with "Priority Announcement"
#define ANNOUNCEMENT_TYPE_PRIORITY "Priority"
/// Make it sound like it's coming from the Captain
#define ANNOUNCEMENT_TYPE_CAPTAIN "Captain"
/// Make it sound like it's coming from the Syndicate
#define ANNOUNCEMENT_TYPE_SYNDICATE "Syndicate"
145 changes: 102 additions & 43 deletions code/__HELPERS/priority_announce.dm
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
// please don't use these defines outside of this file in order to ensure a unified framework. unless you have a really good reason to make them global, then whatever

// these four are just text spans that furnish the TEXT itself with the appropriate CSS classes
#define MAJOR_ANNOUNCEMENT_TITLE(string) ("<span class='major_announcement_title'>" + string + "</span>")
#define MAJOR_ANNOUNCEMENT_TEXT(string) ("<span class='major_announcement_text'>" + string + "</span>")
#define MINOR_ANNOUNCEMENT_TITLE(string) ("<span class='minor_announcement_title'>" + string + "</span>")
#define MINOR_ANNOUNCEMENT_TEXT(string) ("<span class='minor_announcement_text'>" + string + "</span>")

// these two are the ones that actually give the striped background
#define CHAT_ALERT_DEFAULT_SPAN(string) ("<div class='chat_alert_default'>" + string + "</div>")
#define CHAT_ALERT_COLORED_SPAN(color, string) ("<div class='chat_alert_" + color + "'>" + string + "</div>")

/**
* Make a big red text announcement to
*
Expand All @@ -13,7 +25,7 @@
* * text - required, the text to announce
* * title - optional, the title of the announcement.
* * sound - optional, the sound played accompanying the announcement
* * type - optional, the type of the announcement, for some "preset" announcement templates. "Priority", "Captain", "Syndicate Captain"
* * type - optional, the type of the announcement, for some "preset" announcement templates. See __DEFINES/announcements.dm
* * sender_override - optional, modifies the sender of the announcement
* * has_important_message - is this message critical to the game (and should not be overridden by station traits), or not
* * players - a list of all players to send the message to. defaults to all players (not including new players)
Expand All @@ -31,55 +43,44 @@
if(!length(text))
return

var/announcement
var/list/announcement_strings = list()

if(!sound)
sound = SSstation.announcer.get_rand_alert_sound()
else if(SSstation.announcer.event_sounds[sound])
sound = SSstation.announcer.event_sounds[sound]

announcement += "<br>"

if(type == "Priority")
announcement += "[span_priorityannounce("<u>Priority Announcement</u>")]"
if (title && length(title) > 0)
announcement += "[span_prioritytitle("<br>[title]")]"
else if(type == "Captain")
announcement += "[span_priorityannounce("<u>Captain Announces</u>")]"
GLOB.news_network.submit_article(text, "Captain's Announcement", "Station Announcements", null)
else if(type == "Syndicate Captain")
announcement += "[span_priorityannounce("<u>Syndicate Captain Announces</u>")]"

else
if(!sender_override)
announcement += "[span_priorityannounce("<u>[command_name()] Update</u>")]"
var/header
switch(type)
if(ANNOUNCEMENT_TYPE_PRIORITY)
header = MAJOR_ANNOUNCEMENT_TITLE("Priority Announcement")
if(length(title) > 0)
header += MINOR_ANNOUNCEMENT_TITLE(title)
if(ANNOUNCEMENT_TYPE_CAPTAIN)
header = MAJOR_ANNOUNCEMENT_TITLE("Captain's Announcement")
GLOB.news_network.submit_article(text, "Captain's Announcement", "Station Announcements", null)
if(ANNOUNCEMENT_TYPE_SYNDICATE)
header = MAJOR_ANNOUNCEMENT_TITLE("Syndicate Captain's Announcement")
else
announcement += "[span_priorityannounce("<u>[sender_override]</u>")]"
if (title && length(title) > 0)
announcement += "[span_prioritytitle("<br>[title]")]"
header += generate_unique_announcement_header(title, sender_override)

if(!sender_override)
if(title == "")
GLOB.news_network.submit_article(text, "Central Command Update", "Station Announcements", null)
else
GLOB.news_network.submit_article(title + "<br><br>" + text, "Central Command", "Station Announcements", null)
announcement_strings += header

///If the announcer overrides alert messages, use that message.
if(SSstation.announcer.custom_alert_message && !has_important_message)
announcement += "[span_priorityalert("<br>[SSstation.announcer.custom_alert_message]<br>")]"
announcement_strings += SSstation.announcer.custom_alert_message
else
announcement += "[span_priorityalert("<br>[text]<br>")]"
announcement_strings += MAJOR_ANNOUNCEMENT_TEXT(text)

announcement += "<br>"
var/finalized_announcement = CHAT_ALERT_DEFAULT_SPAN(jointext(announcement_strings, "<br>"))

if(!players)
players = GLOB.player_list
dispatch_announcement_to_players(finalized_announcement, players, sound)

var/sound_to_play = sound(sound)
for(var/mob/target in players)
if(!isnewplayer(target) && target.can_hear())
to_chat(target, announcement)
if(target.client.prefs.read_preference(/datum/preference/toggle/sound_announcements))
SEND_SOUND(target, sound_to_play)
if(isnull(sender_override))
if(length(title) > 0)
GLOB.news_network.submit_article(title + "<br><br>" + text, "Central Command", "Station Announcements", null)
else
GLOB.news_network.submit_article(text, "Central Command Update", "Station Announcements", null)

/proc/print_command_report(text = "", title = null, announce=TRUE)
if(!title)
Expand Down Expand Up @@ -107,25 +108,83 @@
* sound_override - optional, use the passed sound file instead of the default notice sounds.
* should_play_sound - Whether the notice sound should be played or not.
*/
/proc/minor_announce(message, title = "Attention:", alert, html_encode = TRUE, list/players = null, sound_override = null, should_play_sound = TRUE)
/proc/minor_announce(message, title = "Attention:", alert = FALSE, html_encode = TRUE, list/players = null, sound_override = null, should_play_sound = TRUE)
if(!message)
return

if (html_encode)
title = html_encode(title)
message = html_encode(message)

var/list/minor_announcement_strings = list()
minor_announcement_strings += MINOR_ANNOUNCEMENT_TITLE(title)
minor_announcement_strings += MINOR_ANNOUNCEMENT_TEXT(message)

var/finalized_announcement = CHAT_ALERT_DEFAULT_SPAN(jointext(minor_announcement_strings, "<br>"))

var/custom_sound = sound_override || (alert ? 'sound/misc/notice1.ogg' : 'sound/misc/notice2.ogg')
dispatch_announcement_to_players(finalized_announcement, players, custom_sound, should_play_sound)

/// Sends an announcement about the level changing to players. Uses the passed in datum and the subsystem's previous security level to generate the message.
/proc/level_announce(datum/security_level/selected_level, previous_level_number)
var/current_level_number = selected_level.number_level
var/current_level_name = selected_level.name
var/current_level_color = selected_level.announcement_color
var/current_level_sound = selected_level.sound

var/title
var/message

if(current_level_number > previous_level_number)
title = "Attention! Security level elevated to [current_level_name]:"
message = selected_level.elevating_to_announcement
else
title = "Attention! Security level lowered to [current_level_name]:"
message = selected_level.lowering_to_announcement

var/list/level_announcement_strings = list()
level_announcement_strings += MINOR_ANNOUNCEMENT_TITLE(title)
level_announcement_strings += MINOR_ANNOUNCEMENT_TEXT(message)

var/finalized_announcement = CHAT_ALERT_COLORED_SPAN(current_level_color, jointext(level_announcement_strings, "<br>"))

dispatch_announcement_to_players(finalized_announcement, GLOB.player_list, current_level_sound)

/// Proc that just generates a custom header based on variables fed into `priority_announce()`
/// Will return a string.
/proc/generate_unique_announcement_header(title, sender_override)
var/list/returnable_strings = list()
if(isnull(sender_override))
returnable_strings += MAJOR_ANNOUNCEMENT_TITLE("[command_name()] Update")
else
returnable_strings += MAJOR_ANNOUNCEMENT_TITLE(sender_override)

if(length(title) > 0)
returnable_strings += MINOR_ANNOUNCEMENT_TITLE(title)

return jointext(returnable_strings, "<br>")

/// Proc that just dispatches the announcement to our applicable audience. Only the announcement is a mandatory arg.
/proc/dispatch_announcement_to_players(announcement, list/players, sound_override = null, should_play_sound = TRUE)
if(!players)
players = GLOB.player_list

var/sound_to_play = !isnull(sound_override) ? sound_override : 'sound/misc/notice2.ogg'

for(var/mob/target in players)
if(isnewplayer(target))
if(isnewplayer(target) || !target.can_hear())
continue
if(!target.can_hear())

to_chat(target, announcement)
if(!should_play_sound)
continue

to_chat(target, "<br>[span_minorannounce(title)]<br>")
to_chat(target, "[span_minoralert(message)]<br><br><br>")
if(should_play_sound && target.client?.prefs.read_preference(/datum/preference/toggle/sound_announcements))
var/sound_to_play = sound_override || (alert ? 'sound/misc/notice1.ogg' : 'sound/misc/notice2.ogg')
if(target.client?.prefs.read_preference(/datum/preference/toggle/sound_announcements))
SEND_SOUND(target, sound(sound_to_play))

#undef MAJOR_ANNOUNCEMENT_TITLE
#undef MAJOR_ANNOUNCEMENT_TEXT
#undef MINOR_ANNOUNCEMENT_TITLE
#undef MINOR_ANNOUNCEMENT_TEXT
#undef CHAT_ALERT_DEFAULT_SPAN
#undef CHAT_ALERT_COLORED_SPAN
4 changes: 2 additions & 2 deletions code/controllers/subsystem/communications.dm
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ SUBSYSTEM_DEF(communications)
else
var/list/message_data = user.treat_message(input)
if(syndicate)
priority_announce(html_decode(message_data["message"]), null, 'sound/misc/announce_syndi.ogg', "Syndicate Captain", has_important_message = TRUE, players = players)
priority_announce(html_decode(message_data["message"]), null, 'sound/misc/announce_syndi.ogg', ANNOUNCEMENT_TYPE_SYNDICATE, has_important_message = TRUE, players = players)
else
priority_announce(html_decode(message_data["message"]), null, 'sound/misc/announce.ogg', "Captain", has_important_message = TRUE, players = players)
priority_announce(html_decode(message_data["message"]), null, 'sound/misc/announce.ogg', ANNOUNCEMENT_TYPE_CAPTAIN, has_important_message = TRUE, players = players)
COOLDOWN_START(src, nonsilicon_message_cooldown, COMMUNICATION_COOLDOWN)
user.log_talk(input, LOG_SAY, tag="priority announcement")
message_admins("[ADMIN_LOOKUPFLW(user)] has made a priority announcement.")
Expand Down
14 changes: 1 addition & 13 deletions code/controllers/subsystem/security_level.dm
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ SUBSYSTEM_DEF(security_level)
if(!selected_level)
CRASH("set_level was called with an invalid security level([new_level])")

announce_security_level(selected_level) // We want to announce BEFORE updating to the new level
level_announce(selected_level, current_security_level.number_level) // We want to announce BEFORE updating to the new level

SSsecurity_level.current_security_level = selected_level

Expand All @@ -56,18 +56,6 @@ SUBSYSTEM_DEF(security_level)
SSnightshift.check_nightshift()
SSblackbox.record_feedback("tally", "security_level_changes", 1, selected_level.name)

/**
* Handles announcements of the newly set security level
*
* Arguments:
* * selected_level - The new security level that has been set
*/
/datum/controller/subsystem/security_level/proc/announce_security_level(datum/security_level/selected_level)
if(selected_level.number_level > current_security_level.number_level) // We are elevating to this level.
minor_announce(selected_level.elevating_to_announcemnt, "Attention! Security level elevated to [selected_level.name]:", sound_override = selected_level.sound)
else // Going down
minor_announce(selected_level.lowering_to_announcement, "Attention! Security level lowered to [selected_level.name]:", sound_override = selected_level.sound)

/**
* Returns the current security level as a number
*/
Expand Down
4 changes: 2 additions & 2 deletions code/controllers/subsystem/shuttle.dm
Original file line number Diff line number Diff line change
Expand Up @@ -505,13 +505,13 @@ SUBSYSTEM_DEF(shuttle)
emergency.sound_played = FALSE
priority_announce("Hostile environment detected. \
Departure has been postponed indefinitely pending \
conflict resolution.", null, 'sound/misc/notice1.ogg', "Priority")
conflict resolution.", null, 'sound/misc/notice1.ogg', ANNOUNCEMENT_TYPE_PRIORITY)
if(!emergency_no_escape && (emergency.mode == SHUTTLE_STRANDED))
emergency.mode = SHUTTLE_DOCKED
emergency.setTimer(emergency_dock_time)
priority_announce("Hostile environment resolved. \
You have 3 minutes to board the Emergency Shuttle.",
null, ANNOUNCER_SHUTTLEDOCK, "Priority")
null, ANNOUNCER_SHUTTLEDOCK, ANNOUNCEMENT_TYPE_PRIORITY)

//try to move/request to dock_home if possible, otherwise dock_away. Mainly used for admin buttons
/datum/controller/subsystem/shuttle/proc/toggleShuttle(shuttle_id, dock_home, dock_away, timed)
Expand Down
10 changes: 8 additions & 2 deletions code/modules/security_levels/security_level_datums.dm
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
/datum/security_level
/// The name of this security level.
var/name = "not set"
/// The color of our announcement divider.
var/announcement_color = "default"
/// The numerical level of this security level, see defines for more information.
var/number_level = -1
/// The sound that we will play when this security level is set
Expand All @@ -22,7 +24,7 @@
/// Our announcement when lowering to this level
var/lowering_to_announcement
/// Our announcement when elevating to this level
var/elevating_to_announcemnt
var/elevating_to_announcement
/// Our configuration key for lowering to text, if set, will override the default lowering to announcement.
var/lowering_to_configuration_key
/// Our configuration key for elevating to text, if set, will override the default elevating to announcement.
Expand All @@ -33,7 +35,7 @@
if(lowering_to_configuration_key) // I'm not sure about you, but isn't there an easier way to do this?
lowering_to_announcement = global.config.Get(lowering_to_configuration_key)
if(elevating_to_configuration_key)
elevating_to_announcemnt = global.config.Get(elevating_to_configuration_key)
elevating_to_announcement = global.config.Get(elevating_to_configuration_key)

/**
* GREEN
Expand All @@ -42,6 +44,7 @@
*/
/datum/security_level/green
name = "green"
announcement_color = "green"
sound = 'sound/misc/notice2.ogg' // Friendly beep
number_level = SEC_LEVEL_GREEN
lowering_to_configuration_key = /datum/config_entry/string/alert_green
Expand All @@ -54,6 +57,7 @@
*/
/datum/security_level/blue
name = "blue"
announcement_color = "blue"
sound = 'sound/misc/notice1.ogg' // Angry alarm
number_level = SEC_LEVEL_BLUE
lowering_to_configuration_key = /datum/config_entry/string/alert_blue_downto
Expand All @@ -67,6 +71,7 @@
*/
/datum/security_level/red
name = "red"
announcement_color = "red"
sound = 'sound/misc/notice3.ogg' // More angry alarm
number_level = SEC_LEVEL_RED
lowering_to_configuration_key = /datum/config_entry/string/alert_red_downto
Expand All @@ -80,6 +85,7 @@
*/
/datum/security_level/delta
name = "delta"
announcement_color = "purple"
sound = 'sound/misc/airraid.ogg' // Air alarm to signify importance
number_level = SEC_LEVEL_DELTA
elevating_to_configuration_key = /datum/config_entry/string/alert_delta
Expand Down
10 changes: 5 additions & 5 deletions code/modules/shuttle/emergency.dm
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@
else
SSshuttle.emergency_last_call_loc = null

priority_announce("The emergency shuttle has been called. [red_alert ? "Red Alert state confirmed: Dispatching priority shuttle. " : "" ]It will arrive in [timeLeft(600)] minutes.[reason][SSshuttle.emergency_last_call_loc ? "\n\nCall signal traced. Results can be viewed on any communications console." : "" ][SSshuttle.admin_emergency_no_recall ? "\n\nWarning: Shuttle recall subroutines disabled; Recall not possible." : ""]", null, ANNOUNCER_SHUTTLECALLED, "Priority")
priority_announce("The emergency shuttle has been called. [red_alert ? "Red Alert state confirmed: Dispatching priority shuttle. " : "" ]It will arrive in [timeLeft(600)] minutes.[reason][SSshuttle.emergency_last_call_loc ? "\n\nCall signal traced. Results can be viewed on any communications console." : "" ][SSshuttle.admin_emergency_no_recall ? "\n\nWarning: Shuttle recall subroutines disabled; Recall not possible." : ""]", null, ANNOUNCER_SHUTTLECALLED, ANNOUNCEMENT_TYPE_PRIORITY)

/obj/docking_port/mobile/emergency/cancel(area/signalOrigin)
if(mode != SHUTTLE_CALL)
Expand All @@ -373,7 +373,7 @@
SSshuttle.emergency_last_call_loc = signalOrigin
else
SSshuttle.emergency_last_call_loc = null
priority_announce("The emergency shuttle has been recalled.[SSshuttle.emergency_last_call_loc ? " Recall signal traced. Results can be viewed on any communications console." : "" ]", null, ANNOUNCER_SHUTTLERECALLED, "Priority")
priority_announce("The emergency shuttle has been recalled.[SSshuttle.emergency_last_call_loc ? " Recall signal traced. Results can be viewed on any communications console." : "" ]", null, ANNOUNCER_SHUTTLERECALLED, ANNOUNCEMENT_TYPE_PRIORITY)

SSticker.emergency_reason = null

Expand Down Expand Up @@ -462,7 +462,7 @@
mode = SHUTTLE_DOCKED
setTimer(SSshuttle.emergency_dock_time)
send2adminchat("Server", "The Emergency Shuttle has docked with the station.")
priority_announce("[SSshuttle.emergency] has docked with the station. You have [timeLeft(600)] minutes to board the Emergency Shuttle.", null, ANNOUNCER_SHUTTLEDOCK, "Priority")
priority_announce("[SSshuttle.emergency] has docked with the station. You have [timeLeft(600)] minutes to board the Emergency Shuttle.", null, ANNOUNCER_SHUTTLEDOCK, ANNOUNCEMENT_TYPE_PRIORITY)
ShuttleDBStuff()
addtimer(CALLBACK(src, PROC_REF(announce_shuttle_events)), 20 SECONDS)

Expand Down Expand Up @@ -514,7 +514,7 @@
mode = SHUTTLE_ESCAPE
launch_status = ENDGAME_LAUNCHED
setTimer(SSshuttle.emergency_escape_time * engine_coeff)
priority_announce("The Emergency Shuttle has left the station. Estimate [timeLeft(600)] minutes until the shuttle docks at Central Command.", null, null, "Priority")
priority_announce("The Emergency Shuttle has left the station. Estimate [timeLeft(600)] minutes until the shuttle docks at Central Command.", null, null, ANNOUNCEMENT_TYPE_PRIORITY)
INVOKE_ASYNC(SSticker, TYPE_PROC_REF(/datum/controller/subsystem/ticker, poll_hearts))
SSmapping.mapvote() //If no map vote has been run yet, start one.

Expand Down Expand Up @@ -579,7 +579,7 @@
mode = SHUTTLE_ESCAPE
launch_status = ENDGAME_LAUNCHED
setTimer(SSshuttle.emergency_escape_time)
priority_announce("The Emergency Shuttle is preparing for direct jump. Estimate [timeLeft(600)] minutes until the shuttle docks at Central Command.", null, null, "Priority")
priority_announce("The Emergency Shuttle is preparing for direct jump. Estimate [timeLeft(600)] minutes until the shuttle docks at Central Command.", null, null, ANNOUNCEMENT_TYPE_PRIORITY)

///Generate a list of events to run during the departure
/obj/docking_port/mobile/emergency/proc/setup_shuttle_events()
Expand Down
1 change: 1 addition & 0 deletions tgstation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "code\__DEFINES\airlock.dm"
#include "code\__DEFINES\alarm.dm"
#include "code\__DEFINES\alerts.dm"
#include "code\__DEFINES\announcements.dm"
#include "code\__DEFINES\anomaly.dm"
#include "code\__DEFINES\antagonists.dm"
#include "code\__DEFINES\apc_defines.dm"
Expand Down
Loading

0 comments on commit 30bac3a

Please sign in to comment.