From c7e49e5fa39339deacba0cff669aab443a6d6131 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Sat, 29 Jul 2023 22:02:36 +0200 Subject: [PATCH] [MIRROR] Doubles the time you can get the "Long shift" achievement, makes it not grant on admin restarts [MDB IGNORE] (#22771) * Doubles the time you can get the "Long shift" achievement, makes it not grant on admin restarts (#77195) ## About The Pull Request - "Long shift" can now be earned from sub 10 minute rounds rather than sub 5 minute rounds - Admin restarts no longer give out "Long shift" ## Why It's Good For The Game I do not think this achievement can *possibly* be earned right now. Like at all. Nuke Ops and cult are the only antags that can possibly do it and it's incredibly infeasible (requiring that they nuke the station or summon Nar'sie in just 3 minutes!) So I bumped up the timer to 10 minutes. This means that ops can get it if they nuke the station in 8 minutes, cult can get it if they REALLY speedrun, and revs can get it if they beeline the heads. I checked the DB for stats on this achievement and it's only been earned in 3 rounds across the last year - `208780` (admin restart due to a bug) `192892` (admin restart due to a bug?) `186192` (admin restart). So I also prevented admin forcing the round to end. (I don't know if it catches admin reboots directly I'll have to check that.) ## Changelog :cl: Melbert balance: The "Long Shift" achievement is now feasibly obtainable, and admins can no longer trigger it unknowingly /:cl: * Doubles the time you can get the "Long shift" achievement, makes it not grant on admin restarts --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/__DEFINES/subsystems.dm | 8 ++++++++ code/__HELPERS/roundend.dm | 8 +++----- code/controllers/subsystem/ticker.dm | 8 +++++--- code/game/gamemodes/game_mode.dm | 6 +++--- code/game/world.dm | 6 +++--- code/modules/admin/topic.dm | 2 +- code/modules/admin/verbs/server.dm | 2 +- code/modules/antagonists/blob/overmind.dm | 2 +- code/modules/antagonists/malf_ai/malf_ai_modules.dm | 2 +- code/modules/power/singularity/narsie.dm | 2 +- .../supermatter_delamination/delamination_effects.dm | 2 +- code/modules/unit_tests/unit_test.dm | 2 +- 12 files changed, 29 insertions(+), 21 deletions(-) diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index c94c0a489c9..2c13b7eb07d 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -259,6 +259,14 @@ /// Game has round finished #define GAME_STATE_FINISHED 4 +// Used for SSticker.force_ending +/// Default, round is not being forced to end. +#define END_ROUND_AS_NORMAL 0 +/// End the round now as normal +#define FORCE_END_ROUND 1 +/// For admin forcing roundend, can be used to distinguish the two +#define ADMIN_FORCE_END_ROUND 2 + /** Create a new timer and add it to the queue. * Arguments: diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index 7294795ba20..9e14c1c1212 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -201,22 +201,20 @@ player_client.give_award(/datum/award/score/hardcore_random, human_mob, round(human_mob.hardcore_survival_score)) -/datum/controller/subsystem/ticker/proc/declare_completion() +/datum/controller/subsystem/ticker/proc/declare_completion(was_forced = END_ROUND_AS_NORMAL) set waitfor = FALSE for(var/datum/callback/roundend_callbacks as anything in round_end_events) roundend_callbacks.InvokeAsync() LAZYCLEARLIST(round_end_events) - var/speed_round = FALSE - if(world.time - SSticker.round_start_time <= 300 SECONDS) - speed_round = TRUE + var/speed_round = (STATION_TIME_PASSED() <= 10 MINUTES) for(var/client/C in GLOB.clients) if(!C?.credits) C?.RollCredits() C?.playtitlemusic(40) - if(speed_round) + if(speed_round && was_forced != ADMIN_FORCE_END_ROUND) C?.give_award(/datum/award/achievement/misc/speed_round, C?.mob) HandleRandomHardcoreScore(C) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index c78ff138a3d..b9260e51312 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -10,8 +10,10 @@ SUBSYSTEM_DEF(ticker) /// state of current round (used by process()) Use the defines GAME_STATE_* ! var/current_state = GAME_STATE_STARTUP - /// Boolean to track if round was ended by admin intervention or a "round-ending" event, like summoning Nar'Sie, a blob victory, the nuke going off, etc. - var/force_ending = FALSE + /// Boolean to track if round should be forcibly ended next ticker tick. + /// Set by admin intervention ([ADMIN_FORCE_END_ROUND]) + /// or a "round-ending" event, like summoning Nar'Sie, a blob victory, the nuke going off, etc. ([FORCE_END_ROUND]) + var/force_ending = END_ROUND_AS_NORMAL /// If TRUE, there is no lobby phase, the game starts immediately. var/start_immediately = FALSE /// Boolean to track and check if our subsystem setup is done. @@ -220,7 +222,7 @@ SUBSYSTEM_DEF(ticker) mode.process(wait * 0.1) check_queue() - if(!roundend_check_paused && mode.check_finished(force_ending) || force_ending) + if(!roundend_check_paused && (mode.check_finished() || force_ending)) current_state = GAME_STATE_FINISHED toggle_ooc(TRUE) // Turn it on toggle_dooc(TRUE) diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 0383bf89bab..61037fe4c77 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -56,7 +56,8 @@ /datum/game_mode/proc/make_antag_chance(mob/living/carbon/human/character) return -/datum/game_mode/proc/check_finished(force_ending) //to be called by SSticker +/// Checks if the round should be ending, called every ticker tick +/datum/game_mode/proc/check_finished() if(!SSticker.setup_done) return FALSE if(SSshuttle.emergency && (SSshuttle.emergency.mode == SHUTTLE_ENDGAME)) @@ -65,8 +66,7 @@ return TRUE if(GLOB.revolutionary_win) return TRUE - if(force_ending) - return TRUE + return FALSE /* * Generate a list of station goals available to purchase to report to the crew. diff --git a/code/game/world.dm b/code/game/world.dm index 07fe533b474..380448d9fcf 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -49,8 +49,8 @@ GLOBAL_VAR(restart_counter) * - Dominion/Cyberboss * * Where to put init shit quick guide: - * If you need it to happen before the mc is created: world/Genesis. - * If you need it to happen last: world/New(), + * If you need it to happen before the mc is created: world/Genesis. + * If you need it to happen last: world/New(), * Otherwise, in a subsystem preinit or init. Subsystems can set an init priority. */ @@ -180,7 +180,7 @@ GLOBAL_VAR(restart_counter) #ifdef UNIT_TESTS cb = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(RunUnitTests)) #else - cb = VARSET_CALLBACK(SSticker, force_ending, TRUE) + cb = VARSET_CALLBACK(SSticker, force_ending, ADMIN_FORCE_END_ROUND) #endif SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_addtimer), cb, 10 SECONDS)) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index b7aea102b69..4dc402e0063 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -197,7 +197,7 @@ if(tgui_alert(usr, "This will end the round, are you SURE you want to do this?", "Confirmation", list("Yes", "No")) == "Yes") if(tgui_alert(usr, "Final Confirmation: End the round NOW?", "Confirmation", list("Yes", "No")) == "Yes") message_admins(span_adminnotice("[key_name_admin(usr)] has ended the round.")) - SSticker.force_ending = TRUE //Yeah there we go APC destroyed mission accomplished + SSticker.force_ending = ADMIN_FORCE_END_ROUND //Yeah there we go APC destroyed mission accomplished return else message_admins(span_adminnotice("[key_name_admin(usr)] decided against ending the round.")) diff --git a/code/modules/admin/verbs/server.dm b/code/modules/admin/verbs/server.dm index 8f0a112da16..811b2a3506d 100644 --- a/code/modules/admin/verbs/server.dm +++ b/code/modules/admin/verbs/server.dm @@ -77,7 +77,7 @@ if(confirm == "Cancel") return if(confirm == "Yes") - SSticker.force_ending = TRUE + SSticker.force_ending = FORCE_END_ROUND SSblackbox.record_feedback("tally", "admin_verb", 1, "End Round") // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! /datum/admins/proc/toggleooc() diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm index 021c8bb12d5..70a1e69e1e3 100644 --- a/code/modules/antagonists/blob/overmind.dm +++ b/code/modules/antagonists/blob/overmind.dm @@ -207,7 +207,7 @@ GLOBAL_LIST_EMPTY(blob_nodes) main_objective.completed = TRUE to_chat(world, span_blob("[real_name] consumed the station in an unstoppable tide!")) SSticker.news_report = BLOB_WIN - SSticker.force_ending = TRUE + SSticker.force_ending = FORCE_END_ROUND /mob/camera/blob/Destroy() QDEL_NULL(blobstrain) diff --git a/code/modules/antagonists/malf_ai/malf_ai_modules.dm b/code/modules/antagonists/malf_ai/malf_ai_modules.dm index 2f628fd66b4..a6c6616ad48 100644 --- a/code/modules/antagonists/malf_ai/malf_ai_modules.dm +++ b/code/modules/antagonists/malf_ai/malf_ai_modules.dm @@ -358,7 +358,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) /obj/machinery/doomsday_device/proc/trigger_doomsday() callback_on_everyone_on_z(SSmapping.levels_by_trait(ZTRAIT_STATION), CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(bring_doomsday)), src) to_chat(world, span_bold("The AI cleansed the station of life with [src]!")) - SSticker.force_ending = TRUE + SSticker.force_ending = FORCE_END_ROUND /proc/bring_doomsday(mob/living/victim, atom/source) if(issilicon(victim)) diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm index 2c0ae6f7705..1c83ca58e1d 100644 --- a/code/modules/power/singularity/narsie.dm +++ b/code/modules/power/singularity/narsie.dm @@ -263,7 +263,7 @@ ///Helper to set the round to end asap. Current usage Cult round end code /proc/ending_helper() - SSticker.force_ending = TRUE + SSticker.force_ending = FORCE_END_ROUND /** * Selects cinematic to play as part of the cult end depending on the outcome then ends the round afterward diff --git a/code/modules/power/supermatter/supermatter_delamination/delamination_effects.dm b/code/modules/power/supermatter/supermatter_delamination/delamination_effects.dm index 1c3a0402ebe..49415d65dec 100644 --- a/code/modules/power/supermatter/supermatter_delamination/delamination_effects.dm +++ b/code/modules/power/supermatter/supermatter_delamination/delamination_effects.dm @@ -205,7 +205,7 @@ sleep(10 SECONDS) SSticker.news_report = SUPERMATTER_CASCADE - SSticker.force_ending = TRUE + SSticker.force_ending = FORCE_END_ROUND /// Scatters crystal mass over the event spawns as long as they are at least 30 tiles away from whatever we want to avoid. /datum/sm_delam/proc/effect_crystal_mass(obj/machinery/power/supermatter_crystal/sm, avoid) diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm index 1709bafb144..3fef3d985f7 100644 --- a/code/modules/unit_tests/unit_test.dm +++ b/code/modules/unit_tests/unit_test.dm @@ -236,7 +236,7 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests()) fdel(file_name) file(file_name) << json_encode(test_results) - SSticker.force_ending = TRUE + SSticker.force_ending = ADMIN_FORCE_END_ROUND //We have to call this manually because del_text can preceed us, and SSticker doesn't fire in the post game SSticker.declare_completion()