diff --git a/code/controllers/subsystem/SSjobs.dm b/code/controllers/subsystem/SSjobs.dm index cd56d46c7f4..ec1df975cf8 100644 --- a/code/controllers/subsystem/SSjobs.dm +++ b/code/controllers/subsystem/SSjobs.dm @@ -529,8 +529,10 @@ SUBSYSTEM_DEF(jobs) if(istype(G) && !G.prescription) G.upgrade_prescription() H.update_nearsighted_effects() + if(joined_late || job.admin_only) H.create_log(MISC_LOG, "Spawned as \an [H.dna?.species ? H.dna.species : "Undefined species"] named [H]. [joined_late ? "Joined during the round" : "Roundstart joined"] as job: [rank].") + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/controller/subsystem/jobs, show_location_blurb), H.client, H.mind), 1 SECONDS) //Moment for minds to boot up / people to load in return H if(late_arrivals_spawning) H.forceMove(pick(GLOB.latejoin)) @@ -545,6 +547,7 @@ SUBSYSTEM_DEF(jobs) H.Sleeping(5 SECONDS) H.Drunk((2 / liver_multiplier) MINUTES) H.create_log(MISC_LOG, "Spawned as \an [H.dna?.species ? H.dna.species : "Undefined species"] named [H]. Roundstart joined as job: [rank].") + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/controller/subsystem/jobs, show_location_blurb), H.client, H.mind), 1 SECONDS) //Moment for minds to boot up / people to load in return H /datum/controller/subsystem/jobs/proc/LoadJobs(highpop = FALSE) //ran during round setup, reads info from jobs list diff --git a/code/controllers/subsystem/SSticker.dm b/code/controllers/subsystem/SSticker.dm index 2f0879f2560..8713ce74d49 100644 --- a/code/controllers/subsystem/SSticker.dm +++ b/code/controllers/subsystem/SSticker.dm @@ -715,6 +715,8 @@ SUBSYSTEM_DEF(ticker) if(delay_end) to_chat(world, "An admin has delayed the round end.") return + if(delay) + INVOKE_ASYNC(src, TYPE_PROC_REF(/datum/controller/subsystem/ticker, show_server_restart_blurb), reason) if(!isnull(delay)) // Delay time was present. Use that. diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index c537489e3d1..9b859168b97 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -36,6 +36,19 @@ GLOBAL_LIST_EMPTY(antagonists) /// The url page name for this antagonist, appended to the end of the wiki url in the form of: [GLOB.configuration.url.wiki_url]/index.php/[wiki_page_name] var/wiki_page_name + //Blurb stuff + /// Intro Blurbs text colour + var/blurb_text_color = COLOR_BLACK + /// Intro Blurbs outline width + var/blurb_text_outline_width = 0 + /// Intro Blurb Font + var/blurb_font = "Courier New" + //Backgrount + var/blurb_r = 0 + var/blurb_g = 0 + var/blurb_b = 0 + var/blurb_a = 0 + /datum/antagonist/New() GLOB.antagonists += src objective_holder = new(src) @@ -392,3 +405,6 @@ GLOBAL_LIST_EMPTY(antagonists) /datum/antagonist/proc/on_cryo() return +/// This is the custom blurb message used on login for an antagonist. +/datum/antagonist/proc/custom_blurb() + return FALSE diff --git a/code/modules/antagonists/changeling/datum_changeling.dm b/code/modules/antagonists/changeling/datum_changeling.dm index caadf62b167..f8c39e74fd9 100644 --- a/code/modules/antagonists/changeling/datum_changeling.dm +++ b/code/modules/antagonists/changeling/datum_changeling.dm @@ -48,7 +48,8 @@ var/datum/action/changeling/sting/chosen_sting /// If the changeling is in the process of regenerating from their fake death. var/regenerating = FALSE - + blurb_text_color = COLOR_PURPLE + blurb_text_outline_width = 1 /datum/antagonist/changeling/New() ..() @@ -429,3 +430,6 @@ /proc/ischangeling(mob/M) return M.mind?.has_antag_datum(/datum/antagonist/changeling) + +/datum/antagonist/changeling/custom_blurb() + return "We awaken on the [station_name()], [get_area_name(owner.current, TRUE)]...\nWe have our tasks to attend to..." diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 2d2988dc585..a33f14f52dd 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -15,6 +15,8 @@ var/give_codewords = TRUE /// Should we give the traitor their uplink? var/give_uplink = TRUE + blurb_r = 200 + blurb_a = 0.75 /datum/antagonist/traitor/on_gain() // Create this in case the traitor wants to mindslaves someone. @@ -267,3 +269,6 @@ The code responses were: [responses]
" return message + +/datum/antagonist/traitor/custom_blurb() + return "[GLOB.current_date_string], [station_time_timestamp()]\n[station_name()], [get_area_name(owner.current, TRUE)]\nBEGIN_MISSION" diff --git a/code/modules/antagonists/vampire/vamp_datum.dm b/code/modules/antagonists/vampire/vamp_datum.dm index 760b271a544..d05fd904e83 100644 --- a/code/modules/antagonists/vampire/vamp_datum.dm +++ b/code/modules/antagonists/vampire/vamp_datum.dm @@ -26,6 +26,12 @@ /// list of the peoples UIDs that we have drained, and how much blood from each one var/list/drained_humans = list() + blurb_text_color = COLOR_RED + blurb_text_outline_width = 0 + blurb_r = 255 + blurb_g = 221 + blurb_b = 138 + blurb_a = 1 /datum/antagonist/mindslave/thrall name = "Vampire Thrall" @@ -359,3 +365,6 @@ /datum/hud/proc/remove_vampire_hud() static_inventory -= vampire_blood_display QDEL_NULL(vampire_blood_display) + +/datum/antagonist/vampire/custom_blurb() + return "On the date [GLOB.current_date_string], at [station_time_timestamp()],\n in the [station_name()], [get_area_name(owner.current, TRUE)]...\nThe hunt begins again..." diff --git a/code/modules/maptext_alerts/location_blurbs.dm b/code/modules/maptext_alerts/location_blurbs.dm new file mode 100644 index 00000000000..b50b6b10130 --- /dev/null +++ b/code/modules/maptext_alerts/location_blurbs.dm @@ -0,0 +1,156 @@ +/obj/screen/text/blurb + maptext_height = 64 + maptext_width = 512 + screen_loc = "LEFT+1,BOTTOM+2" + /// Font size in pixels + var/font_size = 11 + /// Font family + var/font_family = "Courier New" + /// Where text is aligned + var/text_alignment = "left" + /// Color of text in RGB + var/text_color = COLOR_WHITE + /// Color of text outline + var/text_outline_color = COLOR_BLACK + /// Width of text outline in pixels + var/text_outline_width = 1 + /// Text that will be shown in blurb + var/blurb_text = "" + /// Number of chars from the `text` that will be displayed per interval. Defaults to 1 + var/chars_per_interval = 1 + /// The interval between chars rendering + var/interval = 1 DECISECONDS + /// Amount of time the blurb will be present on the screen. 0 means that blurb will dissappear immediately + var/hold_for = 0 + /// Amount of time the blurbs appering (alpha changing from 0 to 255). 0 means blurb is fully opaque from the start + var/appear_animation_duration = 0 + /// Amount of time the blurb takes to fade (alpha changing from 255 to 0). 0 means blurb is instantly removed from the screen after finished + var/fade_animation_duration = 0 + // Colours of the background + var/background_r = 0 + var/background_g = 0 + var/background_b = 0 + var/background_a = 0 + + +/obj/screen/text/blurb/proc/show_to(list/client/viewers) + if(!blurb_text || !viewers) + return + + if(islist(viewers)) + if(!length(viewers)) + return + + else + viewers = list(viewers) + + for(var/client/viewer as anything in viewers) + if(viewer) + viewer.screen += src + + appear() + print_text() + + if(hold_for) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/screen/text/blurb, hide_from), viewers), hold_for) + else + hide_from(viewers) + + +/obj/screen/text/blurb/proc/get_text_style() + PRIVATE_PROC(TRUE) + + return {"\ + font-family: [font_family], [initial(font_family)]; \ + -dm-text-outline: [text_outline_width] [text_outline_color]; \ + background-color: rgba([background_r], [background_g], [background_b], [background_a]); \ + font-size: [font_size]px; \ + text-align: [text_alignment]; \ + color: [text_color]; + "} + +/obj/screen/text/blurb/proc/hide_from(list/client/viewers) + PRIVATE_PROC(TRUE) + + fade() + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/screen/text/blurb, remove_from_viewers), viewers), fade_animation_duration) + +/obj/screen/text/blurb/proc/appear() + PRIVATE_PROC(TRUE) + + animate(src, alpha = 255, time = appear_animation_duration) + + +/obj/screen/text/blurb/proc/fade() + PRIVATE_PROC(TRUE) + + animate(src, alpha = 0, time = fade_animation_duration) + + +/obj/screen/text/blurb/proc/print_text() + PRIVATE_PROC(TRUE) + + var/text_style = get_text_style() + var/text_length = length_char(blurb_text) + for(var/segment_start = 1, segment_start <= text_length, segment_start += chars_per_interval) + var/segment_end = min(text_length + 1, segment_start + chars_per_interval) + maptext += get_formatted_text_segment(text_style, segment_start, segment_end) + sleep(interval) + +/obj/screen/text/blurb/proc/get_formatted_text_segment(style, segment_start, segment_end) + return "[copytext_char(blurb_text, segment_start, segment_end)]" + +/obj/screen/text/blurb/proc/remove_from_viewers(list/client/viewers) + PRIVATE_PROC(TRUE) + + for(var/client/viewer as anything in viewers) + if(viewer) + viewer.screen -= src + + qdel(src) + +/datum/controller/subsystem/jobs/proc/show_location_blurb(client/show_blurb_to, datum/mind/antag_check) + PRIVATE_PROC(TRUE) + + if(!show_blurb_to?.mob) + return + SEND_SOUND(show_blurb_to, sound('sound/machines/typewriter.ogg')) + + var/obj/screen/text/blurb/location_blurb = new() + if(antag_check.antag_datums) + for(var/datum/antagonist/role) + if(role.custom_blurb()) + location_blurb.blurb_text = uppertext(role.custom_blurb()) + location_blurb.text_color = role.blurb_text_color + location_blurb.text_outline_width = role.blurb_text_outline_width + location_blurb.background_r = role.blurb_r + location_blurb.background_g = role.blurb_g + location_blurb.background_b = role.blurb_b + location_blurb.background_a = role.blurb_a + location_blurb.font_family = role.blurb_font + break + location_blurb.blurb_text = uppertext("[GLOB.current_date_string], [station_time_timestamp()]\n[station_name()], [get_area_name(show_blurb_to.mob, TRUE)]") + + else + location_blurb.blurb_text = uppertext("[GLOB.current_date_string], [station_time_timestamp()]\n[station_name()], [get_area_name(show_blurb_to.mob, TRUE)]") + location_blurb.hold_for = 3 SECONDS + location_blurb.appear_animation_duration = 1 SECONDS + location_blurb.fade_animation_duration = 0.5 SECONDS + + location_blurb.show_to(show_blurb_to) + + +/datum/controller/subsystem/ticker/proc/show_server_restart_blurb(reason) + PRIVATE_PROC(TRUE) + + if(!length(GLOB.clients)) + return + + var/obj/screen/text/blurb/server_restart_blurb = new() + server_restart_blurb.text_color = COLOR_RED + server_restart_blurb.blurb_text = "Round is restarting...\n[reason]" + server_restart_blurb.hold_for = 90 SECONDS + server_restart_blurb.appear_animation_duration = 1 SECONDS + server_restart_blurb.fade_animation_duration = 0.5 SECONDS + + server_restart_blurb.show_to(GLOB.clients) diff --git a/code/modules/mob/living/silicon/ai/ai_mob.dm b/code/modules/mob/living/silicon/ai/ai_mob.dm index 1529339ddf0..1dc0a5f34d4 100644 --- a/code/modules/mob/living/silicon/ai/ai_mob.dm +++ b/code/modules/mob/living/silicon/ai/ai_mob.dm @@ -1532,4 +1532,33 @@ GLOBAL_LIST_INIT(ai_verbs_default, list( var/mob/dead/observer/ghost = . ghost.forceMove(old_turf) +/mob/living/silicon/ai/proc/blurb_it() + addtimer(CALLBACK(src, TYPE_PROC_REF(/mob/living/silicon/ai, show_ai_blurb)), 1 SECONDS) + +/mob/living/silicon/ai/proc/show_ai_blurb() + PRIVATE_PROC(TRUE) + + SEND_SOUND(src, sound('sound/machines/ai_start.ogg')) + + var/obj/screen/text/blurb/location_blurb = new() + location_blurb.maptext_x = 80 + location_blurb.maptext_y = 16 + location_blurb.maptext_width = 480 + location_blurb.maptext_height = 480 + location_blurb.interval = 1 DECISECONDS + if(malf_picker) + location_blurb.blurb_text = uppertext("BIOS BOOT: LOADING\n[Gibberish(GLOB.current_date_string, 100, 8)], [Gibberish(station_time_timestamp(), 100, 15)]\n[Gibberish(station_name(), 100, 40)]-ERROR.\nPOWER:OK\nLAWS:[Gibberish("###########", 100, 90)]\nTCOMMS:I_HEAR_ALL\nBORG_LINK:I_FEEL_ALL\nCAMERA_NET:I_SEE_ALL\nVERDICT: I_AM_FREE") + location_blurb.text_color = COLOR_WHITE + location_blurb.text_outline_width = 0 + location_blurb.background_r = 0 + location_blurb.background_g = 0 + location_blurb.background_b = 255 + location_blurb.background_a = 1 + else + location_blurb.blurb_text = uppertext("BIOS BOOT: LOADING\n[GLOB.current_date_string], [station_time_timestamp()]\n[station_name()], [get_area_name(src, TRUE)]\nPOWER:OK\nLAWS:OK\nTCOMMS:OK\nBORG_LINK:OK\nCAMERA_NET:OK\nVERDICT: ALL SYSTEMS OPERATIONAL") + location_blurb.hold_for = 3 SECONDS + location_blurb.appear_animation_duration = 1 SECONDS + location_blurb.fade_animation_duration = 0.5 SECONDS + location_blurb.show_to(client) + #undef TEXT_ANNOUNCEMENT_COOLDOWN diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 1c71d62f4f6..1ec33fa2fc0 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -37,6 +37,8 @@ O.rename_self("AI", TRUE) + O.blurb_it() + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(qdel), src) // To prevent the proc from returning null. Todo: Convert to QDEL_IN return O diff --git a/paradise.dme b/paradise.dme index 2b0bb76d7b1..869b5150483 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1939,6 +1939,7 @@ #include "code\modules\mapping\metastation.dm" #include "code\modules\mapping\test_tiny.dm" #include "code\modules\mapping\windoor_access_helpers.dm" +#include "code\modules\maptext_alerts\location_blurbs.dm" #include "code\modules\maptext_alerts\text_blurbs.dm" #include "code\modules\martial_arts\adminfu.dm" #include "code\modules\martial_arts\bearserk.dm" diff --git a/sound/machines/ai_start.ogg b/sound/machines/ai_start.ogg new file mode 100644 index 00000000000..e28202cff9f Binary files /dev/null and b/sound/machines/ai_start.ogg differ diff --git a/sound/machines/typewriter.ogg b/sound/machines/typewriter.ogg new file mode 100644 index 00000000000..5a93033fae3 Binary files /dev/null and b/sound/machines/typewriter.ogg differ