diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index c5cef548bc099..c2cecc44153bb 100755 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -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" diff --git a/code/_onclick/hud/screen_objects/text_objects.dm b/code/_onclick/hud/screen_objects/text_objects.dm index 10c6afe19dcb4..f717461f715db 100644 --- a/code/_onclick/hud/screen_objects/text_objects.dm +++ b/code/_onclick/hud/screen_objects/text_objects.dm @@ -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 = "" + /// End tag of the HTML tag for maptext + var/maptext_style_right = "" + /// 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) diff --git a/code/game/objects/machinery/nuclearbomb.dm b/code/game/objects/machinery/nuclearbomb.dm index dfe72bae4fe83..a8ccd8271f5c9 100644 --- a/code/game/objects/machinery/nuclearbomb.dm +++ b/code/game/objects/machinery/nuclearbomb.dm @@ -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 ..() @@ -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() diff --git a/code/game/objects/machinery/self_destruct.dm b/code/game/objects/machinery/self_destruct.dm index cf125fe4e80be..827ac83cc8cf3 100644 --- a/code/game/objects/machinery/self_destruct.dm +++ b/code/game/objects/machinery/self_destruct.dm @@ -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) . = ..() @@ -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" @@ -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") diff --git a/code/modules/mob/living/carbon/xenomorph/castes/queen/abilities_queen.dm b/code/modules/mob/living/carbon/xenomorph/castes/queen/abilities_queen.dm index 936165405d397..46d24c38195d0 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/queen/abilities_queen.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/queen/abilities_queen.dm @@ -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 = "" - style_close = "" - /datum/action/xeno_action/hive_message/action_activate() var/mob/living/carbon/xenomorph/queen/Q = owner diff --git a/code/modules/mob/living/carbon/xenomorph/hive_datum.dm b/code/modules/mob/living/carbon/xenomorph/hive_datum.dm index c0a3f006426ff..53ee324463f43 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_datum.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_datum.dm @@ -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 @@ -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 // *************************************** @@ -387,6 +390,7 @@ add_to_lists(X) post_add(X) + nuke_hud_timer?.apply_to(X) return TRUE // helper function @@ -484,6 +488,7 @@ else remove_from_lists(X) + nuke_hud_timer?.remove_from(X) post_removal(X) return TRUE @@ -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) @@ -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 @@ -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)) diff --git a/code/modules/screen_alert/hive_message.dm b/code/modules/screen_alert/hive_message.dm new file mode 100644 index 0000000000000..e24d7ba96c316 --- /dev/null +++ b/code/modules/screen_alert/hive_message.dm @@ -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 = "" + style_close = "" diff --git a/tgmc.dme b/tgmc.dme index ba016b1a7aeb0..ec2545b9ab629 100755 --- a/tgmc.dme +++ b/tgmc.dme @@ -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"