Skip to content

Commit

Permalink
Adds a HUD text timer for both hive collapse and nuke (#13426)
Browse files Browse the repository at this point in the history
* Pretty much works, just gotta make it into a element

* Done and added it to hive collapse too

* Need to stop including map changes

* Orphaning wasn't done properly, need to fix signal overwrites

* Fixes globsigs overwriting themselves due to how there is only once instance of a element per type

* Did not know i needed this

* Accidental change

* Forgot a SIGNAL_HANDLER

* Not sure if it ever really applied for multiple before, whoops

* Appears to work perfectly!

* Removed some commented out code

* Not xeno only anymore

* Forgot DME changes

* Basically redid it to have the screen object be applied on every client

* Removed some old code that's not needed anymore

* Reviews

* More cleanup

* Works now, just need to test every part of it

* done and tested, added the safety for the public func

* Commented code

* removes unnecesary changes

* Somehow missed this other space

* Autodocs for variables?

* @TiviPlus reviews

* more review stuff i missed

* autodoc

* timer_mobs uses weakrefs again

* Doesn't need to be a empty list

* Forgot to add proper hive removal handling

* replacetextEx unfortunately does not return null if it fails to find what it wants

* Whoops wrong var

* Makes the screen timer not runtime if it has no list of mobs

* i forgot to fix this, Fuck

* += to a not a list simply sets it, fun!

* Implements self destruct timer too

* Moved the timers more to the right, and made them not stack on eachother

* Review tweaks
  • Loading branch information
Arturlang authored Jul 31, 2023
1 parent ea547b6 commit 9331072
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 17 deletions.
2 changes: 2 additions & 0 deletions code/__DEFINES/dcs/signals.dm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#define COMSIG_GLOB_NUKE_DIFFUSED "!nuke_diffused"
#define COMSIG_GLOB_DISK_GENERATED "!disk_produced"

#define COMSIG_GLOB_SHIP_SELF_DESTRUCT_ACTIVATED "!ship_self_destruct_activated"

/// from /obj/machinery/setAnchored(): (machine, anchoredstate)
#define COMSIG_GLOB_MACHINERY_ANCHORED_CHANGE "!machinery_anchored_change"

Expand Down
128 changes: 128 additions & 0 deletions code/_onclick/hud/screen_objects/text_objects.dm
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,131 @@
screen_loc = "CENTER-7,CENTER-7"
maptext_height = 480
maptext_width = 480

/// A screen object that shows the time left on a timer
/atom/movable/screen/text/screen_timer
screen_loc = "CENTER-7,CENTER-7"
/// Left side of the HTML tag for maptext, style is also included
var/maptext_style_left = "<span class='maptext' style=font-size:16pt;text-align:center; align='top'>"
/// End tag of the HTML tag for maptext
var/maptext_style_right = "</span>"
/// The actual displayed content of the maptext, use ${timer}, and it'll be replaced with the time left
var/maptext_string
/// Timer ID that we're tracking, the time left of this is displayed as maptext
var/timer_id
/// The list of mobs that we're attached to, and care about
var/list/timer_mobs = list()

/atom/movable/screen/text/screen_timer/Initialize(
mapload,
list/mobs,
timer,
text,
offset_x = 150,
offset_y = -70,
style_start,
style_end,
)
. = ..()

if(!islist(mobs) && mobs)
mobs = list(mobs)
// Copy the list just in case the arguments list is a list we don't want to modify
if(length(mobs))
mobs = mobs.Copy()
if(!timer)
stack_trace("Invalid timer for screen nuke timer!")
return INITIALIZE_HINT_QDEL
if(style_start)
maptext_style_left = style_start
if(style_end)
maptext_style_right = style_end
maptext_string = text
timer_id = timer
maptext_x = offset_x
maptext_y = offset_y
update_maptext()
if(length(mobs))
apply_to(mobs)

/atom/movable/screen/text/screen_timer/process()
if(!timeleft(timer_id))
delete_self()
return
update_maptext()

/// Adds the object to the client.screen of all mobs in the list, and registers the needed signals
/atom/movable/screen/text/screen_timer/proc/apply_to(list/mobs)
if(!islist(mobs))
if(!mobs)
return
mobs = list(mobs)
if(!length(timer_mobs) && length(mobs))
START_PROCESSING(SSprocessing, src)
for(var/player in mobs)
if(player in timer_mobs)
continue
if(istype(player, /datum/weakref))
var/datum/weakref/ref = player
player = ref.resolve()
attach(player)
RegisterSignal(player, COMSIG_MOB_LOGIN, PROC_REF(attach))
timer_mobs += WEAKREF(player)

/// Removes the object from the client.screen of all mobs in the list, and unregisters the needed signals, while also stopping processing if there's no more mobs in the screen timers mob list
/atom/movable/screen/text/screen_timer/proc/remove_from(list/mobs)
if(!islist(mobs))
if(!mobs)
return
mobs = list(mobs)
for(var/player in mobs)
UnregisterSignal(player, COMSIG_MOB_LOGIN)
if(player in timer_mobs)
timer_mobs -= player
if(istype(player, /datum/weakref))
var/datum/weakref/ref = player
player = ref.resolve()
de_attach(player)
if(!length(timer_mobs))
STOP_PROCESSING(SSprocessing, src)

/// Updates the maptext to show the current time left on the timer
/atom/movable/screen/text/screen_timer/proc/update_maptext()
var/time_formatted = time2text(timeleft(timer_id), "mm:ss")
var/timer_text = replacetextEx(maptext_string, "${timer}", time_formatted)
// If we don't find ${timer} in the string, just use the time formatted
var/result_text = "[maptext_style_left][timer_text][maptext_style_right]"
maptext = result_text

/// Adds the object to the client.screen of the mob, or removes it if add_to_screen is FALSE
/atom/movable/screen/text/screen_timer/proc/attach(mob/source, add_to_screen = TRUE)
SIGNAL_HANDLER
if(!source?.client)
return
var/client/client = source.client
// this checks if the screen is already added or removed
if(add_to_screen == (src in client.screen))
return
if(!ismob(source))
CRASH("Invalid source passed to screen_timer/attach()!")
if(add_to_screen)
client.screen += src
else
client.screen -= src

/// Signal handler to run attach with specific args
/atom/movable/screen/text/screen_timer/proc/de_attach(mob/source)
SIGNAL_HANDLER
attach(source, FALSE)

/// Mainly a signal handler so we can run qdel()
/atom/movable/screen/text/screen_timer/proc/delete_self()
SIGNAL_HANDLER
// I noticed in testing that even when qdel() is run, it still keeps running processing, even though it should have stopped processing due to running Destroy
STOP_PROCESSING(SSprocessing, src)
qdel(src)

/atom/movable/screen/text/screen_timer/Destroy()
. = ..()
remove_from(timer_mobs)
STOP_PROCESSING(SSprocessing, src)
5 changes: 4 additions & 1 deletion code/game/objects/machinery/nuclearbomb.dm
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
RegisterSignal(SSdcs, COMSIG_GLOB_DROPSHIP_HIJACKED, PROC_REF(disable_on_hijack))

/obj/machinery/nuclearbomb/Destroy()
if(timer_enabled)
disable()
GLOB.nuke_list -= src
QDEL_NULL(countdown)
return ..()
Expand All @@ -57,11 +59,12 @@
/obj/machinery/nuclearbomb/proc/enable()
GLOB.active_nuke_list += src
countdown.start()
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NUKE_START, src)
notify_ghosts("[usr] enabled the [src], it has [round(time MILLISECONDS)] seconds on the timer.", source = src, action = NOTIFY_ORBIT, extra_large = TRUE)
timer_enabled = TRUE
timer = addtimer(CALLBACK(src, PROC_REF(explode)), time, TIMER_STOPPABLE)
update_minimap_icon()
// The timer is needed for when the signal is sent
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NUKE_START, src)

///Disables nuke timer
/obj/machinery/nuclearbomb/proc/disable()
Expand Down
9 changes: 7 additions & 2 deletions code/game/objects/machinery/self_destruct.dm
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
var/marine_only_activate = TRUE
///When the self destruct sequence was initiated
var/started_at = 0

/// Timer mainly used for hud timers
var/timer


/obj/machinery/self_destruct/Initialize(mapload)
. = ..()
Expand Down Expand Up @@ -64,7 +66,7 @@
data["dest_status"] = active_state
if(active_state == SELF_DESTRUCT_MACHINE_ARMED)
data["detonation_pcent"] = min(round(((world.time - started_at) / (SELF_DESTRUCT_ROD_STARTUP_TIME)), 0.01), 1) // percentage of time left to detonation
data["detonation_time"] = DisplayTimeText(max(0, (SELF_DESTRUCT_ROD_STARTUP_TIME) - (world.time - started_at)), 1) //amount of time left to detonation
data["detonation_time"] = DisplayTimeText(timeleft(timer), 1) //amount of time left to detonation
else
data["detonation_pcent"] = 0
data["detonation_time"] = "Inactive"
Expand All @@ -85,6 +87,9 @@
I.activate_time = world.time
started_at = world.time
SSevacuation.initiate_self_destruct()
timer = addtimer(VARSET_CALLBACK(src, timer, null), SELF_DESTRUCT_ROD_STARTUP_TIME, TIMER_DELETE_ME|TIMER_STOPPABLE)

SEND_GLOBAL_SIGNAL(COMSIG_GLOB_SHIP_SELF_DESTRUCT_ACTIVATED, src)
. = TRUE

if("dest_trigger")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,6 @@
)
use_state_flags = XACT_USE_LYING

//Parameters used when displaying hive message to all xenos
/atom/movable/screen/text/screen_text/queen_order
maptext_height = 128 //Default 64 doubled in height
maptext_width = 456 //Default 480 shifted right by 12
maptext_x = 12 //Half of 24
maptext_y = -64 //Shifting expanded map text downwards to display below buttons.
screen_loc = "LEFT,TOP-3"

letters_per_update = 2
fade_out_delay = 5 SECONDS
style_open = "<span class='maptext' style=font-size:16pt;text-align:center valign='top'>"
style_close = "</span>"

/datum/action/xeno_action/hive_message/action_activate()
var/mob/living/carbon/xenomorph/queen/Q = owner

Expand Down
29 changes: 28 additions & 1 deletion code/modules/mob/living/carbon/xenomorph/hive_datum.dm
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

///Reference to upgrades available and purchased by this hive.
var/datum/hive_purchases/purchases = new
/// The nuke HUD timer datum, shown on each xeno's screen
var/atom/movable/screen/text/screen_timer/nuke_hud_timer

// ***************************************
// *********** Init
Expand All @@ -50,6 +52,7 @@

SSdirection.set_leader(hivenumber, null)

RegisterSignals(SSdcs, list(COMSIG_GLOB_NUKE_START, COMSIG_GLOB_SHIP_SELF_DESTRUCT_ACTIVATED), PROC_REF(setup_nuke_hud_timer))
// ***************************************
// *********** UI for Hive Status
// ***************************************
Expand Down Expand Up @@ -387,6 +390,7 @@
add_to_lists(X)

post_add(X)
nuke_hud_timer?.apply_to(X)
return TRUE

// helper function
Expand Down Expand Up @@ -484,6 +488,7 @@
else
remove_from_lists(X)

nuke_hud_timer?.remove_from(X)
post_removal(X)
return TRUE

Expand Down Expand Up @@ -533,6 +538,17 @@
hivenumber = XENO_HIVE_NONE // failsafe value
reference_hive.update_tier_limits() //Update our tier limits.

/datum/hive_status/proc/setup_nuke_hud_timer(source, thing)
SIGNAL_HANDLER
var/obj/machinery/nuclearbomb/nuke = thing
if(!nuke.timer)
CRASH("hive_status's setup_nuke_hud_timer called with invalid nuke object")
nuke_hud_timer = new(null, get_all_xenos() , nuke.timer, "Nuke ACTIVE: ${timer}")

/datum/hive_status/Destroy(force, ...)
. = ..()
UnregisterSignal(SSdcs, COMSIG_GLOB_NUKE_START)

/mob/living/carbon/xenomorph/queen/remove_from_hive() // override to ensure proper queen/hive behaviour
var/datum/hive_status/hive_removed_from = hive
if(hive_removed_from.living_xeno_queen == src)
Expand Down Expand Up @@ -861,6 +877,16 @@ to_chat will check for valid clients itself already so no need to double check f
// ***************************************
/datum/hive_status/normal // subtype for easier typechecking and overrides
hive_flags = HIVE_CAN_HIJACK
/// Timer ID for the orphan hive timer
var/atom/movable/screen/text/screen_timer/orphan_hud_timer

/datum/hive_status/normal/add_xeno(mob/living/carbon/xenomorph/X)
. = ..()
orphan_hud_timer?.apply_to(X)

/datum/hive_status/normal/remove_xeno(mob/living/carbon/xenomorph/X)
. = ..()
orphan_hud_timer?.remove_from(X)

/datum/hive_status/normal/handle_ruler_timer()
if(!isinfestationgamemode(SSticker.mode)) //Check just need for unit test
Expand All @@ -875,14 +901,15 @@ to_chat will check for valid clients itself already so no need to double check f
if(D.orphan_hive_timer)
deltimer(D.orphan_hive_timer)
D.orphan_hive_timer = null
QDEL_NULL(orphan_hud_timer)
return

if(D.orphan_hive_timer)
return


D.orphan_hive_timer = addtimer(CALLBACK(D, TYPE_PROC_REF(/datum/game_mode, orphan_hivemind_collapse)), NUCLEAR_WAR_ORPHAN_HIVEMIND, TIMER_STOPPABLE)

orphan_hud_timer = new(null, get_all_xenos(), D.orphan_hive_timer, "Orphan Hivemind Collapse: ${timer}", 150, -80)

/datum/hive_status/normal/burrow_larva(mob/living/carbon/xenomorph/larva/L)
if(!is_ground_level(L.z))
Expand Down
13 changes: 13 additions & 0 deletions code/modules/screen_alert/hive_message.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

//Parameters used when displaying hive message to all xenos
/atom/movable/screen/text/screen_text/queen_order
maptext_height = 128 //Default 64 doubled in height
maptext_width = 456 //Default 480 shifted right by 12
maptext_x = 12 //Half of 24
maptext_y = -64 //Shifting expanded map text downwards to display below buttons.
screen_loc = "LEFT,TOP-3"

letters_per_update = 2
fade_out_delay = 5 SECONDS
style_open = "<span class='maptext' style=font-size:16pt;text-align:center valign='top'>"
style_close = "</span>"
1 change: 1 addition & 0 deletions tgmc.dme
Original file line number Diff line number Diff line change
Expand Up @@ -1757,6 +1757,7 @@
#include "code\modules\requisitions\supply_export.dm"
#include "code\modules\screen_alert\_screen_alert.dm"
#include "code\modules\screen_alert\command_alert.dm"
#include "code\modules\screen_alert\hive_message.dm"
#include "code\modules\screen_alert\misc_alert.dm"
#include "code\modules\security_levels\keycard_authentication.dm"
#include "code\modules\shuttle\computer.dm"
Expand Down

0 comments on commit 9331072

Please sign in to comment.