Admins can now varedit blobs to not instantly end the round on victory (#95878)

## About The Pull Request
Originally this PR was just supposed to split blob's "start victory"
thing into its own proc and add an extra check that could be overridden,
both for downstreams because a friend asked, but then I thought
"wouldn't it be funny if you could varedit a blob to not end the round
on critical mass?" so now we're here.

Anyways, it's about what it says on the tin. Blobs now have a variable,
`end_round_on_victory`, which defaults to TRUE (preserving current
behavior). Setting it to 0/FALSE:
- Makes the blob no longer gain infinite points upon reaching critical
mass
- Makes it announce an "emergency containment activation" instead of
killing everyone if it does hit critical mass
- Prevents the blob from expanding over the blob victory count (400 by
default).
- ...basically does nothing else. (You're still going to have to
manually remove the blob from SSshuttle's hostile environments list!)

## Why It's Good For The Game

Maybe you want to jumpscare the station with a giant fight they have to
take but then not actually kill them in the sake they don't actually
win. You could make an event out of this (said in the same cadence as
"You could make a religion out of this"), probably.

## Changelog

🆑
admin: Admins can now varedit blob overminds (the eye mob) to not kill
everyone on the station if they hit critical mass. (Admins will still
have to remove the blob from the shuttle subsystem's "hostile
environments" tracker, though.)
/🆑

---------

Co-authored-by: Hatterhat <Hatterhat@users.noreply.github.com>
This commit is contained in:
Hatterhat
2026-05-05 23:12:50 -04:00
committed by GitHub
co-authored by Hatterhat
parent a772d501ce
commit bb477c9dbd
2 changed files with 48 additions and 15 deletions
+33 -14
View File
@@ -61,6 +61,9 @@ GLOBAL_LIST_EMPTY(blob_nodes)
/// The list of strains the blob can reroll for.
var/list/strain_choices
/// Adminbus potential - if this is set to FALSE, the blob won't end the round upon reaching critical mass.
var/end_round_on_victory = TRUE
/mob/eye/blob/Initialize(mapload, starting_points = OVERMIND_STARTING_POINTS)
ADD_TRAIT(src, TRAIT_BLOB_ALLY, INNATE_TRAIT)
validate_location()
@@ -160,16 +163,8 @@ GLOBAL_LIST_EMPTY(blob_nodes)
qdel(src)
else if(!victory_in_progress && (blobs_legit.len >= blobwincount))
victory_in_progress = TRUE
priority_announce("Biohazard has reached critical mass. Station loss is imminent.", "Biohazard Alert")
SSsecurity_level.set_level(SEC_LEVEL_DELTA)
begin_victory()
// Set status displays to biohazard alert - critical level
send_status_display_biohazard_alert()
max_blob_points = INFINITY
blob_points = INFINITY
addtimer(CALLBACK(src, PROC_REF(victory)), 45 SECONDS)
else if(!free_strain_rerolls && (last_reroll_time + BLOB_POWER_REROLL_FREE_TIME<world.time))
to_chat(src, span_boldnotice("You have gained another free strain re-roll."))
free_strain_rerolls = 1
@@ -199,6 +194,23 @@ GLOBAL_LIST_EMPTY(blob_nodes)
/mob/eye/blob/proc/clear_biohazard_display()
clear_status_display_biohazard()
/// Announce the blob's victory! Tell everyone that they're about to explode and/or turn into biomass soup and give the overmind a victory lap.
/mob/eye/blob/proc/begin_victory()
victory_in_progress = TRUE
priority_announce("Biohazard has reached critical mass. Station loss is imminent.", "Biohazard Alert")
SSsecurity_level.set_level(SEC_LEVEL_DELTA)
// Set status displays to biohazard alert - critical level
send_status_display_biohazard_alert()
if(end_round_on_victory) // Assuming they actually *are* about to turn the station into soup...
max_blob_points = INFINITY
blob_points = INFINITY
else
to_chat(src, span_blob("You've reached critical mass, but something feels terribly wrong, stopping you from expanding further. All you can do now is fight as long as you can..."))
balloon_alert(src, "victory - expansion over critical mass disabled")
addtimer(CALLBACK(src, PROC_REF(victory)), 45 SECONDS)
/// Actually *do* the blob's victory: give them their greentext and, depending on the end_round_on_victory variable, decide if everyone dies or if it's just a jumpscare.
/mob/eye/blob/proc/victory()
// Set victory flags immediately
var/datum/antagonist/blob/B = mind.has_antag_datum(/datum/antagonist/blob)
@@ -207,13 +219,20 @@ GLOBAL_LIST_EMPTY(blob_nodes)
if(main_objective)
main_objective.completed = TRUE
to_chat(world, span_blobannounce("[real_name] consumed the station in an unstoppable tide!"))
SSticker.news_report = BLOB_WIN
SSticker.force_ending = FORCE_END_ROUND
if(end_round_on_victory)
to_chat(world, span_blobannounce("[real_name] consumed the station in an unstoppable tide!"))
SSticker.news_report = BLOB_WIN
SSticker.force_ending = FORCE_END_ROUND
// Handle the heavy victory operations asynchronously
INVOKE_ASYNC(src, PROC_REF(victory_sequence))
// Handle the heavy victory operations (where everyone dies) asynchronously
INVOKE_ASYNC(src, PROC_REF(victory_sequence))
else
// Is the station going boom? No. But is the station still going to get yelled at? Yes.
priority_announce("Experimental, classified, and very expensive emergency countermeasures have been activated to prevent total station loss, \
but the initial failure to contain the viral biohazard will be noted on the station's performance report. Expect further penalties.", \
"Emergency Biohazard Countermeasure Alert")
/// Kill everyone who's still on the station area and not already part of the blob's faction, and cover every station area with blob icons. Everyone's soup now.
/mob/eye/blob/proc/victory_sequence()
sound_to_playing_players('sound/announcer/alarm/nuke_alarm.ogg', 70)
sleep(10 SECONDS)
@@ -157,7 +157,18 @@
O.do_attack_animation(A) //visually attack the whatever
return O //just in case you want to do something to the animation.
/obj/structure/blob/proc/expand(turf/T = null, controller = null, expand_reaction = 1)
/// Can this blob structure make further blobs? For special cases (e.g. blobs not going past crit mass count if not ending the round)
/obj/structure/blob/proc/can_make_blob(mob/eye/blob/controller = null)
// If it's not being done with a controller, it's being done automatically. Because it's not player-controlled, it's not worth worrying about.
if(!controller)
return TRUE
// If it's not supposed to end the round and it's at the win count, don't make more. (400 tiles is still a lot to fight through...)
if(!controller.end_round_on_victory && (controller.blobs_legit.len >= controller.blobwincount))
return FALSE
// Otherwise, it's probably fine.
return TRUE
/obj/structure/blob/proc/expand(turf/T = null, mob/eye/blob/controller = null, expand_reaction = 1)
if(!T)
var/list/dirs = list(1,2,4,8)
for(var/i = 1 to 4)
@@ -172,6 +183,9 @@
return
var/make_blob = TRUE //can we make a blob?
if(!can_make_blob(controller))
make_blob = FALSE
if(isspaceturf(T) && !(locate(/obj/structure/lattice) in T) && prob(80))
make_blob = FALSE
playsound(src.loc, 'sound/effects/splat.ogg', 50, TRUE) //Let's give some feedback that we DID try to spawn in space, since players are used to it