From 5cf7d032955eea6773d160db559bc9e686bb9b0a Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Fri, 24 Mar 2023 16:52:19 +0100 Subject: [PATCH] [MIRROR] Roundstart Xeno egg deliveries create a Captive Xenomorph team, gives regular xenos a fluff objective so their popup isn't blank. [MDB IGNORE] (#20041) * Roundstart Xeno egg deliveries create a Captive Xenomorph team, gives regular xenos a fluff objective so their popup isn't blank. (#73852) ## About The Pull Request Xenomorphs who are a product of the roundstart xenobio egg delivery will now spawn as "Captive Xenomorphs", who receive an objective to break containment. Here's how it works: When a delivery egg is generated that area will be marked as the "captivity area". Xenomorphs born within this area now have their own team, and have their own section in the roundend report that will greentext them based on if they were able to survive and escape captivity. Xenomorphs born outside of this area will spawn as normal Xenomorphs, with no escape objective or special fanfare. To further encourage people from actually taking the role and potentially resigning themselves to an hour in Xenobio CBT prison, the first of the hive gets their own header on the roundend report. (When I say "team" here, I mean they receive a different antag team datum. They're still able to collaborate and cooperate with other Xenomorphs, they just have a different title and extra objective in addition to the bonus roundend report limelight.) ![image](https://user-images.githubusercontent.com/28870487/223782098-4659f7cc-c8d7-44d8-afbf-30ebbc17b9bb.png) ![image](https://user-images.githubusercontent.com/28870487/223765028-e285d810-a751-473f-a821-5fb2679b2f13.png) (This also adds a basic "survive and advance the hive" objective for all xenomorphs, since their objective popup was otherwise completely blank). Since the captivity area is entirely dependent on the location of the egg itself, admins can plop one of these down anywhere, and mappers don't have to put the egg mapping helper specifically in Xenobio. For clarification -- To be qualified for the Captive Xenomorph team, **a delivery egg must be spawned**, and the xeno you inhabit must be born in the same area the egg was spawned. If the queen breaks captivity and starts nesting elsewhere on the station, their children will be born as normal Xenomorphs, not Captive Xenomorphs. ## Why It's Good For The Game Adds a bit of distinction, and gives bragging rights, to anyone bold enough to take a roundstart xeno roll and escape with it. The Xeno egg delivery is already rare enough, I think it deserves a bit more fanfare (especially considering the dramatic impact it sometimes has on the direction of a round). ## Changelog :cl: add: Xenomorphs born in the room the roundstart delivery egg was spawned in will be part of a special "captive xenomorph" team, tasked with escaping and tracked in the roundend report. fix: Regular Xenomorphs no longer receive a blank objectives popup on spawn. /:cl: * Roundstart Xeno egg deliveries create a Captive Xenomorph team, gives regular xenos a fluff objective so their popup isn't blank. --------- Co-authored-by: Rhials --- code/controllers/subsystem/communications.dm | 4 + .../effects/spawners/xeno_egg_delivery.dm | 27 ++-- code/modules/antagonists/xeno/xeno.dm | 127 +++++++++++++++++- 3 files changed, 148 insertions(+), 10 deletions(-) diff --git a/code/controllers/subsystem/communications.dm b/code/controllers/subsystem/communications.dm index 992835072b3..37f1fd582e9 100644 --- a/code/controllers/subsystem/communications.dm +++ b/code/controllers/subsystem/communications.dm @@ -17,6 +17,10 @@ SUBSYSTEM_DEF(communications) var/list/command_report_footnotes = list() /// A counter of conditions that are blocking the command report from printing. Counter incremements up for every blocking condition, and de-incrememnts when it is complete. var/block_command_report = 0 + /// Has a special xenomorph egg been delivered? + var/xenomorph_egg_delivered = FALSE + /// The location where the special xenomorph egg was planted + var/area/captivity_area /datum/controller/subsystem/communications/proc/can_announce(mob/living/user, is_silicon) if(is_silicon && COOLDOWN_FINISHED(src, silicon_message_cooldown)) diff --git a/code/game/objects/effects/spawners/xeno_egg_delivery.dm b/code/game/objects/effects/spawners/xeno_egg_delivery.dm index 2ba20bcb21b..b09a37f14b1 100644 --- a/code/game/objects/effects/spawners/xeno_egg_delivery.dm +++ b/code/game/objects/effects/spawners/xeno_egg_delivery.dm @@ -2,17 +2,28 @@ name = "xeno egg delivery" icon = 'icons/mob/nonhuman-player/alien.dmi' icon_state = "egg_growing" - var/announcement_time = 1200 + var/announcement_time = 120 SECONDS /obj/effect/spawner/xeno_egg_delivery/Initialize(mapload) . = ..() - var/turf/T = get_turf(src) + var/turf/spawn_turf = get_turf(src) - new /obj/structure/alien/egg(T) - new /obj/effect/temp_visual/gravpush(T) - playsound(T, 'sound/items/party_horn.ogg', 50, TRUE, -1) + new /obj/structure/alien/egg/delivery(spawn_turf) + new /obj/effect/temp_visual/gravpush(spawn_turf) + playsound(spawn_turf, 'sound/items/party_horn.ogg', 50, TRUE, -1) - message_admins("An alien egg has been delivered to [ADMIN_VERBOSEJMP(T)].") - log_game("An alien egg has been delivered to [AREACOORD(T)]") - var/message = "Attention [station_name()], we have entrusted you with a research specimen in [get_area_name(T, TRUE)]. Remember to follow all safety precautions when dealing with the specimen." + message_admins("An alien egg has been delivered to [ADMIN_VERBOSEJMP(spawn_turf)].") + log_game("An alien egg has been delivered to [AREACOORD(spawn_turf)]") + var/message = "Attention [station_name()], we have entrusted you with a research specimen in [get_area_name(spawn_turf, TRUE)]. Remember to follow all safety precautions when dealing with the specimen." SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_addtimer), CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(print_command_report), message), announcement_time)) + +/obj/structure/alien/egg/delivery + name = "xenobiological specimen egg" + desc = "A large mottled egg, sent as a part of a Xenobiological Research Initiative by the higher-ups. Handle with care!" + max_integrity = 300 + +/obj/structure/alien/egg/delivery/Initialize(mapload) + . = ..() + + SScommunications.xenomorph_egg_delivered = TRUE + SScommunications.captivity_area = get_area(src) diff --git a/code/modules/antagonists/xeno/xeno.dm b/code/modules/antagonists/xeno/xeno.dm index 53ff49dec73..8ecede79c2a 100644 --- a/code/modules/antagonists/xeno/xeno.dm +++ b/code/modules/antagonists/xeno/xeno.dm @@ -1,3 +1,10 @@ +/// Captive Xeno has been found dead, regardless of location. +#define CAPTIVE_XENO_DEAD "captive_xeno_dead" +/// Captive Xeno has been found alive and within the captivity area. +#define CAPTIVE_XENO_FAIL "captive_xeno_failed" +/// Captive Xeno has been found alive and outside of the captivity area. +#define CAPTIVE_XENO_PASS "captive_xeno_escaped" + /datum/team/xeno name = "\improper Aliens" @@ -17,10 +24,14 @@ show_to_ghosts = TRUE var/datum/team/xeno/xeno_team +/datum/antagonist/xeno/on_gain() + forge_objectives() + . = ..() + /datum/antagonist/xeno/create_team(datum/team/xeno/new_team) if(!new_team) for(var/datum/antagonist/xeno/X in GLOB.antagonists) - if(!X.owner || !X.xeno_team) + if(!X.owner || !X.xeno_team || !istype(X.xeno_team, new_team)) //Make sure we don't add them to the wrong team continue xeno_team = X.xeno_team return @@ -36,11 +47,119 @@ /datum/antagonist/xeno/get_preview_icon() return finish_preview_icon(icon('icons/mob/nonhuman-player/alien.dmi', "alienh")) +/datum/antagonist/xeno/forge_objectives() + var/datum/objective/advance_hive/objective = new + objective.owner = owner + objectives += objective + +/datum/antagonist/xeno/captive + name = "\improper Captive Xenomorph" + ///Our associated antagonist team for captive xenomorphs + var/datum/team/xeno/captive/captive_team + +/datum/antagonist/xeno/captive/create_team(datum/team/xeno/captive/new_team) + if(!new_team) + for(var/datum/antagonist/xeno/captive/captive_xeno in GLOB.antagonists) + if(!captive_xeno.owner || !captive_xeno.captive_team) + continue + captive_team = captive_xeno.captive_team + return + captive_team = new + captive_team.progenitor = owner + else + if(!istype(new_team)) + CRASH("Wrong xeno team type provided to create_team") + captive_team = new_team + +/datum/antagonist/xeno/captive/get_team() + return captive_team + +/datum/antagonist/xeno/captive/forge_objectives() + var/datum/objective/escape_captivity/objective = new + objective.owner = owner + objectives += objective + ..() + +//Xeno Objectives +/datum/objective/escape_captivity + +/datum/objective/escape_captivity/New() + explanation_text = "Escape from captivity." + +/datum/objective/escape_captivity/check_completion() + if(!istype(get_area(owner), SScommunications.captivity_area)) + return TRUE + +/datum/objective/advance_hive + +/datum/objective/advance_hive/New() + explanation_text = "Survive and advance the Hive." + +/datum/objective/advance_hive/check_completion() + return owner.current.stat != DEAD + +///Captive Xenomorphs team +/datum/team/xeno/captive + name = "\improper Captive Aliens" + ///The first member of this team, presumably the queen. + var/datum/mind/progenitor + +/datum/team/xeno/captive/roundend_report() + var/list/parts = list() + var/escape_count = 0 //counts the number of xenomorphs that were born in captivity who ended the round outside of it + var/captive_count = 0 //counts the number of xenomorphs born in captivity who remained there until the end of the round (losers) + + parts += "The [name] were:
" + + if(check_captivity(progenitor)) + parts += span_greentext("The progenitor of this hive was [progenitor.key], as [progenitor], who successfully escaped captivity!") + "
" + else + parts += span_redtext("The progenitor of this hive was [progenitor.key], as [progenitor], who failed to escape captivity") + "
" + + for(var/datum/mind/alien_mind in members) + if(alien_mind == progenitor) + continue + + switch(check_captivity(alien_mind.current)) + if(CAPTIVE_XENO_DEAD) + parts += "[printplayer(alien_mind, fleecheck = FALSE)] while trying to escape captivity!" + if(CAPTIVE_XENO_FAIL) + parts += "[printplayer(alien_mind, fleecheck = FALSE)] in captivity!" + captive_count++ + if(CAPTIVE_XENO_PASS) + parts += "[printplayer(alien_mind, fleecheck = FALSE)] and managed to [span_greentext("escape captivity!")]" + escape_count++ + + parts += "
Overall, [captive_count] xenomorphs remained alive and in captivity, and [escape_count] managed to escape!
" + + var/thank_you_message + if(captive_count > escape_count) + thank_you_message = "xenobiological containment architecture" + else + thank_you_message = "xenofauna combat effectiveness" + + parts += "Nanotrasen thanks the crew of [station_name()] for providing much needed research data on [thank_you_message]." + + return "
[parts.Join("
")]

" + +/datum/team/xeno/captive/proc/check_captivity(mob/living/captive_alien) + if(!captive_alien || captive_alien.stat == DEAD) + return CAPTIVE_XENO_DEAD + + if(istype(get_area(captive_alien), SScommunications.captivity_area)) + return CAPTIVE_XENO_FAIL + + return CAPTIVE_XENO_PASS + //XENO /mob/living/carbon/alien/mind_initialize() ..() if(!mind.has_antag_datum(/datum/antagonist/xeno)) - mind.add_antag_datum(/datum/antagonist/xeno) + if(SScommunications.xenomorph_egg_delivered && istype(get_area(src), SScommunications.captivity_area)) + mind.add_antag_datum(/datum/antagonist/xeno/captive) + else + mind.add_antag_datum(/datum/antagonist/xeno) + mind.set_assigned_role(SSjob.GetJobType(/datum/job/xenomorph)) mind.special_role = ROLE_ALIEN @@ -53,3 +172,7 @@ mind.remove_antag_datum(/datum/antagonist/xeno) mind.set_assigned_role(SSjob.GetJobType(/datum/job/unassigned)) mind.special_role = null + +#undef CAPTIVE_XENO_DEAD +#undef CAPTIVE_XENO_FAIL +#undef CAPTIVE_XENO_PASS