From d49c825f8e90f31cb1cf38c7d8a9f2ef82c96858 Mon Sep 17 00:00:00 2001 From: Leland Kemble <70413276+lelandkemble@users.noreply.github.com> Date: Fri, 29 May 2026 13:35:45 -0400 Subject: [PATCH] Bitrunning glitches take much longer to escape their simulation if there are remaining active bitrunners (#95934) ## About The Pull Request For every living, connected bit avatar remaining in the simulation, the `do_after()` for leaving the simulation as a bitrunning glitch ghost role is multiplied by 5. The base timer remains at it was, two seconds. Additionally, there is an exception in place for the "Island Brawl" domain, which is the FFA with infinite respawns. It still multiplies by 5 for each active bitrunner, but that multiplier is reduced by 1 for each death, so you likely only have to kill one wave of bitrunners for normal escape time. Additionally, because of necessity for the exception and also basic good sense, bitrunning points are no longer component-based on specific turfs in the domain, and are held in the server. It never should have been a component, it had no reason to be one. This, as a consenquence, also fixes that you could completely softlock any domain using points by simply crowbarring the turf that the crate was yet to spawn on. ## Why It's Good For The Game Yesterday, I saw one of the lamest things I've ever seen in the game. A bitrunning glitch spawns in, walks literally right by two bitrunners as they ask who he is, and leaves the simulation to go on a killing spree unburdened. There was extenuating circumstances in that situation, but it still was a miserable breakdown of what I think the intended gameplay of a bitrunning glitch is, and shows how ridiculously easy it is to simply not engage with the intended hurdle in your path. The primary(and, really, only) job of a glitch is to kill bit avatars, and this PR makes it significantly more difficult to just... walk by them to go on your killing spree on station. Work, then play. ## Changelog :cl: balance: For every living, connected bitrunner remaining in a domain, bitrunning glitches will take five times longer to escape. fix: You can no longer softlock any virtual domain that uses points by crowbarring the reward turf before the crate spawns. /:cl: --- .../dcs/signals/signals_bitrunning.dm | 3 -- .../components/bitrunning_points.dm | 36 ------------------- .../modules/bitrunning/server/map_handling.dm | 9 +++-- code/modules/bitrunning/server/threats.dm | 16 +++++++++ .../virtual_domain/virtual_domain.dm | 20 ++++++++++- tgstation.dme | 1 - 6 files changed, 39 insertions(+), 46 deletions(-) delete mode 100644 code/modules/bitrunning/components/bitrunning_points.dm diff --git a/code/__DEFINES/dcs/signals/signals_bitrunning.dm b/code/__DEFINES/dcs/signals/signals_bitrunning.dm index ccf47c22604..5e49840d344 100644 --- a/code/__DEFINES/dcs/signals/signals_bitrunning.dm +++ b/code/__DEFINES/dcs/signals/signals_bitrunning.dm @@ -1,9 +1,6 @@ /// from /atom/movable/screen/alert/bitrunning/qserver_domain_complete #define COMSIG_BITRUNNER_ALERT_SEVER "bitrunner_alert_sever" -/// from /obj/effect/bitrunning/loot_signal: (points) -#define COMSIG_BITRUNNER_GOAL_POINT "bitrunner_goal_point" - // Netpods /// from /obj/machinery/netpod/sever_connection() diff --git a/code/modules/bitrunning/components/bitrunning_points.dm b/code/modules/bitrunning/components/bitrunning_points.dm deleted file mode 100644 index 039f3a9d338..00000000000 --- a/code/modules/bitrunning/components/bitrunning_points.dm +++ /dev/null @@ -1,36 +0,0 @@ -/// Attaches to a turf so it spawns a crate when a certain amount of points are added to it. -/datum/component/bitrunning_points - /// The amount required to spawn a crate - var/points_goal = 10 - /// A special condition limits this from spawning a crate - var/points_received = 0 - - -/datum/component/bitrunning_points/Initialize(datum/lazy_template/virtual_domain/domain) - if(!isturf(parent)) - return COMPONENT_INCOMPATIBLE - - RegisterSignal(domain, COMSIG_BITRUNNER_GOAL_POINT, PROC_REF(on_add_points)) - - -/// Listens for points to be added which will eventually spawn a crate. -/datum/component/bitrunning_points/proc/on_add_points(datum/source, points_to_add) - SIGNAL_HANDLER - - points_received += points_to_add - - if(points_received < points_goal) - return - - reveal() - - -/// Spawns the crate with some effects -/datum/component/bitrunning_points/proc/reveal() - playsound(src, 'sound/effects/magic/blink.ogg', 50, TRUE) - - var/turf/tile = parent - var/obj/structure/closet/crate/secure/bitrunning/encrypted/crate = new() - crate.forceMove(tile) // Triggers any on-move effects on that turf - do_sparks(5, FALSE, tile, spark_type = /datum/effect_system/basic/spark_spread/quantum) - qdel(src) diff --git a/code/modules/bitrunning/server/map_handling.dm b/code/modules/bitrunning/server/map_handling.dm index 96a10d60bbf..b9a2f792163 100644 --- a/code/modules/bitrunning/server/map_handling.dm +++ b/code/modules/bitrunning/server/map_handling.dm @@ -53,12 +53,12 @@ scrub_vdom() is_ready = TRUE return FALSE - - + + //We will want to record how the domain was selected. Either entirely randomly, with the name redacted, or with full information. //Without this, it is difficult to determine what domains are selected more often intentionallly, vs unintentionally. var/selection_type - + if(was_random_selection) selection_type = "random selection" else @@ -168,8 +168,7 @@ continue if(istype(thing, /obj/effect/landmark/bitrunning/loot_signal)) - var/turf/signaler_turf = get_turf(thing) - signaler_turf.AddComponent(/datum/component/bitrunning_points, generated_domain) + generated_domain.main_crate_loc = thing.loc qdel(thing) continue diff --git a/code/modules/bitrunning/server/threats.dm b/code/modules/bitrunning/server/threats.dm index 34583aa358d..c9c33c49f44 100644 --- a/code/modules/bitrunning/server/threats.dm +++ b/code/modules/bitrunning/server/threats.dm @@ -142,6 +142,22 @@ aas.broadcast("QUANTUM SERVER ALERT: Fabrication protocols have crashed unexpectedly. Please evacuate the area.", list(RADIO_CHANNEL_SUPPLY)) timeout = 10 SECONDS + var/bitrunners_alive = 0 + var/island_brawl_exception = istype(generated_domain, /datum/lazy_template/virtual_domain/island_brawl) + for(var/datum/weakref/bitrunner_ref in avatar_connection_refs) + var/mob/living/bitrunner = astype(bitrunner_ref.resolve(), /datum/component/avatar_connection)?.parent + if(!bitrunner) + continue + if((bitrunner.stat > CONSCIOUS) || !bitrunner.client) + continue + if(island_brawl_exception) + timeout *= max(5 - generated_domain.main_crate_points, 1) + continue + bitrunners_alive++ + timeout *= 5 + if(bitrunners_alive) + to_chat(antag, span_warning("[bitrunners_alive] criminals still remain here, pilfering your domain. It will be more difficult to leave until they are handled.")) + if(!do_after(antag, timeout) || QDELETED(chosen_forge) || QDELETED(antag) || QDELETED(src) || !is_ready || !is_operational) chosen_forge.setup_particles() return diff --git a/code/modules/bitrunning/virtual_domain/virtual_domain.dm b/code/modules/bitrunning/virtual_domain/virtual_domain.dm index 8fc3173df95..139e46d5508 100644 --- a/code/modules/bitrunning/virtual_domain/virtual_domain.dm +++ b/code/modules/bitrunning/virtual_domain/virtual_domain.dm @@ -52,6 +52,12 @@ var/secondary_loot_generated /// Has this domain been beaten with high enough score to spawn a tech disk? var/disk_reward_spawned = FALSE + /// The amount of points towards the spawning of the main crate, on maps using points. + var/main_crate_points = 0 + /// The amount of points required to spawn the main crate, on maps using points. + var/main_crate_point_goal = 10 + /// The location the crate will spawn when enough points are accumulated, on maps using points. + var/main_crate_loc /** * Modularity @@ -99,7 +105,19 @@ /// Sends a point to any loot signals on the map /datum/lazy_template/virtual_domain/proc/add_points(points_to_add = 1) - SEND_SIGNAL(src, COMSIG_BITRUNNER_GOAL_POINT, points_to_add) + main_crate_points += points_to_add + if(main_crate_points >= main_crate_point_goal) + reveal() + +/datum/lazy_template/virtual_domain/proc/reveal() + if(!main_crate_loc) + return + var/turf/spawn_loc = get_turf(main_crate_loc) + playsound(spawn_loc, 'sound/effects/magic/blink.ogg', 50, TRUE) + var/obj/structure/closet/crate/secure/bitrunning/encrypted/crate = new() + crate.forceMove(spawn_loc) // Triggers any on-move effects on that turf + do_sparks(5, FALSE, spawn_loc, spark_type = /datum/effect_system/basic/spark_spread/quantum) + main_crate_loc = null /// Loads the ghost candidates. /datum/lazy_template/virtual_domain/proc/load_advanced_npcs(list/mob/lucky_ghosts) diff --git a/tgstation.dme b/tgstation.dme index 5117257ac27..738b35d13ae 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3892,7 +3892,6 @@ #include "code\modules\bitrunning\antagonists\netguardian.dm" #include "code\modules\bitrunning\components\avatar_connection.dm" #include "code\modules\bitrunning\components\avatar_gear.dm" -#include "code\modules\bitrunning\components\bitrunning_points.dm" #include "code\modules\bitrunning\components\glitch.dm" #include "code\modules\bitrunning\components\netpod_healing.dm" #include "code\modules\bitrunning\components\npc_friendly.dm"