From 298b5d37194aeb4201e20f6c456c918b2a0ffa09 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Sat, 29 Jul 2023 14:00:16 -0500 Subject: [PATCH] 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: --- 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 08397bf4ea9..3e9edb50241 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -255,6 +255,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 e19b4a6903e..0c93ef0b429 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 917fcd0b41a..1e5a9b085ee 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. @@ -206,7 +208,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 c969ace7313..3f769e1b8a4 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 fad407ebed9..32442ad8b05 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -162,7 +162,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 8c2a3aba722..3cc79f316f2 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 264175579b0..7c0e169d483 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 916516d38e7..99dd421452c 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 16074128b51..25283c8d09a 100644 --- a/code/modules/power/supermatter/supermatter_delamination/delamination_effects.dm +++ b/code/modules/power/supermatter/supermatter_delamination/delamination_effects.dm @@ -211,7 +211,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()