diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 673bb4fc6d81..c0886ab871f9 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -131,8 +131,9 @@ #define XENO_HIVE_MUTATED "xeno_hive_mutated" #define XENO_HIVE_FORSAKEN "xeno_hive_forsaken" #define XENO_HIVE_YAUTJA "xeno_hive_yautja" +#define XENO_HIVE_RENEGADE "xeno_hive_renegade" -#define ALL_XENO_HIVES list(XENO_HIVE_NORMAL, XENO_HIVE_CORRUPTED, XENO_HIVE_ALPHA, XENO_HIVE_BRAVO, XENO_HIVE_CHARLIE, XENO_HIVE_DELTA, XENO_HIVE_FERAL, XENO_HIVE_TAMED, XENO_HIVE_MUTATED, XENO_HIVE_FORSAKEN, XENO_HIVE_YAUTJA) +#define ALL_XENO_HIVES list(XENO_HIVE_NORMAL, XENO_HIVE_CORRUPTED, XENO_HIVE_ALPHA, XENO_HIVE_BRAVO, XENO_HIVE_CHARLIE, XENO_HIVE_DELTA, XENO_HIVE_FERAL, XENO_HIVE_TAMED, XENO_HIVE_MUTATED, XENO_HIVE_FORSAKEN, XENO_HIVE_YAUTJA, XENO_HIVE_RENEGADE) //================================================= diff --git a/code/__DEFINES/typecheck/xenos.dm b/code/__DEFINES/typecheck/xenos.dm index d313090e8305..34b70ac92f45 100644 --- a/code/__DEFINES/typecheck/xenos.dm +++ b/code/__DEFINES/typecheck/xenos.dm @@ -37,6 +37,10 @@ if(!hive) return FALSE + if(hivenumber == XENO_HIVE_RENEGADE) + var/datum/hive_status/corrupted/renegade/renegade_hive = hive + return renegade_hive.iff_protection_check(src, attempt_harm_mob) + return hive.is_ally(attempt_harm_mob) // need this to set the data for walls/eggs/huggers when they are initialized diff --git a/code/_globalvars/global_lists.dm b/code/_globalvars/global_lists.dm index 7e65cfecd8b0..36058a44fc37 100644 --- a/code/_globalvars/global_lists.dm +++ b/code/_globalvars/global_lists.dm @@ -177,7 +177,8 @@ GLOBAL_LIST_INIT_TYPED(hive_datum, /datum/hive_status, list( XENO_HIVE_TAMED = new /datum/hive_status/corrupted/tamed(), XENO_HIVE_MUTATED = new /datum/hive_status/mutated(), XENO_HIVE_FORSAKEN = new /datum/hive_status/forsaken(), - XENO_HIVE_YAUTJA = new /datum/hive_status/yautja() + XENO_HIVE_YAUTJA = new /datum/hive_status/yautja(), + XENO_HIVE_RENEGADE = new /datum/hive_status/corrupted/renegade(), )) GLOBAL_LIST_INIT(xeno_evolve_times, setup_xeno_evolve_times()) diff --git a/code/modules/mob/living/carbon/xenomorph/Evolution.dm b/code/modules/mob/living/carbon/xenomorph/Evolution.dm index 4806f7528582..d8767ffce87a 100644 --- a/code/modules/mob/living/carbon/xenomorph/Evolution.dm +++ b/code/modules/mob/living/carbon/xenomorph/Evolution.dm @@ -39,7 +39,7 @@ if(!evolve_checks()) return - if((!hive.living_xeno_queen) && castepick != XENO_CASTE_QUEEN && !islarva(src) && !hive.allow_no_queen_actions) + if((!hive.living_xeno_queen) && castepick != XENO_CASTE_QUEEN && !islarva(src) && !hive.allow_no_queen_evo) to_chat(src, SPAN_WARNING("The Hive is shaken by the death of the last Queen. You can't find the strength to evolve.")) return diff --git a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm index 09fdb42ad5c3..667367339698 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm @@ -71,7 +71,7 @@ if(caste && caste.evolution_allowed) evolve_progress = "[min(stored_evolution, evolution_threshold)]/[evolution_threshold]" - if(hive && !hive.allow_no_queen_actions && !caste?.evolve_without_queen) + if(hive && !hive.allow_no_queen_evo && !caste?.evolve_without_queen) if(!hive.living_xeno_queen) evolve_progress += " (NO QUEEN)" else if(!(hive.living_xeno_queen.ovipositor || hive.evolution_without_ovipositor)) diff --git a/code/modules/mob/living/carbon/xenomorph/damage_procs.dm b/code/modules/mob/living/carbon/xenomorph/damage_procs.dm index c26e38202200..51ceee153368 100644 --- a/code/modules/mob/living/carbon/xenomorph/damage_procs.dm +++ b/code/modules/mob/living/carbon/xenomorph/damage_procs.dm @@ -29,6 +29,8 @@ user.put_in_hands(iff_tag) iff_tag = null user.visible_message(SPAN_NOTICE("[user] removes \the [src]'s IFF tag."), SPAN_NOTICE("You remove \the [src]'s IFF tag."), max_distance = 3) + if(hive.hivenumber == XENO_HIVE_RENEGADE) //it's important to know their IFF settings for renegade + to_chat(src, SPAN_NOTICE("With the removal of the device, your instincts have returned to normal.")) return return ..() diff --git a/code/modules/mob/living/carbon/xenomorph/hive_faction.dm b/code/modules/mob/living/carbon/xenomorph/hive_faction.dm index 1eb5818674fd..10af37b8d8e8 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_faction.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_faction.dm @@ -57,4 +57,5 @@ GLOBAL_LIST_INIT(hive_alliable_factions, generate_alliable_factions()) var/should_ally = text2num(params["should_ally"]) assoc_hive.allies[params["target_faction"]] = should_ally + assoc_hive.on_stance_change(params["target_faction"]) . = TRUE diff --git a/code/modules/mob/living/carbon/xenomorph/items/iff_tag.dm b/code/modules/mob/living/carbon/xenomorph/items/iff_tag.dm index cde9cd072a95..4c63fc2b5923 100644 --- a/code/modules/mob/living/carbon/xenomorph/items/iff_tag.dm +++ b/code/modules/mob/living/carbon/xenomorph/items/iff_tag.dm @@ -19,6 +19,8 @@ injector.visible_message(SPAN_NOTICE("[injector] forces \the [src] into [xeno]'s carapace!"), SPAN_NOTICE("You force \the [src] into [xeno]'s carapace!")) xeno.iff_tag = src injector.drop_inv_item_to_loc(src, xeno) + if(xeno.hive.hivenumber == XENO_HIVE_RENEGADE) //it's important to know their IFF settings for renegade + to_chat(xeno, SPAN_NOTICE("With the insertion of the device into your carapace, your instincts have changed compelling you to protect [english_list(faction_groups, "no one")].")) return return ..() @@ -48,6 +50,8 @@ if("Remove") faction_groups = list() to_chat(programmer, SPAN_NOTICE("You [option] the IFF group data, the IFF group on the tag now reads as: [english_list(faction_groups, "None")]")) + if(xeno?.hive.hivenumber == XENO_HIVE_RENEGADE) //it's important to know their IFF settings for renegade + to_chat(xeno, SPAN_NOTICE("Your instincts have changed, you seem compelled to protect [english_list(faction_groups, "no one")].")) return TRUE /obj/item/iff_tag/pmc_handler diff --git a/code/modules/mob/living/carbon/xenomorph/life.dm b/code/modules/mob/living/carbon/xenomorph/life.dm index 842e3b45a76d..6f9a667642e3 100644 --- a/code/modules/mob/living/carbon/xenomorph/life.dm +++ b/code/modules/mob/living/carbon/xenomorph/life.dm @@ -42,7 +42,7 @@ var/progress_amount = 1 if(SSxevolution) progress_amount = SSxevolution.get_evolution_boost_power(hive.hivenumber) - var/ovipositor_check = (hive.allow_no_queen_actions || hive.evolution_without_ovipositor || (hive.living_xeno_queen && hive.living_xeno_queen.ovipositor)) + var/ovipositor_check = (hive.allow_no_queen_evo || hive.evolution_without_ovipositor || (hive.living_xeno_queen && hive.living_xeno_queen.ovipositor)) if(caste && caste.evolution_allowed && (ovipositor_check || caste?.evolve_without_queen)) if(evolution_stored >= evolution_threshold) if(!got_evolution_message) @@ -334,11 +334,6 @@ Make sure their actual health updates immediately.*/ if(!T || !istype(T)) return - var/is_runner_hiding - - if(isrunner(src) && layer != initial(layer)) - is_runner_hiding = 1 - if(caste) if(caste.innate_healing || check_weeds_for_healing()) if(!hive) return // can't heal if you have no hive, sorry bud @@ -369,9 +364,8 @@ Make sure their actual health updates immediately.*/ if(armor_integrity > armor_integrity_max) armor_integrity = armor_integrity_max - else //Xenos restore plasma VERY slowly off weeds, regardless of health, as long as they are not using special abilities - if(prob(50) && !is_runner_hiding && !current_aura) - plasma_stored += 0.1 * plasma_max / 100 + else if(prob(50) && !current_aura) //Xenos restore plasma VERY slowly off weeds, regardless of health, as long as they are not using special abilities + plasma_stored += 0.1 * plasma_max / 100 for(var/datum/action/xeno_action/action in src.actions) diff --git a/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm b/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm index b30ea73cd680..bb58d2cf2a03 100644 --- a/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm +++ b/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm @@ -295,8 +295,9 @@ var/evolution_bonus = 0 var/allow_no_queen_actions = FALSE + var/allow_no_queen_evo = FALSE var/evolution_without_ovipositor = TRUE //Temporary for the roundstart. - /// Set to true if you want to prevent evolutions into Queens + /// Set to false if you want to prevent evolutions into Queens var/allow_queen_evolve = TRUE /// Set to true if you want to prevent bursts and spawns of new xenos. Will also prevent healing if the queen no longer exists var/hardcore = FALSE @@ -1112,13 +1113,15 @@ need_round_end_check = TRUE -/datum/hive_status/corrupted/add_xeno(mob/living/carbon/xenomorph/X) + var/list/defectors = list() + +/datum/hive_status/corrupted/add_xeno(mob/living/carbon/xenomorph/xeno) . = ..() - X.add_language(LANGUAGE_ENGLISH) + xeno.add_language(LANGUAGE_ENGLISH) -/datum/hive_status/corrupted/remove_xeno(mob/living/carbon/xenomorph/X, hard) +/datum/hive_status/corrupted/remove_xeno(mob/living/carbon/xenomorph/xeno, hard) . = ..() - X.remove_language(LANGUAGE_ENGLISH) + xeno.remove_language(LANGUAGE_ENGLISH) /datum/hive_status/corrupted/can_delay_round_end(mob/living/carbon/xenomorph/xeno) if(!faction_is_ally(FACTION_MARINE, TRUE)) @@ -1181,6 +1184,7 @@ destruction_allowed = XENO_NOBODY dynamic_evolution = FALSE allow_no_queen_actions = TRUE + allow_no_queen_evo = TRUE allow_queen_evolve = FALSE ignore_slots = TRUE latejoin_burrowed = FALSE @@ -1195,6 +1199,7 @@ dynamic_evolution = FALSE allow_no_queen_actions = TRUE + allow_no_queen_evo = TRUE allow_queen_evolve = FALSE ignore_slots = TRUE latejoin_burrowed = FALSE @@ -1212,6 +1217,7 @@ dynamic_evolution = FALSE allow_no_queen_actions = TRUE + allow_no_queen_evo = TRUE allow_queen_evolve = FALSE ignore_slots = TRUE latejoin_burrowed = FALSE @@ -1241,6 +1247,7 @@ dynamic_evolution = FALSE allow_no_queen_actions = TRUE + allow_no_queen_evo = TRUE allow_queen_evolve = FALSE ignore_slots = TRUE latejoin_burrowed = FALSE @@ -1296,6 +1303,123 @@ return ..() +/datum/hive_status/corrupted/renegade + name = "Renegade Hive" + reporting_id = "renegade" + hivenumber = XENO_HIVE_RENEGADE + prefix = "Renegade " + color = "#9c7a4d" + ui_color ="#80705c" + + dynamic_evolution = FALSE + allow_queen_evolve = FALSE + allow_no_queen_evo = TRUE + latejoin_burrowed = FALSE + +/datum/hive_status/corrupted/renegade/New() + . = ..() + hive_structures_limit[XENO_STRUCTURE_EGGMORPH] = 0 + hive_structures_limit[XENO_STRUCTURE_EVOPOD] = 0 + for(var/faction in FACTION_LIST_HUMANOID) //renegades allied to all humanoids, but it mostly affects structures. Their ability to attack humanoids and other xenos (including of the same hive) depends on iff settings + allies[faction] = TRUE + +/datum/hive_status/corrupted/renegade/can_spawn_as_hugger(mob/dead/observer/user) + to_chat(user, SPAN_WARNING("The [name] cannot support facehuggers.")) + return FALSE + +/datum/hive_status/corrupted/renegade/proc/iff_protection_check(mob/living/carbon/xenomorph/xeno, mob/living/carbon/attempt_harm_mob) + if(xeno == attempt_harm_mob) + return TRUE //you cannot hurt yourself... + if(!xeno.iff_tag) + return FALSE //can attack anyone if you don't have iff tag + if(isxeno(attempt_harm_mob)) + var/mob/living/carbon/xenomorph/target_xeno = attempt_harm_mob + if(!target_xeno.iff_tag) + return FALSE //can attack any xeno who don't have iff tag + for(var/faction in xeno.iff_tag.faction_groups) + if(faction in target_xeno.iff_tag.faction_groups) + return TRUE //cannot attack xenos with same iff setting + return FALSE + for(var/faction in xeno.iff_tag.faction_groups) + if(faction in attempt_harm_mob.faction_group) + return TRUE //cannot attack mob if iff is set to at least one of its factions + return FALSE + +/datum/hive_status/corrupted/renegade/faction_is_ally(faction, ignore_queen_check = TRUE) + return ..() + +/datum/hive_status/proc/on_stance_change(faction) + if(!living_xeno_queen) + return + if(allies[faction]) + xeno_message(SPAN_XENOANNOUNCE("Your Queen set up an alliance with [faction]!"), 3, hivenumber) + else + xeno_message(SPAN_XENOANNOUNCE("Your Queen broke the alliance with [faction]!"), 3, hivenumber) + + for(var/number in GLOB.hive_datum) + var/datum/hive_status/target_hive = GLOB.hive_datum[number] + if(target_hive.name != faction) + continue + if(!target_hive.living_xeno_queen && !target_hive.allow_no_queen_actions) + return + if(allies[faction]) + xeno_message(SPAN_XENOANNOUNCE("You sense that [name] Queen set up an alliance with us!"), 3, target_hive.hivenumber) + return + + xeno_message(SPAN_XENOANNOUNCE("You sense that [name] Queen broke the alliance with us!"), 3, target_hive.hivenumber) + +/datum/hive_status/corrupted/on_stance_change(faction) + . = ..() + if(allies[faction]) + return + if(!(faction in FACTION_LIST_HUMANOID)) + return + + for(var/mob/living/carbon/xenomorph/xeno in totalXenos) // handle defecting xenos on betrayal + if(!xeno.iff_tag) + continue + if(!(faction in xeno.iff_tag.faction_groups)) + continue + if(xeno in defectors) + continue + if(xeno.caste_type == XENO_CASTE_QUEEN) + continue + INVOKE_ASYNC(src, PROC_REF(give_defection_choice), xeno, faction) + addtimer(CALLBACK(src, PROC_REF(handle_defectors), faction), 11 SECONDS) + +/datum/hive_status/corrupted/proc/give_defection_choice(mob/living/carbon/xenomorph/xeno, faction) + if(tgui_alert(xeno, "Your Queen has broken the alliance with the [faction]. The device inside your carapace begins to suppress your connection with the Hive. Do you remove it and stay loyal to her?", "Alliance broken!", list("Stay loyal", "Obey the talls"), 10 SECONDS) == "Obey the talls") + if(!xeno.iff_tag) + to_chat(xeno, SPAN_XENOWARNING("It's too late now. The device is gone and your service to the Queen continues.")) + return + defectors += xeno + xeno.set_hive_and_update(XENO_HIVE_RENEGADE) + to_chat(xeno, SPAN_XENOANNOUNCE("You lost the connection with your Hive. Now you have no Queen, only your masters.")) + to_chat(xeno, SPAN_NOTICE("Your instincts have changed, you seem compelled to protect [english_list(xeno.iff_tag.faction_groups, "no one")].")) + return + xeno.visible_message(SPAN_XENOWARNING("[xeno] rips out [xeno.iff_tag]!"), SPAN_XENOWARNING("You rip out [xeno.iff_tag]! For the Hive!")) + xeno.adjustBruteLoss(50) + xeno.iff_tag.forceMove(get_turf(xeno)) + xeno.iff_tag = null + +/datum/hive_status/corrupted/proc/handle_defectors(faction) + for(var/mob/living/carbon/xenomorph/xeno in totalXenos) + if(!xeno.iff_tag) + continue + if(xeno in defectors) + continue + if(!(faction in xeno.iff_tag.faction_groups)) + continue + xeno.visible_message(SPAN_XENOWARNING("[xeno] rips out [xeno.iff_tag]!"), SPAN_XENOWARNING("You rip out [xeno.iff_tag]! For the hive!")) + xeno.adjustBruteLoss(50) + xeno.iff_tag.forceMove(get_turf(xeno)) + xeno.iff_tag = null + if(!length(defectors)) + return + + xeno_message(SPAN_XENOANNOUNCE("You sense that [english_list(defectors)] turned their backs against their sisters and the Queen in favor of their slavemasters!"), 3, hivenumber) + defectors.Cut() + //Xeno Resin Mark Shit, the very best place for it too :0) //Defines at the bottom of this list here will show up at the top in the mark menu /datum/xeno_mark_define diff --git a/code/modules/mob/living/carbon/xenomorph/xeno_verbs.dm b/code/modules/mob/living/carbon/xenomorph/xeno_verbs.dm index 6b37145ad7a1..583d26de3ee5 100644 --- a/code/modules/mob/living/carbon/xenomorph/xeno_verbs.dm +++ b/code/modules/mob/living/carbon/xenomorph/xeno_verbs.dm @@ -25,6 +25,13 @@ if(!hive) return + if(hive.hivenumber == XENO_HIVE_RENEGADE) //Renegade's ability to attack someone depends on IFF settings, not on alliance + if(!iff_tag) + to_chat(src, SPAN_NOTICE("You are not obligated to protect anyone.")) + return + to_chat(src, SPAN_NOTICE("You seem compelled to protect [english_list(iff_tag.faction_groups, "no one")].")) + return + if((!hive.living_xeno_queen || Check_WO()) && !hive.allow_no_queen_actions) //No Hive status on WO to_chat(src, SPAN_WARNING("There is no Queen. You are alone.")) return