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