From a7b4328d406d112fbcb97df3d5ae250b8cfe879b Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Mon, 22 Jan 2024 15:05:19 +0000 Subject: [PATCH 01/17] Initial Framework oh boy here we go --- code/__HELPERS/logging.dm | 6 +- code/_globalvars/global_lists.dm | 4 +- code/game/world.dm | 4 +- code/modules/logging/global_logs.dm | 4 +- .../carbon/xenomorph/XenoMutatorSets.dm | 264 ------------------ .../mob/living/carbon/xenomorph/Xenomorph.dm | 33 +-- .../carbon/xenomorph/mutators/mutator.dm | 103 ------- .../behavior_delegate.dm | 0 .../castes}/boiler/trapper.dm | 0 .../castes}/carrier/eggsac.dm | 0 .../castes}/crusher/charger.dm | 0 .../castes}/defender/steel_crest.dm | 0 .../castes}/drone/gardener.dm | 0 .../castes}/drone/healer.dm | 0 .../castes}/hivelord/resin_whisperer.dm | 0 .../castes}/lurker/vampire.dm | 0 .../castes}/praetorian/dancer.dm | 0 .../castes}/praetorian/oppressor.dm | 0 .../castes}/praetorian/vanguard.dm | 0 .../castes}/praetorian/warden.dm | 0 .../castes}/ravager/berserker.dm | 0 .../castes}/ravager/hedgehog.dm | 0 .../strains => strains/castes}/runner/acid.dm | 0 .../carbon/xenomorph/strains/xeno_strain.dm | 116 ++++++++ .../living/carbon/xenomorph/update_icons.dm | 4 +- colonialmarines.dme | 35 ++- 26 files changed, 157 insertions(+), 416 deletions(-) delete mode 100644 code/modules/mob/living/carbon/xenomorph/XenoMutatorSets.dm delete mode 100644 code/modules/mob/living/carbon/xenomorph/mutators/mutator.dm rename code/modules/mob/living/carbon/xenomorph/{mutators => strains}/behavior_delegate.dm (100%) rename code/modules/mob/living/carbon/xenomorph/{mutators/strains => strains/castes}/boiler/trapper.dm (100%) rename code/modules/mob/living/carbon/xenomorph/{mutators/strains => strains/castes}/carrier/eggsac.dm (100%) rename code/modules/mob/living/carbon/xenomorph/{mutators/strains => strains/castes}/crusher/charger.dm (100%) rename code/modules/mob/living/carbon/xenomorph/{mutators/strains => strains/castes}/defender/steel_crest.dm (100%) rename code/modules/mob/living/carbon/xenomorph/{mutators/strains => strains/castes}/drone/gardener.dm (100%) rename code/modules/mob/living/carbon/xenomorph/{mutators/strains => strains/castes}/drone/healer.dm (100%) rename code/modules/mob/living/carbon/xenomorph/{mutators/strains => strains/castes}/hivelord/resin_whisperer.dm (100%) rename code/modules/mob/living/carbon/xenomorph/{mutators/strains => strains/castes}/lurker/vampire.dm (100%) rename code/modules/mob/living/carbon/xenomorph/{mutators/strains => strains/castes}/praetorian/dancer.dm (100%) rename code/modules/mob/living/carbon/xenomorph/{mutators/strains => strains/castes}/praetorian/oppressor.dm (100%) rename code/modules/mob/living/carbon/xenomorph/{mutators/strains => strains/castes}/praetorian/vanguard.dm (100%) rename code/modules/mob/living/carbon/xenomorph/{mutators/strains => strains/castes}/praetorian/warden.dm (100%) rename code/modules/mob/living/carbon/xenomorph/{mutators/strains => strains/castes}/ravager/berserker.dm (100%) rename code/modules/mob/living/carbon/xenomorph/{mutators/strains => strains/castes}/ravager/hedgehog.dm (100%) rename code/modules/mob/living/carbon/xenomorph/{mutators/strains => strains/castes}/runner/acid.dm (100%) create mode 100644 code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm diff --git a/code/__HELPERS/logging.dm b/code/__HELPERS/logging.dm index c20db3da303f..d6c18c8a93be 100644 --- a/code/__HELPERS/logging.dm +++ b/code/__HELPERS/logging.dm @@ -209,10 +209,10 @@ GLOBAL_VAR_INIT(log_end, world.system_type == UNIX ? ascii2text(13) : "") WRITE_LOG(GLOB.world_game_log, "MISC: [text]") GLOB.STUI?.debug.Add("\[[time]]MISC: [text]") -/proc/log_mutator(text) - if(!GLOB.mutator_logs) +/proc/log_strain(text) + if(!GLOB.strain_logs) return - WRITE_LOG(GLOB.mutator_logs, "[text]") + WRITE_LOG(GLOB.strain_logs, "[text]") /proc/log_hiveorder(text) var/time = time_stamp() diff --git a/code/_globalvars/global_lists.dm b/code/_globalvars/global_lists.dm index 66eaf13df282..00a3bc256e6a 100644 --- a/code/_globalvars/global_lists.dm +++ b/code/_globalvars/global_lists.dm @@ -163,8 +163,8 @@ GLOBAL_LIST_INIT(language_keys, setup_language_keys()) //table of say codes for GLOBAL_REFERENCE_LIST_INDEXED(origins, /datum/origin, name) GLOBAL_LIST_INIT(player_origins, USCM_ORIGINS) -//Xeno mutators -GLOBAL_REFERENCE_LIST_INDEXED_SORTED(xeno_mutator_list, /datum/xeno_mutator, name) +//Xeno strains +GLOBAL_SUBTYPE_PATHS_LIST_INDEXED(xeno_strain_list, /datum/xeno_strain, name) //Xeno hives GLOBAL_LIST_INIT_TYPED(hive_datum, /datum/hive_status, list( diff --git a/code/game/world.dm b/code/game/world.dm index f68263412715..8a93f89a43f6 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -129,7 +129,7 @@ GLOBAL_LIST_INIT(reboot_sfx, file2list("config/reboot_sfx.txt")) GLOB.world_runtime_log = "[GLOB.log_directory]/runtime.log" GLOB.round_stats = "[GLOB.log_directory]/round_stats.log" GLOB.scheduler_stats = "[GLOB.log_directory]/round_scheduler_stats.log" - GLOB.mutator_logs = "[GLOB.log_directory]/mutator_logs.log" + GLOB.strain_logs = "[GLOB.log_directory]/strain_logs.log" start_log(GLOB.tgui_log) start_log(GLOB.world_href_log) @@ -138,7 +138,7 @@ GLOBAL_LIST_INIT(reboot_sfx, file2list("config/reboot_sfx.txt")) start_log(GLOB.world_runtime_log) start_log(GLOB.round_stats) start_log(GLOB.scheduler_stats) - start_log(GLOB.mutator_logs) + start_log(GLOB.strain_logs) if(fexists(GLOB.config_error_log)) fcopy(GLOB.config_error_log, "[GLOB.log_directory]/config_error.log") diff --git a/code/modules/logging/global_logs.dm b/code/modules/logging/global_logs.dm index ff384fe537c0..e0055907d67a 100644 --- a/code/modules/logging/global_logs.dm +++ b/code/modules/logging/global_logs.dm @@ -25,8 +25,8 @@ GLOBAL_PROTECT(world_runtime_log) GLOBAL_VAR(scheduler_stats) GLOBAL_PROTECT(scheduler_stats) -GLOBAL_VAR(mutator_logs) -GLOBAL_PROTECT(mutator_logs) +GLOBAL_VAR(strain_logs) +GLOBAL_PROTECT(strain_logs) GLOBAL_VAR(round_stats) GLOBAL_PROTECT(round_stats) diff --git a/code/modules/mob/living/carbon/xenomorph/XenoMutatorSets.dm b/code/modules/mob/living/carbon/xenomorph/XenoMutatorSets.dm deleted file mode 100644 index fc5532955ff9..000000000000 --- a/code/modules/mob/living/carbon/xenomorph/XenoMutatorSets.dm +++ /dev/null @@ -1,264 +0,0 @@ -#define MUTATOR_GAIN_PER_QUEEN_LEVEL 6 -#define MUTATOR_GAIN_PER_XENO_LEVEL 3 - -//A class that holds mutators for a given Xeno hive -//Each time a Queen matures, the hive gets more points -//Each time a Queen dies, the mutators are reset - -//The class contains a lot of variables that are applied to various xenos' stats and actions -/datum/mutator_set - var/remaining_points = 1 //How many points the xeno / hive still has to spend on mutators - var/list/purchased_mutators = list() //List of purchased mutators - var/user_level = 0 //Level of the Queen for Hive or the individual xeno. Starting at -1 so at tier 0 you'd get some mutators to play with - - var/tackle_strength_bonus = 0 - -//Functions to be overloaded to call for when something gets updated on the xenos -/datum/mutator_set/proc/recalculate_everything(description) -/datum/mutator_set/proc/recalculate_stats(description) -/datum/mutator_set/proc/recalculate_actions(description) -/datum/mutator_set/proc/recalculate_pheromones(description) -/datum/mutator_set/proc/give_feedback(description) - - -/datum/mutator_set/proc/purchase_mutator(name) - return FALSE - -/datum/mutator_set/proc/list_and_purchase_mutators() - var/list/mutators_for_purchase = available_mutators() - var/mob/living/carbon/xenomorph/Xeno = usr - if(mutators_for_purchase.len == 0) - to_chat(usr, "There are no available strains.") - var/pick = tgui_input_list(usr, "Which strain would you like to purchase?", "Purchase strain", mutators_for_purchase, theme="hive_status") - if(!pick) - return FALSE - if(alert(usr, "[GLOB.xeno_mutator_list[pick].description]\n\nConfirm mutation?", "Strain purchase", "Yes", "No") != "Yes") return - if(!Xeno.strain_checks()) - return - if(GLOB.xeno_mutator_list[pick].apply_mutator(src)) - to_chat(usr, "Mutation complete!") - return TRUE - else - to_chat(usr, "Mutation failed!") - return FALSE - -/datum/mutator_set/proc/can_purchase_mutator(mutator_name) - var/datum/xeno_mutator/XM = GLOB.xeno_mutator_list[mutator_name] - if(user_level < XM.required_level) - return FALSE //xeno doesn't meet the level requirements - if(remaining_points < XM.cost) - return FALSE //mutator is too expensive - if(XM.unique) - if(XM.name in purchased_mutators) - return FALSE //unique mutator already purchased - if(XM.keystone) - for(var/name in purchased_mutators) - if(GLOB.xeno_mutator_list[name].keystone) - return FALSE //We already have a keystone mutator - if(XM.flaw) - for(var/name in purchased_mutators) - if(GLOB.xeno_mutator_list[name].flaw) - return FALSE //We already have a flaw mutator - return TRUE - -//Lists mutators available for purchase -/datum/mutator_set/proc/available_mutators() - var/list/can_purchase = list() - - for(var/str in GLOB.xeno_mutator_list) - if (can_purchase_mutator(str)) - can_purchase += str //can purchase! - - return can_purchase - -//Mutators applying to the Hive as a whole -/datum/mutator_set/hive_mutators - var/datum/hive_status/hive //Which hive do these mutators apply to. Need this to affect variables there - var/leader_count_boost = 0 - var/maturation_multiplier = 1 - var/tier_slot_multiplier = 1 - var/larva_gestation_multiplier = 1 - var/bonus_larva_spawn_chance = 0 - -/datum/mutator_set/hive_mutators/list_and_purchase_mutators() - if(!hive || !hive.living_xeno_queen) - return //somehow Queen is not set but this function was called... - if(hive.living_xeno_queen.is_dead()) - return //Dead xenos can't mutate! - if(hive.living_xeno_queen.hardcore) - to_chat(usr, SPAN_WARNING("No time for that, must KILL!")) - return - if(!hive.living_xeno_queen.ovipositor) - to_chat(usr, "You must be in Ovipositor to purchase Hive Mutators.") - return - . = ..() - if (. == TRUE && purchased_mutators.len) - var/m = purchased_mutators[purchased_mutators.len] - log_mutator("[hive.living_xeno_queen.name] purchased Hive Mutator '[m]'") - -/datum/mutator_set/hive_mutators/can_purchase_mutator(mutator_name) - if (..() == FALSE) - return FALSE //Can't buy it regardless - var/datum/xeno_mutator/XM = GLOB.xeno_mutator_list[mutator_name] - if(XM.individual_only) - return FALSE //We can't buy individual mutators on a Hive level - return TRUE - -//Called when the Queen dies -// This isn't currently used, but if anyone wants to, expect it to be broken because -// I haven't made any effort to integrate it into the new system (Fourkhan, 5/11/19) -/datum/mutator_set/hive_mutators/proc/reset_mutators() - if(purchased_mutators.len == 0) - //No mutators purchased, nothing to reset! - return - - var/depowered = FALSE - for(var/name in purchased_mutators) - if(!GLOB.xeno_mutator_list[name].death_persistent) - purchased_mutators -= name - depowered = TRUE - - if(!depowered) - return //We haven't lost anything - - tackle_strength_bonus = 0 - - leader_count_boost = 0 - maturation_multiplier = 1 - tier_slot_multiplier = 1 - larva_gestation_multiplier = 1 - bonus_larva_spawn_chance = 0 - - for(var/mob/living/carbon/xenomorph/X in GLOB.living_xeno_list) - if(X.hivenumber == hive.hivenumber) - X.recalculate_everything() - to_chat(X, SPAN_XENOANNOUNCE("Queen's influence wanes. You feel weak!")) - playsound(X.loc, "alien_help", 25) - X.xeno_jitter(15) - -/datum/mutator_set/hive_mutators/recalculate_everything(description) - for(var/mob/living/carbon/xenomorph/X in GLOB.living_xeno_list) - if(X.hivenumber == hive.hivenumber) - X.recalculate_everything() - to_chat(X, SPAN_XENOANNOUNCE("Queen has granted the Hive a boon! [description]")) - X.xeno_jitter(15) -/datum/mutator_set/hive_mutators/recalculate_stats(description) - for(var/mob/living/carbon/xenomorph/X in GLOB.living_xeno_list) - if(X.hivenumber == hive.hivenumber) - X.recalculate_stats() - to_chat(X, SPAN_XENOANNOUNCE("Queen has granted the Hive a boon! [description]")) - X.xeno_jitter(15) -/datum/mutator_set/hive_mutators/recalculate_actions(description) - for(var/mob/living/carbon/xenomorph/X in GLOB.living_xeno_list) - if(X.hivenumber == hive.hivenumber) - X.recalculate_actions() - to_chat(X, SPAN_XENOANNOUNCE("Queen has granted the Hive a boon! [description]")) - X.xeno_jitter(15) -/datum/mutator_set/hive_mutators/recalculate_pheromones(description) - for(var/mob/living/carbon/xenomorph/X in GLOB.living_xeno_list) - if(X.hivenumber == hive.hivenumber) - X.recalculate_pheromones() - to_chat(X, SPAN_XENOANNOUNCE("Queen has granted the Hive a boon! [description]")) - X.xeno_jitter(15) -/datum/mutator_set/hive_mutators/proc/recalculate_maturation(description) - for(var/mob/living/carbon/xenomorph/X in GLOB.living_xeno_list) - if(X.hivenumber == hive.hivenumber) - X.recalculate_maturation() - to_chat(X, SPAN_XENOANNOUNCE("Queen has granted the Hive a boon! [description]")) - X.xeno_jitter(15) -/datum/mutator_set/hive_mutators/proc/recalculate_hive(description) - hive.recalculate_hive() - give_feedback(description) -/datum/mutator_set/hive_mutators/give_feedback(description) - for(var/mob/living/carbon/xenomorph/X in GLOB.living_xeno_list) - if(X.hivenumber == hive.hivenumber) - to_chat(X, SPAN_XENOANNOUNCE("Queen has granted the Hive a boon! [description]")) - X.xeno_jitter(15) - -//Mutators applying to an individual xeno -/datum/mutator_set/individual_mutators - var/mob/living/carbon/xenomorph/xeno - var/pull_multiplier = 1 - var/egg_laying_multiplier = 1 - var/need_weeds = TRUE - //Strains Below - remaining_points = 6 - - -/datum/mutator_set/individual_mutators/Destroy() - if(xeno) - xeno.mutators = null - xeno = null - . = ..() - -/datum/mutator_set/individual_mutators/list_and_purchase_mutators() - . = ..() - if (. == TRUE && purchased_mutators.len) - var/m = purchased_mutators[purchased_mutators.len] - log_mutator("[xeno.name] purchased Mutator '[m]'") - -/datum/mutator_set/individual_mutators/can_purchase_mutator(mutator_name) - if (..() == FALSE) - return FALSE //Can't buy it regardless - var/datum/xeno_mutator/XM = GLOB.xeno_mutator_list[mutator_name] - if(XM.hive_only) - return FALSE //We can't buy Hive mutators on an individual level - if(XM.caste_whitelist && (XM.caste_whitelist.len > 0) && !(xeno.caste_type in XM.caste_whitelist)) - return FALSE //We are not on the whitelist - return TRUE - -/datum/mutator_set/individual_mutators/recalculate_actions(description, flavor_description = null) - xeno.recalculate_actions() - to_chat(xeno, SPAN_XENOANNOUNCE("[description]")) - if (flavor_description != null) - to_chat(xeno, SPAN_XENOLEADER("[flavor_description]")) - xeno.xeno_jitter(15) - - -/mob/living/carbon/xenomorph/queen/verb/purchase_hive_mutators() - set name = "Purchase Hive Mutators" - set desc = "Purchase Mutators affecting the entire Hive." - set category = "Alien" - if(hardcore) - to_chat(usr, SPAN_WARNING("No time for that, must KILL!")) - return - if(!src.hive || !src.hive.mutators) - return //For some reason we don't have mutators - src.hive.mutators.list_and_purchase_mutators() - -/mob/living/carbon/xenomorph/verb/purchase_strains() - set name = "Purchase Strains" - set desc = "Purchase Strains for yourself." - set category = "Alien" - - if(!strain_checks()) - return - if(!src.mutators) - return //For some reason we don't have mutators - src.mutators.list_and_purchase_mutators() - -/mob/living/carbon/xenomorph/proc/strain_checks() - if(!check_state(TRUE)) - return FALSE - - if(is_ventcrawling) - to_chat(src, SPAN_WARNING("This place is too constraining to take a strain.")) - return FALSE - - if(!isturf(loc)) - to_chat(src, SPAN_WARNING("We can't take a strain here.")) - return FALSE - - if(handcuffed || legcuffed) - to_chat(src, SPAN_WARNING("The restraints are too restricting to allow us to take a strain.")) - return FALSE - - if(health < maxHealth) - to_chat(src, SPAN_WARNING("We must be at full health to take a strain.")) - return FALSE - - if(agility || fortify || crest_defense || stealth) - to_chat(src, SPAN_WARNING("We cannot take a strain while in this stance.")) - return FALSE - - return TRUE diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index fc25c80e795f..6aedbb24d0a2 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -130,10 +130,11 @@ var/weed_level = WEED_LEVEL_STANDARD var/acid_level = 0 - // Mutator-related and other important vars - var/mutation_icon_state = null - var/mutation_type = null - var/datum/mutator_set/individual_mutators/mutators = new + // Strain-related vars + /// A list of strain typepaths that the xeno is able to choose. + var/list/available_strains = list() + /// The xeno's strain, if they've taken one. + var/datum/xeno_strain/chosen_strain = null // Hive-related vars var/datum/hive_status/hive @@ -389,8 +390,6 @@ for(var/trait in hive.hive_inherant_traits) ADD_TRAIT(src, trait, TRAIT_SOURCE_HIVE) - mutators.xeno = src - //Set caste stuff if(caste_type && GLOB.xeno_datum_list[caste_type]) caste = GLOB.xeno_datum_list[caste_type] @@ -661,8 +660,8 @@ . += "It appears to belong to [hive?.name ? "the [hive.name]" : "a different hive"]." if(isxeno(user) || isobserver(user)) - if(mutation_type != "Normal") - . += "It has specialized into a [mutation_type]." + if(chosen_strain) + . += "It has specialized into a [chosen_strain.name]." if(iff_tag) . += SPAN_NOTICE("It has an IFF tag sticking out of its carapace.") @@ -693,7 +692,7 @@ selected_ability = null queued_action = null - QDEL_NULL(mutators) + QDEL_NULL(chosen_strain) QDEL_NULL(behavior_delegate) built_structures = null @@ -709,18 +708,11 @@ if(hardcore) attack_log?.Cut() // Completely clear out attack_log to limit mem usage if we fail to delete - . = ..() - - // Everything below fits the "we have to clear by principle it but i dont wanna break stuff" bill - mutators = null - - + return ..() /mob/living/carbon/xenomorph/slip(slip_source_name, stun_level, weaken_level, run_only, override_noslip, slide_steps) return FALSE - - /mob/living/carbon/xenomorph/start_pulling(atom/movable/AM, lunge, no_msg) if(SEND_SIGNAL(AM, COMSIG_MOVABLE_XENO_START_PULLING, src) & COMPONENT_ALLOW_PULL) return do_pull(AM, lunge, no_msg) @@ -823,10 +815,10 @@ //*********************************************************// -//********************Mutator functions********************// +// ******************** Strain Procs **********************// //*********************************************************// -//Call this function when major changes happen - evolutions, upgrades, mutators getting removed +//Call this proc when major changes happen - evolutions, upgrades, mutators getting removed /mob/living/carbon/xenomorph/proc/recalculate_everything() recalculate_stats() recalculate_actions() @@ -1043,7 +1035,8 @@ handle_ghost_message() /mob/living/carbon/xenomorph/proc/handle_ghost_message() - notify_ghosts("[src] ([mutation_type] [caste_type]) has ghosted and their body is up for grabs!", source = src) + var/strain_name = chosen_strain ? chosen_strain.name : "Normal" + notify_ghosts("[src] ([strain_name] [caste_type]) has ghosted and their body is up for grabs!", source = src) /mob/living/carbon/xenomorph/larva/handle_ghost_message() if(locate(/obj/effect/alien/resin/special/pylon/core) in range(2, get_turf(src))) diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/mutator.dm b/code/modules/mob/living/carbon/xenomorph/mutators/mutator.dm deleted file mode 100644 index 6736bdb0419b..000000000000 --- a/code/modules/mob/living/carbon/xenomorph/mutators/mutator.dm +++ /dev/null @@ -1,103 +0,0 @@ -#define MUTATOR_COST_CHEAP 2 -#define MUTATOR_COST_MODERATE 3 -#define MUTATOR_COST_EXPENSIVE 1 - -//Individual mutator -/datum/xeno_mutator - var/name = "Mutator name" //Name of the mutator, should be short but informative - var/description = "Mutator description" //Description to be displayed on purchase - var/flavor_description = null // Optional flavor text to be shown. Semi-OOC - var/cost = MUTATOR_COST_CHEAP //How expensive the mutator is - var/required_level = 0 //Level of xeno upgrade required to unlock - var/unique = TRUE //True if you can only buy it once - var/death_persistent = FALSE //True if the mutators persists after Queen death (aka, mostly for "once ever" mutators) - var/hive_only = FALSE //Hive-only mutators - var/individual_only = FALSE //Individual-only mutators - var/keystone = FALSE //Xeno can only take one Keystone mutator - var/flaw = FALSE //Flaws give you points back, but you can only take one of them - var/list/caste_whitelist = list() //List of the only castes that can buy this mutator - - // Rework by Fourkhan - 4/26/19, redone again c. 2/2020 - // HOW TO ADD A NEW MUTATOR - // Step 0: Write an action(s) - // the "handler" procs go in the appropriate caste's subfolder under the "ABILITIES" file. - // the actual ACTION procs go in the appropriate caste's subfolder under the "POWERS" file. - // Any constants you need to access for your strain should be in the behavior holder and - // accessed using a cast to it using the mutator_type variable as defined below. (Or using an istype of the behavior holder) - // vars that absolutely must be held on the xenos themselves can be added to the Xenomorph class itself. - // Be sure to follow the spec in xeno_action.dm as far as setting up xeno_cooldown is concerned. - // - // Step 1: Write the Behavior Delegate datum IF NECESSARY - // the "behavior holder" datum defines all unique behavior and state for each xeno/strain. It works by embedding a number of 'hooks' - // for example, if you want to store bonus damage and apply it on slashes, behavior delegates are the way to do it. - // in common procs that call back to Xeno features. See other behavior delegates for examples. Afterward, set the behavior_delegate_type - // var on the strain datum to indicate which behavior holder to apply to your strain. - // - // Step 1: Copy/paste another datum definiton and edit it for your strain - // make sure to populate each of the variables listed above (at least as much as other strains) - // - // Step 2: Write the apply_mutator proc. - // FIRST: populate mutator_actions_to_add and mutator_actions_to_remove according to that documentation. - // THEN: write the body of the apply_mutator method according to your speficiations - // THEN: call mutator_update_actions on your xeno - // call recalculate actions on your mutator set (this should be auto populated) - // You should probably also call recalculate_everything() on the host Xeno to make sure you don't end up with any - // strange transient values. - // THEN: Set the mutation_type var on the host xeno to "name" the strain. - // FINALLY: Call apply_behavior_holder() to add the behavior datum to the new Xeno. - // - // You're done! - - // Both should be set to null when their use is not necessary. - /// A list of PATHS of actions that need to be removed when a xeno takes the mutator. - var/list/mutator_actions_to_remove //Actions to remove when the mutator is added - /// A list of PATHS of actions to be ADDED when the Xeno takes the mutator. - var/list/mutator_actions_to_add //Actions to add when the mutator is added - - // Type of the behavior datum to add - var/behavior_delegate_type = null // Specify this on subtypes - -/datum/xeno_mutator/New() - . = ..() - name = "[name]" - - -/datum/xeno_mutator/proc/apply_mutator(datum/mutator_set/MS) - if(!MS.can_purchase_mutator(name)) - return FALSE - if(MS.remaining_points < cost) - return FALSE - MS.remaining_points -= cost - MS.purchased_mutators += name - - if(istype(MS, /datum/mutator_set/individual_mutators)) - var/datum/mutator_set/individual_mutators/IS = MS - if(IS.xeno) - IS.xeno.hive.hive_ui.update_xeno_info() - - return TRUE - -// Sets up actions for when a mutator is taken -// Must be called at the end of any mutator that changes available actions -// (read: Strains) apply_mutator proc for the mutator to work correctly. -/datum/xeno_mutator/proc/mutator_update_actions(mob/living/carbon/xenomorph/X) - if(mutator_actions_to_remove) - for(var/action_path in mutator_actions_to_remove) - remove_action(X, action_path) - if(mutator_actions_to_add) - for(var/action_path in mutator_actions_to_add) - give_action(X, action_path) - -// Substitutes the existing behavior delegate for the strain-defined one. -/datum/xeno_mutator/proc/apply_behavior_holder(mob/living/carbon/xenomorph/X) - if (!istype(X)) - log_debug("Null mob handed to apply_behavior_holder. Tell the devs.") - log_admin("Null mob handed to apply_behavior_holder. Tell the devs.") - message_admins("Null mob handed to apply_behavior_holder. Tell the devs.") - - if (behavior_delegate_type) - if(X.behavior_delegate) - qdel(X.behavior_delegate) - X.behavior_delegate = new behavior_delegate_type() - X.behavior_delegate.bound_xeno = X - X.behavior_delegate.add_to_xeno() diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/behavior_delegate.dm b/code/modules/mob/living/carbon/xenomorph/strains/behavior_delegate.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/behavior_delegate.dm rename to code/modules/mob/living/carbon/xenomorph/strains/behavior_delegate.dm diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/boiler/trapper.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/strains/boiler/trapper.dm rename to code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/carrier/eggsac.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/strains/carrier/eggsac.dm rename to code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/crusher/charger.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/crusher/charger.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/strains/crusher/charger.dm rename to code/modules/mob/living/carbon/xenomorph/strains/castes/crusher/charger.dm diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/defender/steel_crest.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/strains/defender/steel_crest.dm rename to code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/drone/gardener.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/gardener.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/strains/drone/gardener.dm rename to code/modules/mob/living/carbon/xenomorph/strains/castes/drone/gardener.dm diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/drone/healer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/strains/drone/healer.dm rename to code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/hivelord/resin_whisperer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/strains/hivelord/resin_whisperer.dm rename to code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/lurker/vampire.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/strains/lurker/vampire.dm rename to code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/praetorian/dancer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/strains/praetorian/dancer.dm rename to code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/praetorian/oppressor.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/strains/praetorian/oppressor.dm rename to code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/praetorian/vanguard.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/strains/praetorian/vanguard.dm rename to code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/praetorian/warden.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/strains/praetorian/warden.dm rename to code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/ravager/berserker.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/berserker.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/strains/ravager/berserker.dm rename to code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/berserker.dm diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/ravager/hedgehog.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/strains/ravager/hedgehog.dm rename to code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/runner/acid.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm similarity index 100% rename from code/modules/mob/living/carbon/xenomorph/mutators/strains/runner/acid.dm rename to code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm diff --git a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm new file mode 100644 index 000000000000..23ec13c6b596 --- /dev/null +++ b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm @@ -0,0 +1,116 @@ +/datum/xeno_strain + /// The name of the strain. Should be short but informative. + var/name + /// Description to be displayed on purchase. + var/description + /// (OPTIONAL) Flavor text to be shown on purchase. Semi-OOC + var/flavor_description + /// (OPTIONAL) A custom icon state prefix for xenos who have taken the strain. + var/xeno_icon_state + + /// A list of action typepaths which should be removed when a xeno takes the strain. + var/list/actions_to_remove + /// A list of action typepaths which should be added when a xeno takes the strain. + var/list/actions_to_add + + /// Typepath of the [/datum/behavior_delegate] to add. + var/behavior_delegate_type + +/// TODO: documentation +/// Returns a bool indicating if the strain was successfully applied. +/datum/xeno_strain/proc/apply_strain(mob/living/carbon/xenomorph/xeno) + SHOULD_CALL_PARENT(TRUE) + + xeno.chosen_strain = src + update_actions(xeno) + register_signals(xeno) + apply_behavior_holder(xeno) + update_mob(xeno) + + xeno.hive.hive_ui.update_xeno_info() + + to_chat(xeno, SPAN_XENOANNOUNCE(description)) + if(flavor_description) + to_chat(xeno, SPAN_XENOLEADER(flavor_description)) + return TRUE + +/// Update the `xeno`'s action buttons based on [/datum/xeno_strain/var/actions_to_remove] and [/datum/xeno_strain/var/actions_to_add]. +/datum/xeno_strain/proc/update_actions(mob/living/carbon/xenomorph/xeno) + for(var/action_path in actions_to_remove) + remove_action(xeno, action_path) + for(var/action_path in actions_to_add) + give_action(xeno, action_path) + +/// TODO: documentation +/datum/xeno_strain/proc/register_signals(mob/living/carbon/xenomorph/xeno) + return + +/// TODO: documentation +/datum/xeno_strain/proc/apply_behavior_holder(mob/living/carbon/xenomorph/xeno) + if(!behavior_delegate_type) + // don't need to do anything + return + + if(xeno.behavior_delegate) + qdel(xeno.behavior_delegate) + xeno.behavior_delegate = new behavior_delegate_type() + xeno.behavior_delegate.bound_xeno = xeno + xeno.behavior_delegate.add_to_xeno() + +/// TODO: documentation +/datum/xeno_strain/proc/update_mob(mob/living/carbon/xenomorph/xeno) + xeno.xeno_jitter(1.5 SECONDS) + xeno.update_icons() + + +/mob/living/carbon/xenomorph/verb/purchase_strain() + set name = "Purchase Strain" + set desc = "Purchase a strain for yourself" + set category = "Alien" + + if(!can_take_strain()) + return + + var/strain_choice = tgui_input_list(usr, "Which strain would you like to take?", "Choose Strain", GLOB.xeno_strain_list, theme = "hive_status") + var/datum/xeno_strain/strain_path = GLOB.xeno_strain_list[strain_choice] + // Check again after the user has picked one. + if(!can_take_strain()) + return + // Show the user the strain's description, and double check that they want it. + if(alert(usr, "[initial(strain_path.description)]\n\nConfirm mutation?", "Choose Strain", "Yes", "No") != "Yes") + return + // One more time after they confirm. + if(!can_take_strain()) + return + + var/datum/xeno_strain/strain_instance = new strain_path() + // Apply the strain to the xeno. + if(strain_instance.apply_strain(src)) + // And log it if it was successful. + log_strain("[name] purchased strain '[strain_instance.type]'") + +/mob/living/carbon/xenomorph/proc/can_take_strain() + if(!length(available_strains) || !check_state(TRUE)) + return FALSE + + if(is_ventcrawling) + to_chat(src, SPAN_WARNING("This place is too constraining to take a strain.")) + return FALSE + + if(!isturf(loc)) + to_chat(src, SPAN_WARNING("We can't take a strain here.")) + return FALSE + + if(handcuffed || legcuffed) + to_chat(src, SPAN_WARNING("The restraints are too restricting to allow us to take a strain.")) + return FALSE + + if(health < maxHealth) + to_chat(src, SPAN_WARNING("We must be at full health to take a strain.")) + return FALSE + + if(agility || fortify || crest_defense || stealth) + to_chat(src, SPAN_WARNING("We cannot take a strain while in this stance.")) + return FALSE + + return TRUE diff --git a/code/modules/mob/living/carbon/xenomorph/update_icons.dm b/code/modules/mob/living/carbon/xenomorph/update_icons.dm index 55995ec0b264..722b5f7a48bb 100644 --- a/code/modules/mob/living/carbon/xenomorph/update_icons.dm +++ b/code/modules/mob/living/carbon/xenomorph/update_icons.dm @@ -41,7 +41,7 @@ Q.queen_standing_icon = icon_xeno Q.queen_ovipositor_icon = 'icons/mob/xenos/ovipositor.dmi' - var/mutation_caste_state = "[mutation_type] [caste.caste_type]" + var/mutation_caste_state = "[chosen_strain?.xeno_icon_state] [caste.caste_type]" if(!walking_state_cache[mutation_caste_state]) var/cache_walking_state = FALSE for(var/state in icon_states(icon)) @@ -64,7 +64,7 @@ if(behavior_delegate?.on_update_icons()) return - var/mutation_caste_state = "[mutation_icon_state || mutation_type] [caste.caste_type]" + var/mutation_caste_state = "[chosen_strain?.xeno_icon_state] [caste.caste_type]" if(stat == DEAD) icon_state = "[mutation_caste_state] Dead" if(!(icon_state in icon_states(icon_xeno))) diff --git a/colonialmarines.dme b/colonialmarines.dme index 0ad186e331cc..adffc94774b2 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -1961,7 +1961,6 @@ #include "code\modules\mob\living\carbon\xenomorph\xeno_verbs.dm" #include "code\modules\mob\living\carbon\xenomorph\XenoAttacks.dm" #include "code\modules\mob\living\carbon\xenomorph\Xenomorph.dm" -#include "code\modules\mob\living\carbon\xenomorph\XenoMutatorSets.dm" #include "code\modules\mob\living\carbon\xenomorph\XenoOverwatch.dm" #include "code\modules\mob\living\carbon\xenomorph\XenoProcs.dm" #include "code\modules\mob\living\carbon\xenomorph\XenoUpgrade.dm" @@ -2041,23 +2040,23 @@ #include "code\modules\mob\living\carbon\xenomorph\castes\Spitter.dm" #include "code\modules\mob\living\carbon\xenomorph\castes\Warrior.dm" #include "code\modules\mob\living\carbon\xenomorph\items\iff_tag.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\behavior_delegate.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\mutator.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\strains\boiler\trapper.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\strains\carrier\eggsac.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\strains\crusher\charger.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\strains\defender\steel_crest.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\strains\drone\gardener.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\strains\drone\healer.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\strains\hivelord\resin_whisperer.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\strains\lurker\vampire.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\strains\praetorian\dancer.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\strains\praetorian\oppressor.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\strains\praetorian\vanguard.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\strains\praetorian\warden.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\strains\ravager\berserker.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\strains\ravager\hedgehog.dm" -#include "code\modules\mob\living\carbon\xenomorph\mutators\strains\runner\acid.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\behavior_delegate.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\xeno_strain.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\boiler\trapper.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\carrier\eggsac.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\crusher\charger.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\defender\steel_crest.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\drone\gardener.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\drone\healer.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\hivelord\resin_whisperer.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\lurker\vampire.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\praetorian\dancer.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\praetorian\oppressor.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\praetorian\vanguard.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\praetorian\warden.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\ravager\berserker.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\ravager\hedgehog.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\runner\acid.dm" #include "code\modules\mob\living\silicon\death.dm" #include "code\modules\mob\living\silicon\login.dm" #include "code\modules\mob\living\silicon\say.dm" From 64eec09920f6f0c45bfad81469658a39983420bf Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Mon, 22 Jan 2024 15:51:17 +0000 Subject: [PATCH 02/17] Stuff I removed the `tacklestrength_*` part since it wasn't being used at all --- .../mob/living/carbon/xenomorph/Xenomorph.dm | 26 +++++-------------- .../living/carbon/xenomorph/castes/Carrier.dm | 6 ++++- .../living/carbon/xenomorph/castes/Runner.dm | 7 ++++- .../living/carbon/xenomorph/hive_status.dm | 16 +++--------- .../carbon/xenomorph/strains/xeno_strain.dm | 2 +- .../living/carbon/xenomorph/update_icons.dm | 4 +-- .../living/carbon/xenomorph/xeno_helpers.dm | 11 +++++++- tgui/packages/tgui/interfaces/HiveStatus.jsx | 2 +- 8 files changed, 35 insertions(+), 39 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index 6aedbb24d0a2..5245230c20e7 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -134,7 +134,7 @@ /// A list of strain typepaths that the xeno is able to choose. var/list/available_strains = list() /// The xeno's strain, if they've taken one. - var/datum/xeno_strain/chosen_strain = null + var/datum/xeno_strain/strain = null // Hive-related vars var/datum/hive_status/hive @@ -660,8 +660,8 @@ . += "It appears to belong to [hive?.name ? "the [hive.name]" : "a different hive"]." if(isxeno(user) || isobserver(user)) - if(chosen_strain) - . += "It has specialized into a [chosen_strain.name]." + if(strain) + . += "It has specialized into a [strain.name]." if(iff_tag) . += SPAN_NOTICE("It has an IFF tag sticking out of its carapace.") @@ -692,7 +692,7 @@ selected_ability = null queued_action = null - QDEL_NULL(chosen_strain) + QDEL_NULL(strain) QDEL_NULL(behavior_delegate) built_structures = null @@ -842,8 +842,6 @@ tackle_min = caste.tackle_min tackle_max = caste.tackle_max tackle_chance = caste.tackle_chance + tackle_chance_modifier - tacklestrength_min = caste.tacklestrength_min + mutators.tackle_strength_bonus + hive.mutators.tackle_strength_bonus - tacklestrength_max = caste.tacklestrength_max + mutators.tackle_strength_bonus + hive.mutators.tackle_strength_bonus /mob/living/carbon/xenomorph/proc/recalculate_health() var/new_max_health = nocrit ? health_modifier + maxHealth : health_modifier + caste.max_health @@ -899,18 +897,8 @@ /mob/living/carbon/xenomorph/proc/recalculate_actions() recalculate_acid() recalculate_weeds() - pull_multiplier = mutators.pull_multiplier - if(isrunner(src)) - //Xeno runners need a small nerf to dragging speed mutator - pull_multiplier = 1 - (1 - mutators.pull_multiplier) * 0.85 - if(is_zoomed) - zoom_out() - if(iscarrier(src)) - var/mob/living/carbon/xenomorph/carrier/carrier = src - carrier.huggers_max = caste.huggers_max - carrier.eggs_max = caste.eggs_max - need_weeds = mutators.need_weeds - + // Modified on subtypes + pull_multiplier = initial(pull_multiplier) /mob/living/carbon/xenomorph/proc/recalculate_acid() if(caste) @@ -1035,7 +1023,7 @@ handle_ghost_message() /mob/living/carbon/xenomorph/proc/handle_ghost_message() - var/strain_name = chosen_strain ? chosen_strain.name : "Normal" + var/strain_name = strain ? strain.name : "Normal" notify_ghosts("[src] ([strain_name] [caste_type]) has ghosted and their body is up for grabs!", source = src) /mob/living/carbon/xenomorph/larva/handle_ghost_message() diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm index 2e106743514a..131548bcb740 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm @@ -75,7 +75,6 @@ /mob/living/carbon/xenomorph/proc/rename_tunnel, /mob/living/carbon/xenomorph/proc/set_hugger_reserve_for_morpher, ) - mutation_type = CARRIER_NORMAL icon_xenonid = 'icons/mob/xenonids/carrier.dmi' @@ -207,6 +206,11 @@ if(eggs_dropped) //Checks whether or not to announce egg drop. xeno_message(SPAN_XENOANNOUNCE("[src] has dropped some precious eggs!"), 2, hive.hivenumber) +/mob/living/carbon/xenomorph/carrier/recalculate_actions() + . = ..() + huggers_max = caste.huggers_max + eggs_max = caste.eggs_max + /mob/living/carbon/xenomorph/carrier/get_status_tab_items() . = ..() if(huggers_max > 0) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm b/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm index 3a23afc145d1..b55eb5b004b8 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm @@ -62,7 +62,6 @@ inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, ) - mutation_type = RUNNER_NORMAL icon_xeno = 'icons/mob/xenos/runner.dmi' icon_xenonid = 'icons/mob/xenonids/runner.dmi' @@ -77,6 +76,12 @@ if (pass_flags_container) pass_flags_container.flags_pass |= PASS_FLAGS_CRAWLER +/mob/living/carbon/xenomorph/runner/recalculate_actions() + . = ..() + pull_multiplier *= 0.85 + if(is_zoomed) + zoom_out() + /datum/behavior_delegate/runner_base name = "Base Runner Behavior Delegate" diff --git a/code/modules/mob/living/carbon/xenomorph/hive_status.dm b/code/modules/mob/living/carbon/xenomorph/hive_status.dm index bb67eaa055a8..c6d0b158c8b3 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_status.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_status.dm @@ -46,7 +46,6 @@ var/allowed_nest_distance = 15 //How far away do we allow nests from an ovied Queen. Default 15 tiles. var/obj/effect/alien/resin/special/pylon/core/hive_location = null //Set to ref every time a core is built, for defining the hive location - var/datum/mutator_set/hive_mutators/mutators = new var/tier_slot_multiplier = 1 var/larva_gestation_multiplier = 1 var/bonus_larva_spawn_chance = 1 @@ -143,7 +142,6 @@ var/static/list/evolution_menu_images /datum/hive_status/New() - mutators.hive = src hive_ui = new(src) mark_ui = new(src) faction_ui = new(src) @@ -279,7 +277,6 @@ /datum/hive_status/proc/set_living_xeno_queen(mob/living/carbon/xenomorph/queen/queen) if(!queen) - mutators.reset_mutators() SStracking.delete_leader("hive_[hivenumber]") SStracking.stop_tracking("hive_[hivenumber]", living_xeno_queen) SShive_status.wait = 10 SECONDS @@ -293,10 +290,8 @@ recalculate_hive() /datum/hive_status/proc/recalculate_hive() - if (!living_xeno_queen) - queen_leader_limit = 0 //No leaders for a Hive without a Queen! - else - queen_leader_limit = 4 + mutators.leader_count_boost + //No leaders for a Hive without a Queen! + queen_leader_limit = living_xeno_queen ? 4 : 0 if (xeno_leader_list.len > queen_leader_limit) var/diff = 0 @@ -310,11 +305,6 @@ open_xeno_leader_positions += i xeno_leader_list.len++ - - tier_slot_multiplier = mutators.tier_slot_multiplier - larva_gestation_multiplier = mutators.larva_gestation_multiplier - bonus_larva_spawn_chance = mutators.bonus_larva_spawn_chance - hive_ui.update_all_data() /datum/hive_status/proc/add_hive_leader(mob/living/carbon/xenomorph/xeno) @@ -524,7 +514,7 @@ xeno_name = "Larva ([X.nicknumber])" xenos["[X.nicknumber]"] = list( "name" = xeno_name, - "strain" = X.mutation_type, + "strain" = X.strain, "ref" = "\ref[X]" ) diff --git a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm index 23ec13c6b596..fd43b23de993 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm @@ -21,7 +21,7 @@ /datum/xeno_strain/proc/apply_strain(mob/living/carbon/xenomorph/xeno) SHOULD_CALL_PARENT(TRUE) - xeno.chosen_strain = src + xeno.strain = src update_actions(xeno) register_signals(xeno) apply_behavior_holder(xeno) diff --git a/code/modules/mob/living/carbon/xenomorph/update_icons.dm b/code/modules/mob/living/carbon/xenomorph/update_icons.dm index 722b5f7a48bb..ebf7566c0131 100644 --- a/code/modules/mob/living/carbon/xenomorph/update_icons.dm +++ b/code/modules/mob/living/carbon/xenomorph/update_icons.dm @@ -41,7 +41,7 @@ Q.queen_standing_icon = icon_xeno Q.queen_ovipositor_icon = 'icons/mob/xenos/ovipositor.dmi' - var/mutation_caste_state = "[chosen_strain?.xeno_icon_state] [caste.caste_type]" + var/mutation_caste_state = "[strain?.xeno_icon_state] [caste.caste_type]" if(!walking_state_cache[mutation_caste_state]) var/cache_walking_state = FALSE for(var/state in icon_states(icon)) @@ -64,7 +64,7 @@ if(behavior_delegate?.on_update_icons()) return - var/mutation_caste_state = "[chosen_strain?.xeno_icon_state] [caste.caste_type]" + var/mutation_caste_state = "[strain?.xeno_icon_state] [caste.caste_type]" if(stat == DEAD) icon_state = "[mutation_caste_state] Dead" if(!(icon_state in icon_states(icon_xeno))) diff --git a/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm b/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm index 7324a3af6892..4048af28bc81 100644 --- a/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm +++ b/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm @@ -34,6 +34,15 @@ return 100 return round(armor_integrity * 100 / armor_integrity_max) +/** + * Returns the custom icon state from the xeno's strain, if it has one. + * + * If that isn't available, returns "Normal" + */ +/mob/living/carbon/xenomorph/proc/get_strain_sprite() + return strain?.xeno_icon_state || "Normal" + // TODO: Go through xeno/xenoid sprites and remove "Normal", so that this isn't needed. + //These don't do much currently. Or anything? Only around for legacy code. /mob/living/carbon/xenomorph/is_mob_restrained() return 0 @@ -58,4 +67,4 @@ return caste.fire_intensity_resistance /mob/living/carbon/xenomorph/alter_ghost(mob/dead/observer/ghost) - ghost.icon_state = "[mutation_type] [caste.caste_type] Running" + ghost.icon_state = "[get_strain_sprite()] [caste.caste_type] Running" diff --git a/tgui/packages/tgui/interfaces/HiveStatus.jsx b/tgui/packages/tgui/interfaces/HiveStatus.jsx index ea23b73aca55..72d9476f96dd 100644 --- a/tgui/packages/tgui/interfaces/HiveStatus.jsx +++ b/tgui/packages/tgui/interfaces/HiveStatus.jsx @@ -359,7 +359,7 @@ const XenoList = (props) => { {entry.name} - {entry.strain} + {entry.strain} // TODO make sure this still works {entry.location} {entry.health < 30 ? ( From a3e9423aec6571fe75aecc771593c69451a789b7 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Mon, 22 Jan 2024 16:04:51 +0000 Subject: [PATCH 03/17] Strains first pass (squashed commits) Trapper first pass Eggsac first pass Charger first pass Steel Crest first pass Drone strains first pass Resin Whisperer first pass Vampire first pass Praetorian strains first pass Ravager strains first pass Acider first pass Watcher strain (almost forgot this existed lol) --- code/__DEFINES/mobs.dm | 42 +++--------------- .../living/carbon/xenomorph/castes/Boiler.dm | 3 +- .../living/carbon/xenomorph/castes/Carrier.dm | 1 + .../living/carbon/xenomorph/castes/Crusher.dm | 3 +- .../carbon/xenomorph/castes/Defender.dm | 3 +- .../living/carbon/xenomorph/castes/Drone.dm | 5 ++- .../carbon/xenomorph/castes/Facehugger.dm | 34 +------------- .../carbon/xenomorph/castes/Hivelord.dm | 2 +- .../living/carbon/xenomorph/castes/Lurker.dm | 2 +- .../carbon/xenomorph/castes/Praetorian.dm | 7 ++- .../living/carbon/xenomorph/castes/Ravager.dm | 5 ++- .../living/carbon/xenomorph/castes/Runner.dm | 1 + .../strains/castes/boiler/trapper.dm | 29 ++++-------- .../strains/castes/carrier/eggsac.dm | 36 ++++++--------- .../strains/castes/crusher/charger.dm | 38 ++++++++-------- .../strains/castes/defender/steel_crest.dm | 28 +++++------- .../strains/castes/drone/gardener.dm | 32 +++++++------- .../xenomorph/strains/castes/drone/healer.dm | 33 +++++--------- .../strains/castes/facehugger/watcher.dm | 18 ++++++++ .../castes/hivelord/resin_whisperer.dm | 24 +++------- .../strains/castes/lurker/vampire.dm | 23 +++------- .../strains/castes/praetorian/dancer.dm | 37 ++++++---------- .../strains/castes/praetorian/oppressor.dm | 44 +++++++------------ .../strains/castes/praetorian/vanguard.dm | 39 +++++----------- .../strains/castes/praetorian/warden.dm | 34 +++++--------- .../strains/castes/ravager/berserker.dm | 24 +++------- .../strains/castes/ravager/hedgehog.dm | 26 +++-------- .../xenomorph/strains/castes/runner/acid.dm | 29 +++++------- .../living/carbon/xenomorph/xeno_helpers.dm | 4 +- colonialmarines.dme | 1 + 30 files changed, 213 insertions(+), 394 deletions(-) create mode 100644 code/modules/mob/living/carbon/xenomorph/strains/castes/facehugger/watcher.dm diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 31914815ae93..e67fa1b21845 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -310,72 +310,43 @@ // STRAIN FLAGS // // ------------ // -// Queen strain flags -#define QUEEN_NORMAL "Normal" - // Facehugger strain flags -#define FACEHUGGER_NORMAL "Normal" #define FACEHUGGER_WATCHER "Watcher" // Drone strain flags -#define DRONE_NORMAL "Normal" #define DRONE_HEALER "Healer" #define DRONE_GARDENER "Gardener" // Hivelord strain flags -#define HIVELORD_NORMAL "Normal" #define HIVELORD_RESIN_WHISPERER "Resin Whisperer" // Carrier strain flags -#define CARRIER_NORMAL "Normal" #define CARRIER_EGGSAC "Eggsac" -// Burrower strain flags -#define BURROWER_NORMAL "Normal" -#define BURROWER_TREMOR "Tremor" - -// Sentinel strain flags -#define SENTINEL_NORMAL "Normal" - -// Spitter strain flags -#define SPITTER_NORMAL "Normal" - // Boiler strain flags -#define BOILER_NORMAL "Normal" #define BOILER_TRAPPER "Trapper" // Runner strain flags -#define RUNNER_NORMAL "Normal" #define RUNNER_ACIDER "Acider" // Lurker strain flags -#define LURKER_NORMAL "Normal" -#define LURKER_VAMPIRE "Vampire" +#define LURKER_VAMPIRE "Vampire" + // Ravager strain flags -#define RAVAGER_NORMAL "Normal" #define RAVAGER_HEDGEHOG "Hedgehog" -#define RAVAGER_BERSERKER "Berserker" +#define RAVAGER_BERSERKER "Berserker" // Defender strain flags -#define DEFENDER_NORMAL "Normal" #define DEFENDER_STEELCREST "Steelcrest" -// Warrior strain flags -#define WARRIOR_NORMAL "Normal" - // Crusher strain flags -#define CRUSHER_NORMAL "Normal" #define CRUSHER_CHARGER "Charger" // Praetorian strain flags -#define PRAETORIAN_NORMAL "Normal" #define PRAETORIAN_VANGUARD "Vanguard" -#define PRAETORIAN_DANCER "Dancer" -#define PRAETORIAN_WARDEN "Warden" -#define PRAETORIAN_OPPRESSOR "Oppressor" - -// Hellhound strain flags -#define HELLHOUND_NORMAL "Normal" +#define PRAETORIAN_DANCER "Dancer" +#define PRAETORIAN_WARDEN "Warden" +#define PRAETORIAN_OPPRESSOR"Oppressor" GLOBAL_LIST_INIT(default_onmob_icons, list( WEAR_L_HAND = 'icons/mob/humans/onmob/items_lefthand_0.dmi', @@ -449,4 +420,3 @@ GLOBAL_LIST_INIT(default_xeno_onmob_icons, list( #define MOBILITY_FLAGS_DEFAULT (MOBILITY_MOVE | MOBILITY_STAND) #define MOBILITY_FLAGS_CARBON_DEFAULT (MOBILITY_MOVE | MOBILITY_STAND | MOBILITY_REST | MOBILITY_LIEDOWN) #define MOBILITY_FLAGS_REST_CAPABLE_DEFAULT (MOBILITY_MOVE | MOBILITY_STAND | MOBILITY_REST | MOBILITY_LIEDOWN) - diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm b/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm index 074af92d69fa..02c48ae3d6dd 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm @@ -50,10 +50,10 @@ tier = 3 gib_chance = 100 drag_delay = 6 //pulling a big dead xeno is hard - mutation_type = BOILER_NORMAL spit_delay = 30 SECONDS tileoffset = 3 viewsize = 7 + available_strains = list(/datum/xeno_strain/trapper) icon_xeno = 'icons/mob/xenos/boiler.dmi' icon_xenonid = 'icons/mob/xenonids/boiler.dmi' @@ -98,4 +98,3 @@ // No special behavior for boilers /datum/behavior_delegate/boiler_base name = "Base Boiler Behavior Delegate" - diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm index 131548bcb740..713b66bfa5c1 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm @@ -75,6 +75,7 @@ /mob/living/carbon/xenomorph/proc/rename_tunnel, /mob/living/carbon/xenomorph/proc/set_hugger_reserve_for_morpher, ) + available_strains = list(/datum/xeno_strain/eggsac) icon_xenonid = 'icons/mob/xenonids/carrier.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm index d2c0b0e40e59..b48de1b34d54 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm @@ -63,8 +63,7 @@ ) claw_type = CLAW_TYPE_VERY_SHARP - mutation_icon_state = CRUSHER_NORMAL - mutation_type = CRUSHER_NORMAL + available_strains = list(/datum/xeno_strain/charger) icon_xeno = 'icons/mob/xenos/crusher.dmi' icon_xenonid = 'icons/mob/xenonids/crusher.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm b/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm index 8ec53d51046e..18a7f2aeab65 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm @@ -51,8 +51,7 @@ /datum/action/xeno_action/onclick/tacmap, ) - mutation_icon_state = DEFENDER_NORMAL - mutation_type = DEFENDER_NORMAL + available_strains = list(/datum/xeno_strain/steel_crest) icon_xeno = 'icons/mob/xenos/defender.dmi' icon_xenonid = 'icons/mob/xenonids/defender.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm b/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm index c4c9b11b37e4..5c476e4a4067 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm @@ -69,7 +69,10 @@ /mob/living/carbon/xenomorph/proc/rename_tunnel, /mob/living/carbon/xenomorph/proc/set_hugger_reserve_for_morpher, ) - mutation_type = DRONE_NORMAL + available_strains = list( + /datum/xeno_strain/gardener, + /datum/xeno_strain/healer, + ) icon_xeno = 'icons/mob/xenos/drone.dmi' icon_xenonid = 'icons/mob/xenonids/drone.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm b/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm index 7ce3a8750568..75de76737255 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm @@ -55,7 +55,7 @@ inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, ) - mutation_type = "Normal" + available_strains = list(/datum/xeno_strain/watcher) icon_xeno = 'icons/mob/xenos/facehugger.dmi' icon_xenonid = 'icons/mob/xenonids/facehugger.dmi' @@ -234,35 +234,3 @@ . += "Lifetime Hugs: [total_facehugs] / [next_facehug_goal]" else . += "Lifetime Hugs: [total_facehugs]" - - -/datum/xeno_mutator/watcher - name = "STRAIN: Facehugger - Watcher" - description = "You lose your ability to hide in exchange to see further and the ability to no longer take damage outside of weeds. This enables you to stalk your host from a distance and wait for the perfect oppertunity to strike." - flavor_description = "No need to hide when you can see the danger." - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_FACEHUGGER) - mutator_actions_to_remove = list( - /datum/action/xeno_action/onclick/xenohide, - ) - mutator_actions_to_add = list( - /datum/action/xeno_action/onclick/toggle_long_range/runner, - ) - - cost = 1 - - keystone = TRUE - -/datum/xeno_mutator/watcher/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) - . = ..() - if(!.) - return - - var/mob/living/carbon/xenomorph/facehugger/facehugger = mutator_set.xeno - - facehugger.viewsize = 10 - facehugger.layer = MOB_LAYER - - facehugger.mutation_type = FACEHUGGER_WATCHER - mutator_update_actions(facehugger) - mutator_set.recalculate_actions(description, flavor_description) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm b/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm index b00ec2a9c1eb..766a3e571f8c 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm @@ -76,7 +76,7 @@ /mob/living/carbon/xenomorph/proc/set_hugger_reserve_for_morpher, ) - mutation_type = HIVELORD_NORMAL + available_strains = list(/datum/xeno_strain/resin_whisperer) icon_xeno = 'icons/mob/xenos/hivelord.dmi' icon_xenonid = 'icons/mob/xenonids/hivelord.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm index 469b9a78d063..df2589073f9c 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm @@ -50,7 +50,7 @@ inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, ) - mutation_type = LURKER_NORMAL + available_strains = list(/datum/xeno_strain/vampire) claw_type = CLAW_TYPE_SHARP tackle_min = 2 diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm b/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm index 9536ef1553e9..a4c105de1dd6 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm @@ -46,7 +46,12 @@ mob_size = MOB_SIZE_BIG drag_delay = 6 //pulling a big dead xeno is hard tier = 3 - mutation_type = PRAETORIAN_NORMAL + available_strains = list( + /datum/xeno_strain/dancer, + /datum/xeno_strain/oppressor, + /datum/xeno_strain/vanguard, + /datum/xeno_strain/warden, + ) base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm b/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm index 6d19a1b8feec..d05f2e22f4f7 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm @@ -45,7 +45,10 @@ tier = 3 pixel_x = -16 old_x = -16 - mutation_type = RAVAGER_NORMAL + available_strains = list( + /datum/xeno_strain/berserker, + /datum/xeno_strain/hedgehog, + ) claw_type = CLAW_TYPE_VERY_SHARP base_actions = list( diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm b/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm index b55eb5b004b8..3026ee2ee9da 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm @@ -62,6 +62,7 @@ inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, ) + available_strains = list(/datum/xeno_strain/acider) icon_xeno = 'icons/mob/xenos/runner.dmi' icon_xenonid = 'icons/mob/xenonids/runner.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm index c14d2c6773cf..c18973209220 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm @@ -1,52 +1,41 @@ - -/datum/xeno_mutator/trapper - name = "STRAIN: Boiler - Trapper" +/datum/xeno_strain/trapper + name = BOILER_TRAPPER description = "You trade your ability to bombard, lance, and dump your acid in order to gain some speed and the ability to create acid explosions and restrain talls within them. With your longer-range vision, set up traps that immobilize your opponents and place acid mines which deal damage to talls and barricades and reduce the cooldown of your trap deployment for every tall hit. Finally, hit talls with your Acid Shotgun ability which adds a stack of insight to empower the next trap you place once you reach a maximum of ten insight. A point-blank shot or a shot on a stunned target will instantly apply ten stacks." flavor_description = "Hsss, I love the smell of burnin' tallhost flesh in the mornin'." - cost = MUTATOR_COST_EXPENSIVE - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_BOILER) //Only boiler. - mutator_actions_to_remove = list( + + actions_to_remove = list( /datum/action/xeno_action/activable/xeno_spit/bombard, /datum/action/xeno_action/onclick/shift_spits/boiler, /datum/action/xeno_action/activable/spray_acid/boiler, /datum/action/xeno_action/onclick/toggle_long_range/boiler, /datum/action/xeno_action/onclick/acid_shroud, ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/activable/boiler_trap, /datum/action/xeno_action/activable/acid_mine, /datum/action/xeno_action/activable/acid_shotgun, /datum/action/xeno_action/onclick/toggle_long_range/trapper, ) - keystone = TRUE behavior_delegate_type = /datum/behavior_delegate/boiler_trapper -/datum/xeno_mutator/trapper/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) +/datum/xeno_strain/trapper/apply_strain(mob/living/carbon/xenomorph/boiler/boiler) . = ..() - if(. == 0) - return + if(!istype(boiler)) + return FALSE - var/mob/living/carbon/xenomorph/boiler/boiler = mutator_set.xeno if(boiler.is_zoomed) boiler.zoom_out() boiler.tileoffset = 0 boiler.viewsize = TRAPPER_VIEWRANGE - boiler.mutation_type = BOILER_TRAPPER boiler.plasma_types -= PLASMA_NEUROTOXIN boiler.armor_modifier -= XENO_ARMOR_MOD_LARGE // no armor boiler.health_modifier -= XENO_HEALTH_MOD_MED boiler.speed_modifier += XENO_SPEED_SLOWMOD_TIER_5 // compensating for base buffs boiler.recalculate_everything() - - apply_behavior_holder(boiler) - - mutator_update_actions(boiler) - mutator_set.recalculate_actions(description, flavor_description) - + return TRUE /datum/behavior_delegate/boiler_trapper name = "Boiler Trapper Behavior Delegate" diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm index 10cbc29f51b0..c2229122a99a 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm @@ -1,47 +1,37 @@ -/datum/xeno_mutator/eggsac - name = "STRAIN: Carrier - Eggsac" +/datum/xeno_strain/eggsac + name = CARRIER_EGGSAC description = "In exchange for your ability to store huggers and place traps, you gain larger plasma stores, strong pheromones, and the ability to lay eggs by using your plasma stores. In addition, you can now carry twelve eggs at once and can place eggs one pace further than normal. \n\nYou can also place a small number of fragile eggs on normal weeds. These eggs have a lifetime of five minutes while you remain within 14 tiles. Or one minute if you leave this range." flavor_description = "An egg is always an adventure; the next one may be different." - cost = MUTATOR_COST_EXPENSIVE - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_CARRIER) - mutator_actions_to_remove = list( + + actions_to_remove = list( /datum/action/xeno_action/activable/throw_hugger, /datum/action/xeno_action/onclick/place_trap, /datum/action/xeno_action/activable/retrieve_egg, // readding it so it gets at the end of the ability list /datum/action/xeno_action/onclick/set_hugger_reserve, ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/active_toggle/generate_egg, /datum/action/xeno_action/activable/retrieve_egg, // readding it so it gets at the end of the ability list ) + behavior_delegate_type = /datum/behavior_delegate/carrier_eggsac - keystone = TRUE -/datum/xeno_mutator/eggsac/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) +/datum/xeno_strain/eggsac/apply_strain(mob/living/carbon/xenomorph/carrier/carrier) . = ..() - if (!.) - return - var/mob/living/carbon/xenomorph/carrier/carrier = mutator_set.xeno - if(!istype(carrier)) - return FALSE + carrier.plasma_types = list(PLASMA_EGG) carrier.phero_modifier += XENO_PHERO_MOD_LARGE // praetorian level pheremones - carrier.plasmapool_modifier = 1.2 - mutator_update_actions(carrier) - mutator_set.recalculate_actions(description, flavor_description) - carrier.recalculate_pheromones() carrier.recalculate_plasma() - if(carrier.huggers_cur > 0) - playsound(carrier.loc, 'sound/voice/alien_facehugger_dies.ogg', 25, 1) + carrier.recalculate_pheromones() + + if(carrier.huggers_cur) + playsound(carrier.loc, 'sound/voice/alien_facehugger_dies.ogg', 25, TRUE) carrier.huggers_cur = 0 carrier.huggers_max = 0 carrier.update_hugger_overlays() - carrier.mutation_type = CARRIER_EGGSAC - carrier.update_eggsac_overlays() carrier.eggs_max = 12 carrier.egg_planting_range = 2 - apply_behavior_holder(carrier) + carrier.update_eggsac_overlays() return TRUE #define EGGSAC_OFF_WEED_EGGCAP 4 diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/crusher/charger.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/crusher/charger.dm index 17b5cf62052c..f2dd564cb2ee 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/crusher/charger.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/crusher/charger.dm @@ -1,10 +1,8 @@ -// // Specific momentum based damage defines #define CHARGER_DESTROY charger_ability.momentum * 40 #define CHARGER_DAMAGE_CADE charger_ability.momentum * 22 #define CHARGER_DAMAGE_SENTRY charger_ability.momentum * 9 -#define CHARGER_DAMAGE_MG charger_ability.momentum * 15 // Momentum loss defines. 8 is maximum momentum @@ -14,34 +12,28 @@ #define CCA_MOMENTUM_LOSS_MIN 1 -/datum/xeno_mutator/charger - name = "STRAIN: Crusher - Charger" +/datum/xeno_strain/charger + name = CRUSHER_CHARGER description = "In exchange for your shield, a little bit of your armor and damage, your slowdown resist from autospitters, your influence under frenzy pheromones, your stomp no longer knocking down talls, and your ability to lock your direction, you gain a considerable amount of health, some speed, your stomp does extra damage when stomping over a grounded tall, and your charge is now manually-controlled and momentum-based; the further you go, the more damage and speed you will gain until you achieve maximum momentum, indicated by your roar. In addition, your armor is now directional, being the toughest on the front, weaker on the sides, and weakest from the back. In return, you gain an ability to tumble to pass through talls and avoid enemy fire, and an ability to forcefully move enemies via ramming into them." flavor_description = "We're just getting started. Nothing stops this train. Nothing." - cost = MUTATOR_COST_EXPENSIVE - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_CRUSHER) - mutator_actions_to_remove = list ( + + actions_to_remove = list( /datum/action/xeno_action/activable/pounce/crusher_charge, /datum/action/xeno_action/onclick/crusher_stomp, /datum/action/xeno_action/onclick/crusher_shield, ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/onclick/charger_charge, /datum/action/xeno_action/activable/tumble, /datum/action/xeno_action/onclick/crusher_stomp/charger, /datum/action/xeno_action/activable/fling/charger, ) - keystone = TRUE + behavior_delegate_type = /datum/behavior_delegate/crusher_charger -/datum/xeno_mutator/charger/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) +/datum/xeno_strain/charger/apply_strain(mob/living/carbon/xenomorph/crusher/crusher) . = ..() - if (. == 0) - return - var/mob/living/carbon/xenomorph/crusher/crusher = mutator_set.xeno - crusher.mutation_type = CRUSHER_CHARGER crusher.small_explosives_stun = FALSE crusher.health_modifier += XENO_HEALTH_MOD_LARGE crusher.speed_modifier += XENO_SPEED_FASTMOD_TIER_3 @@ -49,11 +41,8 @@ crusher.damage_modifier -= XENO_DAMAGE_MOD_SMALL crusher.ignore_aura = "frenzy" // no funny crushers going 7 morbillion kilometers per second crusher.phero_modifier = -crusher.caste.aura_strength - crusher.recalculate_pheromones() - mutator_update_actions(crusher) - mutator_set.recalculate_actions(description, flavor_description) - apply_behavior_holder(crusher) crusher.recalculate_everything() + return TRUE /datum/behavior_delegate/crusher_charger name = "Charger Crusher Behavior Delegate" @@ -83,7 +72,7 @@ /datum/behavior_delegate/crusher_charger/on_update_icons() if(HAS_TRAIT(bound_xeno, TRAIT_CHARGING) && bound_xeno.body_position == STANDING_UP) - bound_xeno.icon_state = "[bound_xeno.mutation_icon_state || bound_xeno.mutation_type] Crusher Charging" + bound_xeno.icon_state = "[bound_xeno.get_strain_icon()] Crusher Charging" return TRUE // Fallback proc for shit that doesn't have a collision def @@ -643,3 +632,12 @@ return XENO_CHARGE_TRY_MOVE charger_ability.stop_momentum() + + +#undef CHARGER_DESTROY +#undef CHARGER_DAMAGE_CADE +#undef CHARGER_DAMAGE_SENTRY +#undef CCA_MOMENTUM_LOSS_HALF +#undef CCA_MOMENTUM_LOSS_THIRD +#undef CCA_MOMENTUM_LOSS_QUARTER +#undef CCA_MOMENTUM_LOSS_MIN diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm index 957e7f1b8926..5f1f85b5b1bd 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm @@ -1,32 +1,24 @@ -/datum/xeno_mutator/steel_crest - name = "STRAIN: Defender - Steel Crest" +/datum/xeno_strain/steel_crest + name = DEFENDER_STEELCREST description = "You trade your tail sweep and a small amount of your slash damage for slightly increased headbutt knockback and damage and the ability to slowly move and headbutt while fortified. Along with this, you gain a unique ability to accumulate damage, and use it to recover a slight amount of health and refresh your tail slam." flavor_description = "To handle yourself, use your head. To handle others, use your head." - cost = MUTATOR_COST_EXPENSIVE - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_DEFENDER) - mutator_actions_to_remove = list( + xeno_icon_state = DEFENDER_STEELCREST + + actions_to_remove = list( /datum/action/xeno_action/onclick/tail_sweep, ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/onclick/soak, ) + behavior_delegate_type = /datum/behavior_delegate/defender_steel_crest - keystone = TRUE -/datum/xeno_mutator/steel_crest/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) +/datum/xeno_strain/steel_crest/apply_strain(mob/living/carbon/xenomorph/defender/defender) . = ..() - if (. == 0) - return - var/mob/living/carbon/xenomorph/defender/defender = mutator_set.xeno - defender.mutation_type = DEFENDER_STEELCREST - defender.mutation_icon_state = DEFENDER_STEELCREST defender.damage_modifier -= XENO_DAMAGE_MOD_VERY_SMALL if(defender.fortify) defender.ability_speed_modifier += 2.5 - mutator_update_actions(defender) - mutator_set.recalculate_actions(description, flavor_description) defender.recalculate_stats() /datum/behavior_delegate/defender_steel_crest @@ -37,8 +29,8 @@ return if(bound_xeno.fortify) - bound_xeno.icon_state = "[bound_xeno.mutation_icon_state || bound_xeno.mutation_type] Steelcrest Defender Fortify" + bound_xeno.icon_state = "[bound_xeno.get_strain_icon()] Steelcrest Defender Fortify" return TRUE if(bound_xeno.crest_defense) - bound_xeno.icon_state = "[bound_xeno.mutation_icon_state || bound_xeno.mutation_type] Steelcrest Defender Crest" + bound_xeno.icon_state = "[bound_xeno.get_strain_icon()] Steelcrest Defender Crest" return TRUE diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/gardener.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/gardener.dm index 4d47ac333a23..456768cdd25a 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/gardener.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/gardener.dm @@ -1,44 +1,42 @@ -/datum/xeno_mutator/gardener - name = "STRAIN: Drone - Gardener" +/datum/xeno_strain/gardener + name = DRONE_GARDENER description = "You trade your choice of resin secretions, your corrosive acid, and your ability to transfer plasma for a tiny bit of extra health regeneration on weeds and several new abilities, including the ability to plant hardier weeds, temporarily reinforce structures with your plasma, and to plant up to six potent resin fruits for your sisters by secreting your vital fluids at the cost of a bit of your health for each fruit you shape." flavor_description = "The glory of gardening: hands in the weeds, head in the dark, heart with resin." - cost = MUTATOR_COST_EXPENSIVE - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_DRONE) //Only drone. - mutator_actions_to_remove = list( + + actions_to_remove = list( /datum/action/xeno_action/activable/secrete_resin, /datum/action/xeno_action/onclick/choose_resin, /datum/action/xeno_action/activable/corrosive_acid/weak, /datum/action/xeno_action/activable/transfer_plasma, ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/onclick/plant_weeds/gardener, // second macro /datum/action/xeno_action/activable/resin_surge, // third macro /datum/action/xeno_action/onclick/plant_resin_fruit/greater, // fourth macro /datum/action/xeno_action/onclick/change_fruit, ) - keystone = TRUE + behavior_delegate_type = /datum/behavior_delegate/drone_gardener -/datum/xeno_mutator/gardener/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) +/datum/xeno_strain/gardener/apply_strain(mob/living/carbon/xenomorph/drone/drone) . = ..() - if (. == 0) - return - var/mob/living/carbon/xenomorph/drone/drone = mutator_set.xeno - drone.mutation_type = DRONE_GARDENER - drone.available_fruits = list(/obj/effect/alien/resin/fruit/greater, /obj/effect/alien/resin/fruit/unstable, /obj/effect/alien/resin/fruit/spore, /obj/effect/alien/resin/fruit/speed, /obj/effect/alien/resin/fruit/plasma) + drone.available_fruits = list( + /obj/effect/alien/resin/fruit/greater, + /obj/effect/alien/resin/fruit/unstable, + /obj/effect/alien/resin/fruit/spore, + /obj/effect/alien/resin/fruit/speed, + /obj/effect/alien/resin/fruit/plasma + ) drone.selected_fruit = /obj/effect/alien/resin/fruit/greater drone.max_placeable = 6 drone.regeneration_multiplier = XENO_REGEN_MULTIPLIER_TIER_1 - mutator_update_actions(drone) - apply_behavior_holder(drone) + // Also change the primacy value for our place construction ability (because we want it in the same place but have another primacy ability) for(var/datum/action/xeno_action/action in drone.actions) if(istype(action, /datum/action/xeno_action/activable/place_construction)) action.ability_primacy = XENO_NOT_PRIMARY_ACTION break // Don't need to keep looking - mutator_set.recalculate_actions(description, flavor_description) /datum/action/xeno_action/onclick/plant_resin_fruit name = "Plant Resin Fruit (50)" diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm index 86f50b47e080..3f698345193e 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm @@ -1,18 +1,16 @@ -/datum/xeno_mutator/healer - name = "STRAIN: Drone - Healer" +/datum/xeno_strain/healer + name = DRONE_HEALER description = "You lose your choice of resin secretions, a chunk of your slash damage, and you will experience a slighty-increased difficulty in tackling tallhosts in exchange for strong pheromones, the ability to use a bit of your health to plant a maximum of three lesser resin fruits, and the ability to heal your sisters' wounds by secreting a regenerative resin salve by using your vital fluids and a fifth of your plasma. Be wary, this is a dangerous process; overexert yourself and you may exhaust yourself to unconsciousness, or die..." flavor_description = "To the very last drop, your blood belongs to The Hive; share it with your sisters to keep them fighting." - cost = MUTATOR_COST_EXPENSIVE - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_DRONE) //Only drone. - mutator_actions_to_remove = list( + + actions_to_remove = list( /datum/action/xeno_action/activable/secrete_resin, /datum/action/xeno_action/onclick/choose_resin, /datum/action/xeno_action/activable/transfer_plasma, /datum/action/xeno_action/activable/place_construction, // so it doesn't use fifth macro /datum/action/xeno_action/onclick/plant_weeds, // so it doesn't break order ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/activable/place_construction/not_primary, // so it doesn't use fifth macro /datum/action/xeno_action/onclick/plant_weeds, // so it doesn't break order /datum/action/xeno_action/onclick/plant_resin_fruit, // Second macro. Resin fruits belong to Gardener, but Healer has a minor variant. @@ -20,32 +18,22 @@ /datum/action/xeno_action/activable/transfer_plasma/healer, //Fourth macro, an improved plasma transfer. /datum/action/xeno_action/activable/healer_sacrifice, //Fifth macro, the ultimate ability to sacrifice yourself ) - keystone = TRUE - behavior_delegate_type = /datum/behavior_delegate/drone_healer + behavior_delegate_type = /datum/behavior_delegate/drone_healer -/datum/xeno_mutator/healer/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) +/datum/xeno_strain/healer/apply_strain(mob/living/carbon/xenomorph/drone/drone) . = ..() - if (. == 0) - return - var/mob/living/carbon/xenomorph/drone/drone = mutator_set.xeno - drone.mutation_type = DRONE_HEALER drone.phero_modifier += XENO_PHERO_MOD_LARGE drone.plasma_types += PLASMA_PHEROMONE drone.damage_modifier -= XENO_DAMAGE_MOD_VERY_SMALL + drone.tackle_chance_modifier -= 5 drone.max_placeable = 3 drone.available_fruits = list(/obj/effect/alien/resin/fruit) drone.selected_fruit = /obj/effect/alien/resin/fruit - drone.tackle_chance_modifier -= 5 - mutator_update_actions(drone) - apply_behavior_holder(drone) - mutator_set.recalculate_actions(description, flavor_description) - drone.recalculate_health() - drone.recalculate_damage() - drone.recalculate_pheromones() - drone.recalculate_tackle() + + drone.recalculate_everything() /* Improved Plasma Transfer @@ -301,4 +289,3 @@ to_chat(xeno, SPAN_HIGHDANGER("Warning: [name] is a last measure skill. Using it will kill us.")) else to_chat(xeno, SPAN_HIGHDANGER("Warning: [name] is a last measure skill. Using it will kill us, but new life will be granted for our hard work for the hive.")) - diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/facehugger/watcher.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/facehugger/watcher.dm new file mode 100644 index 000000000000..1b7e09a584ef --- /dev/null +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/facehugger/watcher.dm @@ -0,0 +1,18 @@ +/datum/xeno_strain/watcher + name = FACEHUGGER_WATCHER + description = "You lose your ability to hide in exchange to see further and the ability to no longer take damage outside of weeds. This enables you to stalk your host from a distance and wait for the perfect oppertunity to strike." + flavor_description = "No need to hide when you can see the danger." + + actions_to_remove = list( + /datum/action/xeno_action/onclick/xenohide, + ) + actions_to_add = list( + /datum/action/xeno_action/onclick/toggle_long_range/runner, + ) + +/datum/xeno_strain/watcher/apply_strain(mob/living/carbon/xenomorph/facehugger/huggy) + . = ..() + + huggy.viewsize = 10 + huggy.layer = initial(huggy.layer) + return TRUE diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm index 3653209b78f2..a2013470df8a 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm @@ -1,41 +1,31 @@ -/datum/xeno_mutator/resinwhisperer - name = "STRAIN: Hivelord - Resin Whisperer" +/datum/xeno_strain/resin_whisperer + name = HIVELORD_RESIN_WHISPERER description = "You lose your corrosive acid, your ability to secrete thick resin, your ability to reinforce resin secretions, sacrifice your ability to plant resin nodes outside of weeds, and you sacrifice a fifth of your plasma reserves to enhance your vision and gain a stronger connection to the resin. You can now remotely place resin secretions including resin nodes up to a distance of twelve paces!" flavor_description = "Let the resin guide you. It whispers, so listen closely." - cost = MUTATOR_COST_EXPENSIVE - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_HIVELORD) - mutator_actions_to_remove = list( + + actions_to_remove = list( /datum/action/xeno_action/onclick/plant_weeds, /datum/action/xeno_action/activable/secrete_resin/hivelord, /datum/action/xeno_action/activable/corrosive_acid, /datum/action/xeno_action/activable/transfer_plasma/hivelord, /datum/action/xeno_action/active_toggle/toggle_speed, ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/activable/secrete_resin/remote, //third macro /datum/action/xeno_action/activable/transfer_plasma/hivelord, // readding it so it gets at the end of the ability list /datum/action/xeno_action/active_toggle/toggle_speed, // readding it so it gets at the end of the ability list ) - keystone = TRUE -/datum/xeno_mutator/resinwhisperer/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) +/datum/xeno_strain/resin_whisperer/apply_strain(mob/living/carbon/xenomorph/hivelord/hivelord) . = ..() - if(!.) - return - var/mob/living/carbon/xenomorph/hivelord/hivelord = mutator_set.xeno hivelord.plasmapool_modifier = 0.8 // -20% plasma pool hivelord.extra_build_dist = 12 // 1 + 12 = 13 tile build range hivelord.can_stack_builds = TRUE + hivelord.recalculate_plasma() hivelord.client.change_view(10, src) - hivelord.mutation_type = HIVELORD_RESIN_WHISPERER - mutator_update_actions(hivelord) - mutator_set.recalculate_actions(description, flavor_description) - hivelord.recalculate_plasma() - hivelord.set_resin_build_order(GLOB.resin_build_order_hivelord_whisperer) for(var/datum/action/xeno_action/action in hivelord.actions) // Also update the choose_resin icon since it resets diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm index 72214d06332e..4beec851c420 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm @@ -1,30 +1,22 @@ - -/datum/xeno_mutator/Vampire - name = "STRAIN: Lurker - Vampire" +/datum/xeno_strain/vampire + name = LURKER_VAMPIRE description = "You lose all of your abilities and you forefeit a chunk of your health and damage in exchange for a large amount of armor, a little bit of movement speed, increased attack speed, and brand new abilities that make you an assassin. Rush on your opponent to disorient them and Flurry to unleash a forward cleave that can hit and slow three talls and heal you for every tall you hit. Use your special AoE Tail Jab to knock talls away, doing more damage with direct hits and even more damage and a stun if they smack into walls. Finally, execute unconscious talls with a headbite that bypasses armor and heals you for a grand amount of health." flavor_description = "Your thirst for tallhost blood surpasses even mine, child. Show no mercy! Slaughter them all!" - cost = MUTATOR_COST_EXPENSIVE - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_LURKER) - mutator_actions_to_remove = list( + + actions_to_remove = list( /datum/action/xeno_action/onclick/lurker_invisibility, /datum/action/xeno_action/onclick/lurker_assassinate, /datum/action/xeno_action/activable/pounce/lurker, ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/activable/pounce/rush, /datum/action/xeno_action/activable/flurry, /datum/action/xeno_action/activable/tail_jab, /datum/action/xeno_action/activable/headbite, ) - keystone = TRUE -/datum/xeno_mutator/Vampire/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) +/datum/xeno_strain/vampire/apply_strain(mob/living/carbon/xenomorph/lurker/lurker) . = ..() - if (. == FALSE) - return - - var/mob/living/carbon/xenomorph/lurker/lurker = mutator_set.xeno lurker.plasmapool_modifier = 0 lurker.health_modifier -= XENO_HEALTH_MOD_MED @@ -34,7 +26,4 @@ lurker.melee_damage_upper = XENO_DAMAGE_TIER_3 lurker.attack_speed_modifier -= 2 - mutator_update_actions(lurker) - mutator_set.recalculate_actions(description, flavor_description) lurker.recalculate_everything() - lurker.mutation_type = LURKER_VAMPIRE diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm index a21f549ea8cd..2d6d7bb7b15d 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm @@ -1,44 +1,33 @@ -/datum/xeno_mutator/praetorian_dancer +/datum/xeno_strain/dancer // My name is Cuban Pete, I'm the King of the Rumba Beat - name = "STRAIN: Praetorian - Dancer" + name = PRAETORIAN_DANCER description = "You lose all of your acid-based abilities and a small amount of your armor in exchange for increased movement speed, evasion, and unparalleled agility that gives you an ability to move even more quickly, dodge bullets, and phase through tallhosts. By slashing tallhosts, you temporarily increase your movement speed and you also you apply a tag that changes how your two new tail abilities function. By tagging hosts, you will make Impale hit twice instead of once and make Tail Trip knock hosts down instead of stunning them." flavor_description = "Demonstrate to the talls what 'there is beauty in death' truly symbolizes, then dance upon their graves!" - cost = MUTATOR_COST_EXPENSIVE - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_PRAETORIAN) // Only bae - mutator_actions_to_remove = list( + xeno_icon_state = PRAETORIAN_DANCER + + actions_to_remove = list( /datum/action/xeno_action/activable/xeno_spit, /datum/action/xeno_action/activable/pounce/base_prae_dash, /datum/action/xeno_action/activable/prae_acid_ball, /datum/action/xeno_action/activable/spray_acid/base_prae_spray_acid, ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/activable/prae_impale, /datum/action/xeno_action/onclick/prae_dodge, /datum/action/xeno_action/activable/prae_tail_trip, ) + behavior_delegate_type = /datum/behavior_delegate/praetorian_dancer - keystone = TRUE -/datum/xeno_mutator/praetorian_dancer/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) +/datum/xeno_strain/dancer/apply_strain(mob/living/carbon/xenomorph/praetorian/prae) . = ..() - if (. == 0) - return - - var/mob/living/carbon/xenomorph/praetorian/praetorian = mutator_set.xeno - praetorian.armor_modifier -= XENO_ARMOR_MOD_VERY_SMALL - praetorian.speed_modifier += XENO_SPEED_FASTMOD_TIER_5 - praetorian.plasma_types = list(PLASMA_CATECHOLAMINE) - praetorian.claw_type = CLAW_TYPE_SHARP - - mutator_update_actions(praetorian) - mutator_set.recalculate_actions(description, flavor_description) - praetorian.recalculate_everything() + prae.armor_modifier -= XENO_ARMOR_MOD_VERY_SMALL + prae.speed_modifier += XENO_SPEED_FASTMOD_TIER_5 + prae.plasma_types = list(PLASMA_CATECHOLAMINE) + prae.claw_type = CLAW_TYPE_SHARP - apply_behavior_holder(praetorian) - praetorian.mutation_icon_state = PRAETORIAN_DANCER - praetorian.mutation_type = PRAETORIAN_DANCER + prae.recalculate_everything() /datum/behavior_delegate/praetorian_dancer name = "Praetorian Dancer Behavior Delegate" diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm index 4beaedf8d6a8..6d3d50c1d12d 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm @@ -1,12 +1,11 @@ -/datum/xeno_mutator/praetorian_oppressor +/datum/xeno_strain/oppressor // Dread it, run from it, destiny still arrives... or should I say, I do - name = "STRAIN: Praetorian - Oppressor" + name = PRAETORIAN_OPPRESSOR description = "You abandon all of your acid-based abilities, your dash, some speed, and a bit of your slash damage for some resistance against small explosives, slashes that deal extra damage to prone targets, and a powerful hook ability that pulls up to three talls towards you, slows them, and has varying effects depending on how many talls you pull. You also gain a powerful punch that reduces your other abilities' cooldowns, pierces through armor, and does double damage in addition to rooting slowed targets. You can also knock talls back and slow them with your new Tail Lash and quickly grab a tall, slow it, and pull it towards you with your unique Tail Stab." flavor_description = "Dread it. Run from it. The Hive arrives all the same, or, more accurately, you do." - cost = MUTATOR_COST_EXPENSIVE - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_PRAETORIAN) - mutator_actions_to_remove = list( + xeno_icon_state = PRAETORIAN_OPPRESSOR + + actions_to_remove = list( /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/activable/xeno_spit, /datum/action/xeno_action/activable/pounce/base_prae_dash, @@ -14,38 +13,26 @@ /datum/action/xeno_action/activable/spray_acid/base_prae_spray_acid, /datum/action/xeno_action/activable/corrosive_acid, ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/activable/tail_stab/tail_seize, /datum/action/xeno_action/activable/prae_abduct, /datum/action/xeno_action/activable/oppressor_punch, /datum/action/xeno_action/activable/tail_lash, ) + behavior_delegate_type = /datum/behavior_delegate/oppressor_praetorian - keystone = TRUE -/datum/xeno_mutator/praetorian_oppressor/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) +/datum/xeno_strain/oppressor/apply_strain(mob/living/carbon/xenomorph/praetorian/prae) . = ..() - if (. == 0) - return - - var/mob/living/carbon/xenomorph/praetorian/praetorian = mutator_set.xeno - praetorian.damage_modifier -= XENO_DAMAGE_MOD_SMALL - praetorian.explosivearmor_modifier += XENO_EXPOSIVEARMOR_MOD_SMALL - praetorian.small_explosives_stun = FALSE - praetorian.speed_modifier += XENO_SPEED_SLOWMOD_TIER_5 - praetorian.plasma_types = list(PLASMA_NEUROTOXIN, PLASMA_CHITIN) - praetorian.claw_type = CLAW_TYPE_SHARP + prae.damage_modifier -= XENO_DAMAGE_MOD_SMALL + prae.explosivearmor_modifier += XENO_EXPOSIVEARMOR_MOD_SMALL + prae.small_explosives_stun = FALSE + prae.speed_modifier += XENO_SPEED_SLOWMOD_TIER_5 + prae.plasma_types = list(PLASMA_NEUROTOXIN, PLASMA_CHITIN) + prae.claw_type = CLAW_TYPE_SHARP - mutator_update_actions(praetorian) - - mutator_set.recalculate_actions(description, flavor_description) - - apply_behavior_holder(praetorian) - - praetorian.recalculate_everything() - praetorian.mutation_icon_state = PRAETORIAN_OPPRESSOR - praetorian.mutation_type = PRAETORIAN_OPPRESSOR + prae.recalculate_everything() /datum/behavior_delegate/oppressor_praetorian name = "Oppressor Praetorian Behavior Delegate" @@ -60,4 +47,3 @@ target_carbon.apply_armoured_damage(get_xeno_damage_slash(target_carbon, tearing_damage), ARMOR_MELEE, BRUTE, bound_xeno.zone_selected ? bound_xeno.zone_selected : "chest") target_carbon.visible_message(SPAN_DANGER("[bound_xeno] tears into [target_carbon]!")) playsound(bound_xeno, 'sound/weapons/alien_tail_attack.ogg', 25, TRUE) - diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm index d5ca8c4d6aad..b8baef5e518f 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm @@ -1,43 +1,33 @@ -/datum/xeno_mutator/vanguard - name = "STRAIN: Praetorian - Vanguard" +/datum/xeno_strain/vanguard + name = PRAETORIAN_VANGUARD description = "You forfeit all of your acid-based abilities and some health for some extra speed and a rechargable shield that can block one attack. Use your Pierce from up to three paces away to stab through talls, while stabbing through several will completely recharge your shield. Use your charge to plow through enemies and use it again to unleash a powerful AoE slash that reaches up to three paces. You also have a Cleave ability, amplified by your shield, which you can toggle to either immobilize or fling a target away." flavor_description = "They are my bulwark against the tallhosts. They are my Vanguard and they shall know no fear." - cost = MUTATOR_COST_EXPENSIVE - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_PRAETORIAN) //Only praetorian. - mutator_actions_to_remove = list( + xeno_icon_state = PRAETORIAN_VANGUARD + + actions_to_remove = list( /datum/action/xeno_action/activable/xeno_spit, /datum/action/xeno_action/activable/pounce/base_prae_dash, /datum/action/xeno_action/activable/prae_acid_ball, /datum/action/xeno_action/activable/spray_acid/base_prae_spray_acid, /datum/action/xeno_action/activable/corrosive_acid, ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/activable/pierce, /datum/action/xeno_action/activable/pounce/prae_dash, /datum/action/xeno_action/activable/cleave, /datum/action/xeno_action/onclick/toggle_cleave, ) + behavior_delegate_type = /datum/behavior_delegate/praetorian_vanguard - keystone = TRUE -/datum/xeno_mutator/vanguard/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) +/datum/xeno_strain/vanguard/apply_strain(mob/living/carbon/xenomorph/praetorian/prae) . = ..() - if (. == 0) - return - var/mob/living/carbon/xenomorph/praetorian/praetorian = mutator_set.xeno - praetorian.speed_modifier += XENO_SPEED_FASTMOD_TIER_3 - praetorian.health_modifier -= XENO_HEALTH_MOD_MED - praetorian.claw_type = CLAW_TYPE_SHARP - mutator_update_actions(praetorian) - mutator_set.recalculate_actions(description, flavor_description) - praetorian.recalculate_everything() + prae.speed_modifier += XENO_SPEED_FASTMOD_TIER_3 + prae.health_modifier -= XENO_HEALTH_MOD_MED + prae.claw_type = CLAW_TYPE_SHARP - praetorian.mutation_icon_state = PRAETORIAN_VANGUARD - praetorian.mutation_type = PRAETORIAN_VANGUARD - - apply_behavior_holder(praetorian) + prae.recalculate_everything() /datum/behavior_delegate/praetorian_vanguard name = "Praetorian Vanguard Behavior Delegate" @@ -103,8 +93,3 @@ var/datum/action/xeno_action/activable/cleave/caction = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/activable/cleave) if (istype(caction)) caction.buffed = TRUE - - - - - diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm index 4328058c8a8e..3cb42e59e175 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm @@ -1,45 +1,33 @@ -/datum/xeno_mutator/praetorian_warden +/datum/xeno_strain/warden // i mean so basically im braum - name = "STRAIN: Praetorian - Warden" + name = PRAETORIAN_WARDEN description = "You trade your acid ball, acid spray, dash, and a small bit of your slash damage and speed to become an effective medic. You gain the ability to emit strong pheromones, an ability that retrieves endangered, knocked-down or sitting allies and pulls them to your location, and you gain an internal hitpoint pool that fills with every slash against your enemies, which can be spent to aid your allies and yourself by healing them or curing their ailments." flavor_description = "Only in death does your sisters' service to the Queen end. They will be untouched by plague or disease; no sickness will blight them." - cost = MUTATOR_COST_EXPENSIVE - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_PRAETORIAN) // Only bae - mutator_actions_to_remove = list( + xeno_icon_state = PRAETORIAN_WARDEN + + actions_to_remove = list( /datum/action/xeno_action/activable/pounce/base_prae_dash, /datum/action/xeno_action/activable/prae_acid_ball, /datum/action/xeno_action/activable/spray_acid/base_prae_spray_acid, ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/activable/spray_acid/prae_warden, /datum/action/xeno_action/activable/warden_heal, /datum/action/xeno_action/activable/prae_retrieve, /datum/action/xeno_action/onclick/prae_switch_heal_type, /datum/action/xeno_action/onclick/emit_pheromones, ) + behavior_delegate_type = /datum/behavior_delegate/praetorian_warden - keystone = TRUE -/datum/xeno_mutator/praetorian_warden/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) +/datum/xeno_strain/warden/apply_strain(mob/living/carbon/xenomorph/praetorian/prae) . = ..() - if (. == 0) - return - - var/mob/living/carbon/xenomorph/praetorian/praetorian = mutator_set.xeno // Make a 'halftank' - praetorian.speed_modifier += XENO_SPEED_SLOWMOD_TIER_5 - praetorian.damage_modifier -= XENO_DAMAGE_MOD_SMALL - - mutator_update_actions(praetorian) - mutator_set.recalculate_actions(description, flavor_description) - - praetorian.recalculate_everything() + prae.speed_modifier += XENO_SPEED_SLOWMOD_TIER_5 + prae.damage_modifier -= XENO_DAMAGE_MOD_SMALL - apply_behavior_holder(praetorian) - praetorian.mutation_icon_state = PRAETORIAN_WARDEN - praetorian.mutation_type = PRAETORIAN_WARDEN + prae.recalculate_everything() /datum/behavior_delegate/praetorian_warden name = "Praetorian Warden Behavior Delegate" diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/berserker.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/berserker.dm index 7881c9aa75f1..80261d295ab6 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/berserker.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/berserker.dm @@ -1,39 +1,29 @@ -/datum/xeno_mutator/berserker - name = "STRAIN: Ravager - Berserker" +/datum/xeno_strain/berserker + name = RAVAGER_BERSERKER description = "You lose your empower, charge, and scissor cut, decrease your health, and sacrifice a bit of your influence under frenzy pheromones to increase your movement speed, slightly increase your armor, and gain a new set of abilities that make you a terrifying melee monster. By slashing, you heal yourself and gain a stack of rage that increases your armor, movement speed, attack speed, and your heals per slash, to a maximum of six rage. Use your new Appehend ability to increase your movement speed and apply a slow on the next target you slash and use your Clothesline ability to fling your target to heal yourself, even more-so if you have a rage stack that will be used up. Finally, use your Eviscerate to unleash a devastating windmill attack that heals you for every host you hit after an immobilizing wind-up." flavor_description = "They shall be my finest warriors. They will rend and tear, crush and butcher, and maim and rage until every tallhost falls." - cost = MUTATOR_COST_EXPENSIVE - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_RAVAGER) - mutator_actions_to_remove = list( + + actions_to_remove = list( /datum/action/xeno_action/onclick/empower, /datum/action/xeno_action/activable/pounce/charge, /datum/action/xeno_action/activable/scissor_cut, ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/onclick/apprehend, /datum/action/xeno_action/activable/clothesline, /datum/action/xeno_action/activable/eviscerate, ) - keystone = TRUE + behavior_delegate_type = /datum/behavior_delegate/ravager_berserker -/datum/xeno_mutator/berserker/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) +/datum/xeno_strain/berserker/apply_strain(mob/living/carbon/xenomorph/ravager/ravager) . = ..() - if (. == 0) - return - var/mob/living/carbon/xenomorph/ravager/ravager = mutator_set.xeno - ravager.mutation_type = RAVAGER_BERSERKER ravager.plasma_max = 0 ravager.health_modifier -= XENO_HEALTH_MOD_MED ravager.armor_modifier += XENO_ARMOR_MOD_VERY_SMALL ravager.speed_modifier += XENO_SPEED_FASTMOD_TIER_3 ravager.received_phero_caps["frenzy"] = 2.9 // Moderate - mutator_update_actions(ravager) - mutator_set.recalculate_actions(description, flavor_description) - - apply_behavior_holder(ravager) ravager.recalculate_everything() diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm index 913883549fba..75a85ca3e72e 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm @@ -1,41 +1,29 @@ -/datum/xeno_mutator/hedgehog - name = "STRAIN: Ravager - Hedgehog" +/datum/xeno_strain/hedgehog + name = RAVAGER_HEDGEHOG description = "You lose your empower, charge, scissor cut and some slash damage, for a bit more explosive resistance, immunity to small explosions, and you gain several new abilities that allow you to become a spiky tank. You build up shards internally over time and also when taking damage that increase your armor's resilience. You can use these shards to power three new abilities: Spike Shield, which gives you a temporary shield that spits bone shards around you when damaged, Fire Spikes, which launches spikes at your target that slows them and does extra damage if they move, and finally, Spike Shed, which launches spikes all around yourself and gives you a temporary speed boost as an escape plan at the cost of all your stored shards and being unable to gain shards for thirty seconds." flavor_description = "They will be of iron will and steely muscle. In great armor shall they be clad, and with the mightiest spikes will they be armed." - cost = MUTATOR_COST_EXPENSIVE - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_RAVAGER) // Only Ravager. - mutator_actions_to_remove = list( + + actions_to_remove = list( /datum/action/xeno_action/onclick/empower, /datum/action/xeno_action/activable/pounce/charge, /datum/action/xeno_action/activable/scissor_cut, ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/onclick/spike_shield, /datum/action/xeno_action/activable/rav_spikes, /datum/action/xeno_action/onclick/spike_shed, ) + behavior_delegate_type = /datum/behavior_delegate/ravager_hedgehog - keystone = TRUE -/datum/xeno_mutator/hedgehog/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) +/datum/xeno_strain/hedgehog/apply_strain(mob/living/carbon/xenomorph/ravager/ravager) . = ..() - if (. == 0) - return - var/mob/living/carbon/xenomorph/ravager/ravager = mutator_set.xeno - - ravager.mutation_type = RAVAGER_HEDGEHOG ravager.plasma_max = 0 ravager.small_explosives_stun = FALSE ravager.explosivearmor_modifier += XENO_EXPOSIVEARMOR_MOD_SMALL ravager.damage_modifier -= XENO_DAMAGE_MOD_SMALL - apply_behavior_holder(ravager) - - mutator_update_actions(ravager) - mutator_set.recalculate_actions(description, flavor_description) - ravager.recalculate_everything() /datum/behavior_delegate/ravager_hedgehog diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm index 490e5ca36cba..d768ad61ce2d 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm @@ -1,37 +1,30 @@ -/datum/xeno_mutator/acider - name = "STRAIN: Runner - Acider" +/datum/xeno_strain/acider + name = RUNNER_ACIDER description = "At the cost of a little bit of your speed and all of your current abilities, you gain a considerable amount of health, some armor, and a new organ that fills with volatile acid over time. Your Tail Stab and slashes apply acid to living lifeforms that slowly burns them, and slashes against targets with acid stacks fill your acid glands. You also gain Corrosive Acid equivalent to that of a boiler that you can deploy more quickly than any other caste, at the cost of a chunk of your acid reserves with each use. Finally, after a twenty second windup, you can force your body to explode, covering everything near you with acid. The more acid you have stored, the more devastating the explosion will be, but during those twenty seconds before detonation you are slowed and give off several warning signals which give talls an opportunity to end you before you can detonate. If you successfully explode, you will reincarnate as a larva again!" flavor_description = "Burn their walls, maim their faces! Your life, for The Hive!" - cost = MUTATOR_COST_EXPENSIVE - individual_only = TRUE - caste_whitelist = list(XENO_CASTE_RUNNER) - keystone = TRUE - behavior_delegate_type = /datum/behavior_delegate/runner_acider - mutator_actions_to_remove = list( + xeno_icon_state = RUNNER_ACIDER + + actions_to_remove = list( /datum/action/xeno_action/activable/pounce/runner, /datum/action/xeno_action/activable/runner_skillshot, /datum/action/xeno_action/onclick/toggle_long_range/runner, ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/activable/acider_acid, /datum/action/xeno_action/activable/acider_for_the_hive, ) -/datum/xeno_mutator/acider/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) + behavior_delegate_type = /datum/behavior_delegate/runner_acider + +/datum/xeno_strain/acider/apply_strain(mob/living/carbon/xenomorph/runner/runner) . = ..() - if (. == 0) - return - var/mob/living/carbon/xenomorph/runner/runner = mutator_set.xeno - runner.mutation_icon_state = RUNNER_ACIDER - runner.mutation_type = RUNNER_ACIDER runner.speed_modifier += XENO_SPEED_SLOWMOD_TIER_5 runner.armor_modifier += XENO_ARMOR_MOD_MED runner.health_modifier += XENO_HEALTH_MOD_ACIDER - apply_behavior_holder(runner) - mutator_update_actions(runner) + runner.recalculate_everything() - mutator_set.recalculate_actions(description, flavor_description) + /datum/behavior_delegate/runner_acider var/acid_amount = 0 diff --git a/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm b/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm index 4048af28bc81..af1511a3601e 100644 --- a/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm +++ b/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm @@ -39,7 +39,7 @@ * * If that isn't available, returns "Normal" */ -/mob/living/carbon/xenomorph/proc/get_strain_sprite() +/mob/living/carbon/xenomorph/proc/get_strain_icon() return strain?.xeno_icon_state || "Normal" // TODO: Go through xeno/xenoid sprites and remove "Normal", so that this isn't needed. @@ -67,4 +67,4 @@ return caste.fire_intensity_resistance /mob/living/carbon/xenomorph/alter_ghost(mob/dead/observer/ghost) - ghost.icon_state = "[get_strain_sprite()] [caste.caste_type] Running" + ghost.icon_state = "[get_strain_icon()] [caste.caste_type] Running" diff --git a/colonialmarines.dme b/colonialmarines.dme index adffc94774b2..c736fbf45b25 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -2048,6 +2048,7 @@ #include "code\modules\mob\living\carbon\xenomorph\strains\castes\defender\steel_crest.dm" #include "code\modules\mob\living\carbon\xenomorph\strains\castes\drone\gardener.dm" #include "code\modules\mob\living\carbon\xenomorph\strains\castes\drone\healer.dm" +#include "code\modules\mob\living\carbon\xenomorph\strains\castes\facehugger\watcher.dm" #include "code\modules\mob\living\carbon\xenomorph\strains\castes\hivelord\resin_whisperer.dm" #include "code\modules\mob\living\carbon\xenomorph\strains\castes\lurker\vampire.dm" #include "code\modules\mob\living\carbon\xenomorph\strains\castes\praetorian\dancer.dm" From 2e5562784cf9e4cf7da7dc2ea4b6ecce3d94af44 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Mon, 22 Jan 2024 19:46:03 +0000 Subject: [PATCH 04/17] Unused burrower strain The 'Tremor' burrower sprites look the same as the regular burrower, so I've just removed the icon update part. --- .../carbon/xenomorph/castes/Burrower.dm | 10 ---------- icons/mob/xenos/burrower.dmi | Bin 28208 -> 13039 bytes 2 files changed, 10 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm b/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm index 886ffcfe1ef2..bec41a87521e 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm @@ -74,8 +74,6 @@ /mob/living/carbon/xenomorph/proc/set_hugger_reserve_for_morpher, ) - mutation_type = BURROWER_NORMAL - icon_xeno = 'icons/mob/xenos/burrower.dmi' icon_xenonid = 'icons/mob/xenonids/burrower.dmi' @@ -109,11 +107,3 @@ /datum/behavior_delegate/burrower_base name = "Base Burrower Behavior Delegate" - -/datum/behavior_delegate/burrower_base/on_update_icons() - if(bound_xeno.stat == DEAD) - return - - if(HAS_TRAIT(bound_xeno, TRAIT_ABILITY_BURROWED)) - bound_xeno.icon_state = "[bound_xeno.mutation_icon_state] Burrower Burrowed" - return TRUE diff --git a/icons/mob/xenos/burrower.dmi b/icons/mob/xenos/burrower.dmi index f546776e6b27d801f23ecb0a86e77d3df36995a4..c54684e61bc90d4b969a5f66bed366337bd54fd4 100644 GIT binary patch literal 13039 zcmcheXHXQ;*Qc8xIVwm75tW>C&M1gv5J9qJh9EHHqyz;95Q)OT03tc(jHE#_l7=kF zA%`Ij48!{0x3+e-_UqPLb*pZF=ucg@`#jG%zy7SJ^PHT7kput$a?KZN1^|Hb?-B{js-&#v1Q%TYp*naw= zOo$xFsmC$%=D#>1-G$*1w|02=Uq-*ot59txiBR(^>CVI z5yi=cu{qaaMO%HbQnM3slV-?FF83Hv=?~B`L?=%IfC!GJnzE69_5m~`{_R}AN+LJN zIQfrRYN5kMcZxw?JecnO2btm)@nXeKrtZK@GH!%$cX6t!w172j#5?m3#s$hGbFsAM zDrTgg_=OYl?l;`)k)XvP-U#=7O7#-Y%Vy%y)_sIYK28jUee~lzdq_on$9T)>QovuR z_fhbE@X~xhShuyqAyOJCe*_O0ZxLmeO4#`CTVpAw30})rHOr)X7);B9BDe_!Jkz0) z75*v@6L;z%*%cFY?ks}ah%K_5U)QLPBwP*IYYoj^Mw+DgJ$SBS5j@$fWyt-z z-Nb8`IaRh6d+4RU!KHR81b$)e*9M}Gm&5%8Nf&>Z!ZtxfdiMQq{ zb+s?G&(f8%3U&kixwxRd7l0q zuQ`CNn26304jdsvz9C;%KqaEFK16_T zqY3vlt8wB@u+Uz>R^h|%rvf^){L?K^5EZ@xL!9}R4VcQuBBPCci6LyZXT zhm}x>%D8Ng%f46^yKt!pAB}OmyfqSzr6*oSYvf@{myWO6dbf_Je@UK_Iz-#ZPs^=^tOjoCGj#fcBK$)4R^QPR4P7>T`k3kaoNY}ZeS-si{`sMb|(zAbK8_4 z6^`&dK?!D#1w4IVSi-4;UXybwNh7M=W88QRoxa#qr!4uAx>}kNckTU^T@(D0IQ|ot z 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 DL#(E6 literal 28208 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 Date: Mon, 22 Jan 2024 19:49:30 +0000 Subject: [PATCH 05/17] More stuff --- code/__DEFINES/mobs.dm | 42 ------------------- code/__DEFINES/xeno.dm | 42 +++++++++++++++++++ .../carbon/xenomorph/castes/Hellhound.dm | 1 - .../living/carbon/xenomorph/castes/Larva.dm | 1 - .../carbon/xenomorph/castes/Predalien.dm | 2 - .../living/carbon/xenomorph/castes/Queen.dm | 2 - .../carbon/xenomorph/castes/Sentinel.dm | 1 - .../living/carbon/xenomorph/castes/Spitter.dm | 1 - .../living/carbon/xenomorph/castes/Warrior.dm | 1 - .../carbon/xenomorph/castes/lesser_drone.dm | 2 - .../living/carbon/xenomorph/update_icons.dm | 4 +- 11 files changed, 44 insertions(+), 55 deletions(-) diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index e67fa1b21845..5e35411d3b20 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -306,48 +306,6 @@ #define CAN_HOLD_TWO_HANDS 1 #define CAN_HOLD_ONE_HAND 2 -// ------------ // -// STRAIN FLAGS // -// ------------ // - -// Facehugger strain flags -#define FACEHUGGER_WATCHER "Watcher" - -// Drone strain flags -#define DRONE_HEALER "Healer" -#define DRONE_GARDENER "Gardener" - -// Hivelord strain flags -#define HIVELORD_RESIN_WHISPERER "Resin Whisperer" - -// Carrier strain flags -#define CARRIER_EGGSAC "Eggsac" - -// Boiler strain flags -#define BOILER_TRAPPER "Trapper" - -// Runner strain flags -#define RUNNER_ACIDER "Acider" - -// Lurker strain flags -#define LURKER_VAMPIRE "Vampire" - -// Ravager strain flags -#define RAVAGER_HEDGEHOG "Hedgehog" -#define RAVAGER_BERSERKER "Berserker" - -// Defender strain flags -#define DEFENDER_STEELCREST "Steelcrest" - -// Crusher strain flags -#define CRUSHER_CHARGER "Charger" - -// Praetorian strain flags -#define PRAETORIAN_VANGUARD "Vanguard" -#define PRAETORIAN_DANCER "Dancer" -#define PRAETORIAN_WARDEN "Warden" -#define PRAETORIAN_OPPRESSOR"Oppressor" - GLOBAL_LIST_INIT(default_onmob_icons, list( WEAR_L_HAND = 'icons/mob/humans/onmob/items_lefthand_0.dmi', WEAR_R_HAND = 'icons/mob/humans/onmob/items_righthand_0.dmi', diff --git a/code/__DEFINES/xeno.dm b/code/__DEFINES/xeno.dm index e3a35d0c4744..33aa3d5fbc64 100644 --- a/code/__DEFINES/xeno.dm +++ b/code/__DEFINES/xeno.dm @@ -361,6 +361,48 @@ #define RESIN_CONSTRUCTION_NO_MAX -1 +// -------------- // +// STRAIN DEFINES // +// -------------- // + +// Facehugger strain flags +#define FACEHUGGER_WATCHER "Watcher" + +// Drone strain flags +#define DRONE_HEALER "Healer" +#define DRONE_GARDENER "Gardener" + +// Hivelord strain flags +#define HIVELORD_RESIN_WHISPERER "Resin Whisperer" + +// Carrier strain flags +#define CARRIER_EGGSAC "Eggsac" + +// Boiler strain flags +#define BOILER_TRAPPER "Trapper" + +// Runner strain flags +#define RUNNER_ACIDER "Acider" + +// Lurker strain flags +#define LURKER_VAMPIRE "Vampire" + +// Ravager strain flags +#define RAVAGER_HEDGEHOG "Hedgehog" +#define RAVAGER_BERSERKER "Berserker" + +// Defender strain flags +#define DEFENDER_STEELCREST "Steelcrest" + +// Crusher strain flags +#define CRUSHER_CHARGER "Charger" + +// Praetorian strain flags +#define PRAETORIAN_VANGUARD "Vanguard" +#define PRAETORIAN_DANCER "Dancer" +#define PRAETORIAN_WARDEN "Warden" +#define PRAETORIAN_OPPRESSOR "Oppressor" + ///////////////////////////////////////////////////////////////////////////////////// // // Modifiers diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm b/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm index 6868fd5ac589..93d40820bf7b 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm @@ -64,7 +64,6 @@ inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, ) - mutation_type = HELLHOUND_NORMAL icon_xeno = 'icons/mob/xenos/hellhound.dmi' icon_xenonid = 'icons/mob/xenos/hellhound.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Larva.dm b/code/modules/mob/living/carbon/xenomorph/castes/Larva.dm index f1c77e7fb757..c06b8c43839d 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Larva.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Larva.dm @@ -46,7 +46,6 @@ inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, ) - mutation_type = "Normal" var/burrowable = TRUE //Can it be safely burrowed if it has no player? var/state_override diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm b/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm index bcf47386fefc..ebae6f56830f 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm @@ -63,8 +63,6 @@ /datum/action/xeno_action/onclick/tacmap, ) - mutation_type = "Normal" - weed_food_icon = 'icons/mob/xenos/weeds_64x64.dmi' weed_food_states = list("Predalien_1","Predalien_2","Predalien_3") weed_food_states_flipped = list("Predalien_1","Predalien_2","Predalien_3") diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm index f847c1a4ac8a..db2a9b4a38de 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm @@ -350,8 +350,6 @@ /datum/action/xeno_action/activable/xeno_spit/queen_macro, //third macro /datum/action/xeno_action/onclick/shift_spits, //second macro ) - mutation_icon_state = QUEEN_NORMAL - mutation_type = QUEEN_NORMAL claw_type = CLAW_TYPE_VERY_SHARP var/queen_aged = FALSE diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm b/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm index a568a093b3a4..2e53f97e297b 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm @@ -53,7 +53,6 @@ inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, ) - mutation_type = SENTINEL_NORMAL icon_xeno = 'icons/mob/xenos/sentinel.dmi' icon_xenonid = 'icons/mob/xenonids/sentinel.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm b/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm index 9ad2f4909fb8..984a2d08bb75 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm @@ -56,7 +56,6 @@ inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, ) - mutation_type = SPITTER_NORMAL icon_xeno = 'icons/mob/xenos/spitter.dmi' icon_xenonid = 'icons/mob/xenonids/spitter.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Warrior.dm b/code/modules/mob/living/carbon/xenomorph/castes/Warrior.dm index b19978a33766..1c329c8b9e82 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Warrior.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Warrior.dm @@ -55,7 +55,6 @@ /datum/action/xeno_action/onclick/tacmap, ) - mutation_type = WARRIOR_NORMAL claw_type = CLAW_TYPE_SHARP icon_xeno = 'icons/mob/xenos/warrior.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/lesser_drone.dm b/code/modules/mob/living/carbon/xenomorph/castes/lesser_drone.dm index f050a0dcfe8a..de239aa72e5c 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/lesser_drone.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/lesser_drone.dm @@ -74,8 +74,6 @@ /mob/living/carbon/xenomorph/proc/set_hugger_reserve_for_morpher, ) - mutation_type = DRONE_NORMAL - icon_xeno = 'icons/mob/xenos/lesser_drone.dmi' icon_xenonid = 'icons/mob/xenonids/lesser_drone.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/update_icons.dm b/code/modules/mob/living/carbon/xenomorph/update_icons.dm index ebf7566c0131..571f261ab981 100644 --- a/code/modules/mob/living/carbon/xenomorph/update_icons.dm +++ b/code/modules/mob/living/carbon/xenomorph/update_icons.dm @@ -41,7 +41,7 @@ Q.queen_standing_icon = icon_xeno Q.queen_ovipositor_icon = 'icons/mob/xenos/ovipositor.dmi' - var/mutation_caste_state = "[strain?.xeno_icon_state] [caste.caste_type]" + var/mutation_caste_state = "[get_strain_icon()] [caste.caste_type]" if(!walking_state_cache[mutation_caste_state]) var/cache_walking_state = FALSE for(var/state in icon_states(icon)) @@ -64,7 +64,7 @@ if(behavior_delegate?.on_update_icons()) return - var/mutation_caste_state = "[strain?.xeno_icon_state] [caste.caste_type]" + var/mutation_caste_state = "[get_strain_icon()] [caste.caste_type]" if(stat == DEAD) icon_state = "[mutation_caste_state] Dead" if(!(icon_state in icon_states(icon_xeno))) From e75a626f05dffa299e4aa9d81950a387ddbe276d Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Mon, 22 Jan 2024 23:58:23 +0000 Subject: [PATCH 06/17] `available_strains` to caste It makes more sense there really --- .../modules/mob/living/carbon/xenomorph/Xenomorph.dm | 3 --- .../mob/living/carbon/xenomorph/castes/Boiler.dm | 2 +- .../mob/living/carbon/xenomorph/castes/Carrier.dm | 3 ++- .../mob/living/carbon/xenomorph/castes/Crusher.dm | 2 +- .../mob/living/carbon/xenomorph/castes/Defender.dm | 3 +-- .../mob/living/carbon/xenomorph/castes/Drone.dm | 9 +++++---- .../mob/living/carbon/xenomorph/castes/Facehugger.dm | 3 ++- .../mob/living/carbon/xenomorph/castes/Hivelord.dm | 4 ++-- .../mob/living/carbon/xenomorph/castes/Lurker.dm | 2 +- .../mob/living/carbon/xenomorph/castes/Praetorian.dm | 12 ++++++------ .../mob/living/carbon/xenomorph/castes/Ravager.dm | 8 ++++---- .../mob/living/carbon/xenomorph/castes/Runner.dm | 3 ++- .../living/carbon/xenomorph/castes/caste_datum.dm | 3 +++ .../living/carbon/xenomorph/strains/xeno_strain.dm | 2 +- 14 files changed, 31 insertions(+), 28 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index 5245230c20e7..cb1704c8be5b 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -130,9 +130,6 @@ var/weed_level = WEED_LEVEL_STANDARD var/acid_level = 0 - // Strain-related vars - /// A list of strain typepaths that the xeno is able to choose. - var/list/available_strains = list() /// The xeno's strain, if they've taken one. var/datum/xeno_strain/strain = null diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm b/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm index 02c48ae3d6dd..f7e906a82b28 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm @@ -13,6 +13,7 @@ evasion = XENO_EVASION_NONE speed = XENO_SPEED_TIER_3 + available_strains = list(/datum/xeno_strain/trapper) behavior_delegate_type = /datum/behavior_delegate/boiler_base evolution_allowed = FALSE @@ -53,7 +54,6 @@ spit_delay = 30 SECONDS tileoffset = 3 viewsize = 7 - available_strains = list(/datum/xeno_strain/trapper) icon_xeno = 'icons/mob/xenos/boiler.dmi' icon_xenonid = 'icons/mob/xenonids/boiler.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm index 713b66bfa5c1..c800f129e3ff 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm @@ -14,6 +14,8 @@ evasion = XENO_EVASION_NONE speed = XENO_SPEED_TIER_4 + available_strains = list(/datum/xeno_strain/eggsac) + evolution_allowed = FALSE deevolves_to = list(XENO_CASTE_DRONE) throwspeed = SPEED_AVERAGE @@ -75,7 +77,6 @@ /mob/living/carbon/xenomorph/proc/rename_tunnel, /mob/living/carbon/xenomorph/proc/set_hugger_reserve_for_morpher, ) - available_strains = list(/datum/xeno_strain/eggsac) icon_xenonid = 'icons/mob/xenonids/carrier.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm index b48de1b34d54..f7d986570f9f 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm @@ -14,6 +14,7 @@ speed = XENO_SPEED_TIER_2 heal_standing = 0.66 + available_strains = list(/datum/xeno_strain/charger) behavior_delegate_type = /datum/behavior_delegate/crusher_base minimum_evolve_time = 15 MINUTES @@ -63,7 +64,6 @@ ) claw_type = CLAW_TYPE_VERY_SHARP - available_strains = list(/datum/xeno_strain/charger) icon_xeno = 'icons/mob/xenos/crusher.dmi' icon_xenonid = 'icons/mob/xenonids/crusher.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm b/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm index 18a7f2aeab65..23ba08e294ba 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm @@ -18,6 +18,7 @@ deevolves_to = list("Larva") can_vent_crawl = 0 + available_strains = list(/datum/xeno_strain/steel_crest) behavior_delegate_type = /datum/behavior_delegate/defender_base tackle_min = 2 @@ -51,8 +52,6 @@ /datum/action/xeno_action/onclick/tacmap, ) - available_strains = list(/datum/xeno_strain/steel_crest) - icon_xeno = 'icons/mob/xenos/defender.dmi' icon_xenonid = 'icons/mob/xenonids/defender.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm b/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm index 5c476e4a4067..a0ce70316eb8 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm @@ -12,6 +12,11 @@ evasion = XENO_EVASION_MEDIUM speed = XENO_SPEED_TIER_7 + available_strains = list( + /datum/xeno_strain/gardener, + /datum/xeno_strain/healer, + ) + build_time_mult = BUILD_TIME_MULT_BUILDER caste_desc = "A builder of hives. Only drones may evolve into Queens." @@ -69,10 +74,6 @@ /mob/living/carbon/xenomorph/proc/rename_tunnel, /mob/living/carbon/xenomorph/proc/set_hugger_reserve_for_morpher, ) - available_strains = list( - /datum/xeno_strain/gardener, - /datum/xeno_strain/healer, - ) icon_xeno = 'icons/mob/xenos/drone.dmi' icon_xenonid = 'icons/mob/xenonids/drone.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm b/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm index 75de76737255..83c61358e49d 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm @@ -9,6 +9,8 @@ caste_desc = "Ewwww, that's disgusting!" speed = XENO_SPEED_TIER_8 + available_strains = list(/datum/xeno_strain/watcher) + evolution_allowed = FALSE can_be_revived = FALSE @@ -55,7 +57,6 @@ inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, ) - available_strains = list(/datum/xeno_strain/watcher) icon_xeno = 'icons/mob/xenos/facehugger.dmi' icon_xenonid = 'icons/mob/xenonids/facehugger.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm b/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm index 766a3e571f8c..c821fbc49208 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm @@ -13,6 +13,8 @@ evasion = XENO_EVASION_NONE speed = XENO_SPEED_TIER_2 + available_strains = list(/datum/xeno_strain/resin_whisperer) + evolution_allowed = FALSE caste_desc = "A builder of really big hives." deevolves_to = list(XENO_CASTE_DRONE) @@ -76,8 +78,6 @@ /mob/living/carbon/xenomorph/proc/set_hugger_reserve_for_morpher, ) - available_strains = list(/datum/xeno_strain/resin_whisperer) - icon_xeno = 'icons/mob/xenos/hivelord.dmi' icon_xenonid = 'icons/mob/xenonids/hivelord.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm index df2589073f9c..b9bde4c78992 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm @@ -15,6 +15,7 @@ attack_delay = 2 // VERY high slash damage, but attacks relatively slowly + available_strains = list(/datum/xeno_strain/vampire) behavior_delegate_type = /datum/behavior_delegate/lurker_base deevolves_to = list(XENO_CASTE_RUNNER) @@ -50,7 +51,6 @@ inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, ) - available_strains = list(/datum/xeno_strain/vampire) claw_type = CLAW_TYPE_SHARP tackle_min = 2 diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm b/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm index a4c105de1dd6..69b679573352 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm @@ -26,6 +26,12 @@ tackle_max = 5 tackle_chance = 45 + available_strains = list( + /datum/xeno_strain/dancer, + /datum/xeno_strain/oppressor, + /datum/xeno_strain/vanguard, + /datum/xeno_strain/warden, + ) behavior_delegate_type = /datum/behavior_delegate/praetorian_base minimum_evolve_time = 15 MINUTES @@ -46,12 +52,6 @@ mob_size = MOB_SIZE_BIG drag_delay = 6 //pulling a big dead xeno is hard tier = 3 - available_strains = list( - /datum/xeno_strain/dancer, - /datum/xeno_strain/oppressor, - /datum/xeno_strain/vanguard, - /datum/xeno_strain/warden, - ) base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm b/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm index d05f2e22f4f7..e50a0f026d65 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm @@ -26,6 +26,10 @@ fire_immunity = FIRE_IMMUNITY_NO_DAMAGE|FIRE_IMMUNITY_XENO_FRENZY attack_delay = -1 + available_strains = list( + /datum/xeno_strain/berserker, + /datum/xeno_strain/hedgehog, + ) behavior_delegate_type = /datum/behavior_delegate/ravager_base minimum_evolve_time = 15 MINUTES @@ -45,10 +49,6 @@ tier = 3 pixel_x = -16 old_x = -16 - available_strains = list( - /datum/xeno_strain/berserker, - /datum/xeno_strain/hedgehog, - ) claw_type = CLAW_TYPE_VERY_SHARP base_actions = list( diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm b/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm index 3026ee2ee9da..400195f21de0 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm @@ -13,6 +13,8 @@ evasion = XENO_EVASION_NONE speed = XENO_SPEED_RUNNER attack_delay = -4 + + available_strains = list(/datum/xeno_strain/acider) behavior_delegate_type = /datum/behavior_delegate/runner_base evolves_to = list(XENO_CASTE_LURKER) deevolves_to = list("Larva") @@ -62,7 +64,6 @@ inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, ) - available_strains = list(/datum/xeno_strain/acider) icon_xeno = 'icons/mob/xenos/runner.dmi' icon_xenonid = 'icons/mob/xenonids/runner.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/caste_datum.dm b/code/modules/mob/living/carbon/xenomorph/castes/caste_datum.dm index cfaedf013a44..feee2edecb67 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/caste_datum.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/caste_datum.dm @@ -66,6 +66,9 @@ var/agility_speed_increase = 0 // this opens up possibilities for balancing + /// A list of strain typepaths that are able to be chosen by this caste. + var/list/available_strains = list() + // The type of mutator delegate to instantiate on the base caste. Will // be replaced when the Xeno chooses a strain. var/behavior_delegate_type = /datum/behavior_delegate diff --git a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm index fd43b23de993..57ba97050075 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm @@ -90,7 +90,7 @@ log_strain("[name] purchased strain '[strain_instance.type]'") /mob/living/carbon/xenomorph/proc/can_take_strain() - if(!length(available_strains) || !check_state(TRUE)) + if(!length(caste.available_strains) || !check_state(TRUE)) return FALSE if(is_ventcrawling) From f6d142c118caeb2d301af81d86da48fcdbc33d08 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Tue, 23 Jan 2024 13:32:28 +0000 Subject: [PATCH 07/17] Second pass (squashed commits) There's a lot of removed `mutation_type` checks in here, but as far as I can tell there's no way for other strains to access the ability in those cases. --- .../shield_types/vanguard_shield.dm | 7 +- .../abilities/crusher/crusher_powers.dm | 6 +- .../abilities/defender/defender_abilities.dm | 12 ++- .../abilities/defender/defender_powers.dm | 75 +++++++------ .../abilities/lurker/lurker_abilities.dm | 35 ------ .../abilities/lurker/lurker_powers.dm | 47 ++++++-- .../abilities/praetorian/praetorian_powers.dm | 82 ++++++-------- .../abilities/queen/queen_abilities.dm | 4 + .../abilities/ravager/ravager_powers.dm | 100 +++++++----------- .../abilities/runner/runner_powers.dm | 5 +- .../abilities/sentinel/sentinel_powers.dm | 6 -- .../living/carbon/xenomorph/castes/Carrier.dm | 23 ++-- .../living/carbon/xenomorph/castes/Crusher.dm | 2 +- .../carbon/xenomorph/castes/Defender.dm | 4 +- .../carbon/xenomorph/castes/Facehugger.dm | 35 +++--- .../carbon/xenomorph/castes/Hivelord.dm | 7 -- .../living/carbon/xenomorph/castes/Queen.dm | 4 +- .../strains/castes/carrier/eggsac.dm | 8 ++ .../strains/castes/defender/steel_crest.dm | 4 + .../xenomorph/strains/castes/drone/healer.dm | 11 +- .../strains/castes/facehugger/watcher.dm | 6 ++ .../castes/hivelord/resin_whisperer.dm | 15 +-- 22 files changed, 227 insertions(+), 271 deletions(-) diff --git a/code/datums/xeno_shields/shield_types/vanguard_shield.dm b/code/datums/xeno_shields/shield_types/vanguard_shield.dm index 5b9eebc04ab8..faf38e466e99 100644 --- a/code/datums/xeno_shields/shield_types/vanguard_shield.dm +++ b/code/datums/xeno_shields/shield_types/vanguard_shield.dm @@ -50,7 +50,6 @@ if (!istype(linked_xeno)) return - if (linked_xeno.mutation_type == PRAETORIAN_VANGUARD) - var/datum/behavior_delegate/praetorian_vanguard/BD = linked_xeno.behavior_delegate - if (istype(BD)) - BD.last_combat_time = world.time + var/datum/behavior_delegate/praetorian_vanguard/BD = linked_xeno.behavior_delegate + if (istype(BD)) + BD.last_combat_time = world.time diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_powers.dm index 4ac166c58c69..e1af5e36a40f 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/crusher/crusher_powers.dm @@ -37,7 +37,7 @@ RegisterSignal(owner, COMSIG_XENO_PRE_CALCULATE_ARMOURED_DAMAGE_PROJECTILE, PROC_REF(check_directional_armor)) var/mob/living/carbon/xenomorph/xeno_owner = owner - if(!istype(xeno_owner) || xeno_owner.mutation_type != CRUSHER_NORMAL) + if(!istype(xeno_owner)) return var/datum/behavior_delegate/crusher_base/crusher_delegate = xeno_owner.behavior_delegate @@ -51,7 +51,7 @@ ..() UnregisterSignal(owner, COMSIG_XENO_PRE_CALCULATE_ARMOURED_DAMAGE_PROJECTILE) var/mob/living/carbon/xenomorph/xeno_owner = owner - if(!istype(xeno_owner) || xeno_owner.mutation_type != CRUSHER_NORMAL) + if(!istype(xeno_owner)) return var/datum/behavior_delegate/crusher_base/crusher_delegate = xeno_owner.behavior_delegate @@ -62,7 +62,7 @@ /datum/action/xeno_action/activable/pounce/crusher_charge/proc/undo_charging_icon() var/mob/living/carbon/xenomorph/xeno_owner = owner - if(!istype(xeno_owner) || xeno_owner.mutation_type != CRUSHER_NORMAL) + if(!istype(xeno_owner)) return var/datum/behavior_delegate/crusher_base/crusher_delegate = xeno_owner.behavior_delegate diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_abilities.dm index 22d5f4b57aa2..d28a4bb67978 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_abilities.dm @@ -20,6 +20,13 @@ ability_primacy = XENO_PRIMARY_ACTION_2 xeno_cooldown = 4 SECONDS + var/base_damage = 30 + var/usable_while_fortified = FALSE + +/datum/action/xeno_action/activable/headbutt/steel_crest + base_damage = 37.5 + usable_while_fortified = TRUE + /datum/action/xeno_action/onclick/tail_sweep name = "Tail Sweep" action_icon_state = "tail_sweep" @@ -41,8 +48,9 @@ /// Extra armor when fortified and facing bullets. var/frontal_armor = 5 - /// Extra armor when steelcrest, fortified, and facing bullets. - var/steelcrest_frontal_armor = 15 + +/datum/action/xeno_action/activable/fortify/steel_crest + frontal_armor = 15 /datum/action/xeno_action/activable/tail_stab/slam name = "Tail Slam" diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_powers.dm index bd01376c9f9d..610dbc4694ae 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_powers.dm @@ -40,7 +40,7 @@ // Defender Headbutt /datum/action/xeno_action/activable/headbutt/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/fendy = owner - if (!istype(fendy)) + if(!istype(fendy)) return if(!isxeno_human(target_atom) || fendy.can_not_harm(target_atom)) @@ -49,13 +49,13 @@ if(!fendy.check_state()) return - if (!action_cooldown_check()) + if(!action_cooldown_check()) return if(!check_and_use_plasma_owner()) return - if(fendy.fortify && !(fendy.mutation_type == DEFENDER_STEELCREST)) + if(fendy.fortify && !usable_while_fortified) to_chat(fendy, SPAN_XENOWARNING("We cannot use headbutt while fortified.")) return @@ -81,11 +81,10 @@ fendy.visible_message(SPAN_XENOWARNING("[fendy] rams [carbone] with its armored crest!"), \ SPAN_XENOWARNING("We ram [carbone] with our armored crest!")) - if(carbone.stat != DEAD && (!(carbone.status_flags & XENO_HOST) || !HAS_TRAIT(carbone, TRAIT_NESTED)) ) - var/h_damage = 30 - (fendy.crest_defense * 10) - if(fendy.mutation_type == DEFENDER_STEELCREST) - h_damage += 7.5 - carbone.apply_armoured_damage(get_xeno_damage_slash(carbone, h_damage), ARMOR_MELEE, BRUTE, "chest", 5) + if(carbone.stat != DEAD && (!(carbone.status_flags & XENO_HOST) || !HAS_TRAIT(carbone, TRAIT_NESTED))) + // -10 damage if their crest is down. + var/damage = base_damage - (fendy.crest_defense * 10) + carbone.apply_armoured_damage(get_xeno_damage_slash(carbone, damage), ARMOR_MELEE, BRUTE, "chest", 5) var/facing = get_dir(fendy, carbone) var/headbutt_distance = 1 + (fendy.crest_defense * 2) + (fendy.fortify * 2) @@ -157,10 +156,6 @@ if (!istype(xeno)) return - if(xeno.crest_defense && xeno.mutation_type == DEFENDER_STEELCREST) - to_chat(src, SPAN_XENOWARNING("We cannot fortify while our crest is already down!")) - return - if(xeno.crest_defense) to_chat(src, SPAN_XENOWARNING("We cannot use fortify with our crest lowered.")) return @@ -205,49 +200,53 @@ if(fortify_state) to_chat(X, SPAN_XENOWARNING("We tuck ourself into a defensive stance.")) - if(X.mutation_type == DEFENDER_STEELCREST) - X.armor_deflection_buff += 10 - X.armor_explosive_buff += 60 - X.ability_speed_modifier += 3 - X.damage_modifier -= XENO_DAMAGE_MOD_SMALL - else - X.armor_deflection_buff += 30 - X.armor_explosive_buff += 60 - ADD_TRAIT(X, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Fortify")) - X.anchored = TRUE - X.small_explosives_stun = FALSE RegisterSignal(owner, COMSIG_XENO_PRE_CALCULATE_ARMOURED_DAMAGE_PROJECTILE, PROC_REF(check_directional_armor)) X.mob_size = MOB_SIZE_IMMOBILE //knockback immune X.mob_flags &= ~SQUEEZE_UNDER_VEHICLES - X.update_icons() X.fortify = TRUE else to_chat(X, SPAN_XENOWARNING("We resume our normal stance.")) REMOVE_TRAIT(X, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Fortify")) X.anchored = FALSE - if(X.mutation_type == DEFENDER_STEELCREST) - X.armor_deflection_buff -= 10 - X.armor_explosive_buff -= 60 - X.ability_speed_modifier -= 3 - X.damage_modifier += XENO_DAMAGE_MOD_SMALL - else - X.armor_deflection_buff -= 30 - X.armor_explosive_buff -= 60 - X.small_explosives_stun = TRUE UnregisterSignal(owner, COMSIG_XENO_PRE_CALCULATE_ARMOURED_DAMAGE_PROJECTILE) X.mob_size = MOB_SIZE_XENO //no longer knockback immune X.mob_flags |= SQUEEZE_UNDER_VEHICLES - X.update_icons() X.fortify = FALSE + apply_modifiers(X, fortify_state) + X.update_icons() + +/datum/action/xeno_action/activable/fortify/proc/apply_modifiers(mob/living/carbon/xenomorph/X, fortify_state) + if(fortify_state) + X.armor_deflection_buff += 30 + X.armor_explosive_buff += 60 + ADD_TRAIT(X, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Fortify")) + X.anchored = TRUE + X.small_explosives_stun = FALSE + else + X.armor_deflection_buff -= 30 + X.armor_explosive_buff -= 60 + X.small_explosives_stun = TRUE + +// Steel crest override +/datum/action/xeno_action/activable/fortify/steel_crest/apply_modifiers(mob/living/carbon/xenomorph/X, fortify_state) + if(fortify_state) + X.armor_deflection_buff += 10 + X.armor_explosive_buff += 60 + X.ability_speed_modifier += 3 + X.damage_modifier -= XENO_DAMAGE_MOD_SMALL + else + X.armor_deflection_buff -= 10 + X.armor_explosive_buff -= 60 + X.ability_speed_modifier -= 3 + X.damage_modifier += XENO_DAMAGE_MOD_SMALL + /datum/action/xeno_action/activable/fortify/proc/check_directional_armor(mob/living/carbon/xenomorph/defendy, list/damagedata) SIGNAL_HANDLER var/projectile_direction = damagedata["direction"] + // If the defender is facing the projectile. if(defendy.dir & REVERSE_DIR(projectile_direction)) - if(defendy.mutation_type == DEFENDER_STEELCREST) - damagedata["armor"] += steelcrest_frontal_armor - else - damagedata["armor"] += frontal_armor + damagedata["armor"] += frontal_armor /datum/action/xeno_action/activable/fortify/proc/death_check() SIGNAL_HANDLER diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm index fd525701b12d..8a829d8d6bc0 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm @@ -6,46 +6,11 @@ plasma_cost = 20 // Config options - distance = 6 knockdown = FALSE knockdown_duration = 2.5 - freeze_self = TRUE freeze_time = 15 can_be_shield_blocked = TRUE -/datum/action/xeno_action/activable/pounce/lurker/additional_effects_always() - var/mob/living/carbon/xenomorph/xeno = owner - if (!istype(xeno)) - return - if (xeno.mutation_type == LURKER_NORMAL) - var/found = FALSE - for (var/mob/living/carbon/human/human in get_turf(xeno)) - if(human.stat == DEAD) - continue - found = TRUE - break - - if (found) - var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invis = get_xeno_action_by_type(xeno, /datum/action/xeno_action/onclick/lurker_invisibility) - if (istype(lurker_invis)) - lurker_invis.invisibility_off() - -/datum/action/xeno_action/activable/pounce/lurker/additional_effects(mob/living/living_mob) - var/mob/living/carbon/xenomorph/xeno = owner - if (!istype(xeno)) - return - - if (xeno.mutation_type == LURKER_NORMAL) - RegisterSignal(xeno, COMSIG_XENO_SLASH_ADDITIONAL_EFFECTS_SELF, PROC_REF(remove_freeze), TRUE) // Suppresses runtime ever we pounce again before slashing - -/datum/action/xeno_action/activable/pounce/lurker/proc/remove_freeze(mob/living/carbon/xenomorph/xeno) - SIGNAL_HANDLER - - var/datum/behavior_delegate/lurker_base/behaviour_del = xeno.behavior_delegate - if (istype(behaviour_del)) - UnregisterSignal(xeno, COMSIG_XENO_SLASH_ADDITIONAL_EFFECTS_SELF) - end_pounce_freeze() - /datum/action/xeno_action/onclick/lurker_invisibility name = "Turn Invisible" action_icon_state = "lurker_invisibility" diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm index 4ec301a17819..29ef331d723f 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm @@ -1,3 +1,35 @@ +/datum/action/xeno_action/activable/pounce/lurker/additional_effects_always() + var/mob/living/carbon/xenomorph/xeno = owner + if(!istype(xeno)) + return + + var/found = FALSE + for(var/mob/living/carbon/human/human in get_turf(xeno)) + if(human.stat == DEAD) + continue + found = TRUE + break + + if(found) + var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invis = get_xeno_action_by_type(xeno, /datum/action/xeno_action/onclick/lurker_invisibility) + if(istype(lurker_invis)) + lurker_invis.invisibility_off() + +/datum/action/xeno_action/activable/pounce/lurker/additional_effects(mob/living/living_mob) + var/mob/living/carbon/xenomorph/xeno = owner + if(!istype(xeno)) + return + + RegisterSignal(xeno, COMSIG_XENO_SLASH_ADDITIONAL_EFFECTS_SELF, PROC_REF(remove_freeze), TRUE) // Suppresses runtime ever we pounce again before slashing + +/datum/action/xeno_action/activable/pounce/lurker/proc/remove_freeze(mob/living/carbon/xenomorph/xeno) + SIGNAL_HANDLER + + var/datum/behavior_delegate/lurker_base/behaviour_del = xeno.behavior_delegate + if(istype(behaviour_del)) + UnregisterSignal(xeno, COMSIG_XENO_SLASH_ADDITIONAL_EFFECTS_SELF) + end_pounce_freeze() + /datum/action/xeno_action/onclick/lurker_invisibility/use_ability(atom/targeted_atom) var/mob/living/carbon/xenomorph/xeno = owner @@ -16,9 +48,8 @@ xeno.speed_modifier -= speed_buff xeno.recalculate_speed() - if (xeno.mutation_type == LURKER_NORMAL) - var/datum/behavior_delegate/lurker_base/behavior = xeno.behavior_delegate - behavior.on_invisibility() + var/datum/behavior_delegate/lurker_base/behavior = xeno.behavior_delegate + behavior.on_invisibility() // if we go off early, this also works fine. invis_timer_id = addtimer(CALLBACK(src, PROC_REF(invisibility_off)), duration, TIMER_STOPPABLE) @@ -45,10 +76,9 @@ xeno.speed_modifier += speed_buff xeno.recalculate_speed() - if (xeno.mutation_type == LURKER_NORMAL) - var/datum/behavior_delegate/lurker_base/behavior = xeno.behavior_delegate - if (istype(behavior)) - behavior.on_invisibility_off() + var/datum/behavior_delegate/lurker_base/behavior = xeno.behavior_delegate + if (istype(behavior)) + behavior.on_invisibility_off() /datum/action/xeno_action/onclick/lurker_invisibility/ability_cooldown_over() to_chat(owner, SPAN_XENOHIGHDANGER("We are ready to use our invisibility again!")) @@ -66,9 +96,6 @@ if (!check_and_use_plasma_owner()) return - if (xeno.mutation_type != LURKER_NORMAL) - return - var/datum/behavior_delegate/lurker_base/behavior = xeno.behavior_delegate if (istype(behavior)) behavior.next_slash_buffed = TRUE diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm index 2eaf332755dc..b0f5adcfdde3 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm @@ -70,10 +70,9 @@ playsound(current_mob, 'sound/weapons/alien_tail_attack.ogg', 30, TRUE) if (target_mobs.len >= shield_regen_threshold) - if (source_xeno.mutation_type == PRAETORIAN_VANGUARD) - var/datum/behavior_delegate/praetorian_vanguard/BD = source_xeno.behavior_delegate - if (istype(BD)) - BD.regen_shield() + var/datum/behavior_delegate/praetorian_vanguard/BD = source_xeno.behavior_delegate + if (istype(BD)) + BD.regen_shield() apply_cooldown() return ..() @@ -135,10 +134,9 @@ playsound(get_turf(H), "alien_claw_flesh", 30, 1) if (target_mobs.len >= shield_regen_threshold) - if (X.mutation_type == PRAETORIAN_VANGUARD) - var/datum/behavior_delegate/praetorian_vanguard/BD = X.behavior_delegate - if (istype(BD)) - BD.regen_shield() + var/datum/behavior_delegate/praetorian_vanguard/BD = X.behavior_delegate + if (istype(BD)) + BD.regen_shield() /datum/action/xeno_action/activable/cleave/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/vanguard_user = owner @@ -545,16 +543,12 @@ if (!check_and_use_plasma_owner()) return - var/buffed = FALSE apply_cooldown() - if (dancer_user.mutation_type == PRAETORIAN_DANCER) - var/found = FALSE - for (var/datum/effects/dancer_tag/dancer_tag_effect in target_carbon.effects_list) - found = TRUE - qdel(dancer_tag_effect) - break - - buffed = found + var/buffed = FALSE + for (var/datum/effects/dancer_tag/dancer_tag_effect in target_carbon.effects_list) + buffed = TRUE + qdel(dancer_tag_effect) + break if(ishuman(target_carbon)) var/mob/living/carbon/human/Hu = target_carbon @@ -601,9 +595,6 @@ if (!check_and_use_plasma_owner()) return - if (xeno.mutation_type != PRAETORIAN_DANCER) - return - var/datum/behavior_delegate/praetorian_dancer/behavior = xeno.behavior_delegate if (!istype(behavior)) return @@ -626,9 +617,6 @@ if (!istype(xeno)) return - if (xeno.mutation_type != PRAETORIAN_DANCER) - return - var/datum/behavior_delegate/praetorian_dancer/behavior = xeno.behavior_delegate if (!istype(behavior)) return @@ -806,17 +794,16 @@ var/bonus_shield = 0 - if (X.mutation_type == PRAETORIAN_WARDEN) - var/datum/behavior_delegate/praetorian_warden/BD = X.behavior_delegate - if (!istype(BD)) - return + var/datum/behavior_delegate/praetorian_warden/BD = X.behavior_delegate + if (!istype(BD)) + return - if (!BD.use_internal_hp_ability(shield_cost)) - return + if (!BD.use_internal_hp_ability(shield_cost)) + return - bonus_shield = BD.internal_hitpoints*0.5 - if (!BD.use_internal_hp_ability(bonus_shield)) - bonus_shield = 0 + bonus_shield = BD.internal_hitpoints*0.5 + if (!BD.use_internal_hp_ability(bonus_shield)) + bonus_shield = 0 var/total_shield_amount = shield_amount + bonus_shield @@ -841,7 +828,7 @@ if (!X.Adjacent(A)) to_chat(X, SPAN_XENODANGER("We must be within touching distance of [targetXeno]!")) return - if (targetXeno.mutation_type == PRAETORIAN_WARDEN) + if(istype(targetXeno.strain, /datum/xeno_strain/warden)) to_chat(X, SPAN_XENODANGER("We cannot heal a sister of the same strain!")) return if (SEND_SIGNAL(targetXeno, COMSIG_XENO_PRE_HEAL) & COMPONENT_CANCEL_XENO_HEAL) @@ -849,18 +836,16 @@ return var/bonus_heal = 0 + var/datum/behavior_delegate/praetorian_warden/BD = X.behavior_delegate + if (!istype(BD)) + return - if (X.mutation_type == PRAETORIAN_WARDEN) - var/datum/behavior_delegate/praetorian_warden/BD = X.behavior_delegate - if (!istype(BD)) - return - - if (!BD.use_internal_hp_ability(heal_cost)) - return + if (!BD.use_internal_hp_ability(heal_cost)) + return - bonus_heal = BD.internal_hitpoints*0.5 - if (!BD.use_internal_hp_ability(bonus_heal)) - bonus_heal = 0 + bonus_heal = BD.internal_hitpoints*0.5 + if (!BD.use_internal_hp_ability(bonus_heal)) + bonus_heal = 0 to_chat(X, SPAN_XENODANGER("We heal [targetXeno]!")) to_chat(targetXeno, SPAN_XENOHIGHDANGER("We are healed by [X]!")) @@ -876,13 +861,12 @@ to_chat(X, SPAN_XENOHIGHDANGER("We cannot rejuvenate targets through overwatch!")) return - if (X.mutation_type == PRAETORIAN_WARDEN) - var/datum/behavior_delegate/praetorian_warden/BD = X.behavior_delegate - if (!istype(BD)) - return + var/datum/behavior_delegate/praetorian_warden/BD = X.behavior_delegate + if (!istype(BD)) + return - if (!BD.use_internal_hp_ability(debuff_cost)) - return + if (!BD.use_internal_hp_ability(debuff_cost)) + return to_chat(X, SPAN_XENODANGER("We rejuvenate [targetXeno]!")) to_chat(targetXeno, SPAN_XENOHIGHDANGER("We are rejuvenated by [X]!")) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_abilities.dm index d245449fa2cf..307f28261d28 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_abilities.dm @@ -62,6 +62,10 @@ . = ..() SSticker.OnRoundstart(CALLBACK(src, PROC_REF(apply_queen_build_boost))) +// queenos don't need weeds under them to build +/datum/action/xeno_action/activable/secrete_resin/remote/queen/can_remote_build() + return TRUE + /datum/action/xeno_action/activable/secrete_resin/remote/queen/proc/apply_queen_build_boost() var/boost_duration = 30 MINUTES // In the event secrete_resin is given after round start diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/ravager/ravager_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/ravager/ravager_powers.dm index daad0362e91e..8fe101a08dfa 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/ravager/ravager_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/ravager/ravager_powers.dm @@ -6,9 +6,6 @@ if(!xeno.check_state()) return - if(xeno.mutation_type != RAVAGER_NORMAL) - return - if(!action_cooldown_check()) return @@ -122,8 +119,6 @@ var/mob/living/carbon/human/human = living var/mob/living/carbon/xenomorph/xeno = owner - if(xeno.mutation_type != RAVAGER_NORMAL) - return var/datum/behavior_delegate/ravager_base/behavior = xeno.behavior_delegate if(behavior.empower_targets < behavior.super_empower_threshold) return @@ -146,8 +141,6 @@ // Determine whether or not we should daze here var/should_sslow = FALSE - if(ravager_user.mutation_type != RAVAGER_NORMAL) - return var/datum/behavior_delegate/ravager_base/ravager_delegate = ravager_user.behavior_delegate if(ravager_delegate.empower_targets >= ravager_delegate.super_empower_threshold) should_sslow = TRUE @@ -302,17 +295,14 @@ if (carbon.stat == DEAD) return - // All strain-specific behavior - if (xeno.mutation_type == RAVAGER_BERSERKER) - var/datum/behavior_delegate/ravager_berserker/behavior = xeno.behavior_delegate - - if (behavior.rage >= 2) - behavior.decrement_rage() - heal_amount += additional_healing_enraged - else - to_chat(xeno, SPAN_XENOWARNING("Our rejuvenation was weaker without rage!")) - debilitate = FALSE - fling_distance-- + var/datum/behavior_delegate/ravager_berserker/behavior = xeno.behavior_delegate + if (behavior.rage >= 2) + behavior.decrement_rage() + heal_amount += additional_healing_enraged + else + to_chat(xeno, SPAN_XENOWARNING("Our rejuvenation was weaker without rage!")) + debilitate = FALSE + fling_distance-- // Damage var/obj/limb/head/head = carbon.get_limb("head") @@ -361,17 +351,16 @@ var/max_lifesteal = 250 var/lifesteal_range = 1 - if (xeno.mutation_type == RAVAGER_BERSERKER) - var/datum/behavior_delegate/ravager_berserker/behavior = xeno.behavior_delegate - if (behavior.rage == 0) - to_chat(xeno, SPAN_XENODANGER("We cannot eviscerate when we have 0 rage!")) - return - damage = damage_at_rage_levels[clamp(behavior.rage, 1, behavior.max_rage)] - range = range_at_rage_levels[clamp(behavior.rage, 1, behavior.max_rage)] - windup_reduction = windup_reduction_at_rage_levels[clamp(behavior.rage, 1, behavior.max_rage)] - behavior.decrement_rage(behavior.rage) + var/datum/behavior_delegate/ravager_berserker/behavior = xeno.behavior_delegate + if (behavior.rage == 0) + to_chat(xeno, SPAN_XENODANGER("We cannot eviscerate when we have 0 rage!")) + return + damage = damage_at_rage_levels[clamp(behavior.rage, 1, behavior.max_rage)] + range = range_at_rage_levels[clamp(behavior.rage, 1, behavior.max_rage)] + windup_reduction = windup_reduction_at_rage_levels[clamp(behavior.rage, 1, behavior.max_rage)] + behavior.decrement_rage(behavior.rage) - apply_cooldown() + apply_cooldown() if (range > 1) xeno.visible_message(SPAN_XENOHIGHDANGER("[xeno] begins digging in for a massive strike!"), SPAN_XENOHIGHDANGER("We begin digging in for a massive strike!")) @@ -439,12 +428,11 @@ if (!xeno.check_state()) return - if (xeno.mutation_type == RAVAGER_HEDGEHOG) - var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate - if (!behavior.check_shards(shard_cost)) - to_chat(xeno, SPAN_DANGER("Not enough shards! We need [shard_cost - behavior.shards] more!")) - return - behavior.use_shards(shard_cost) + var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate + if (!behavior.check_shards(shard_cost)) + to_chat(xeno, SPAN_DANGER("Not enough shards! We need [shard_cost - behavior.shards] more!")) + return + behavior.use_shards(shard_cost) xeno.visible_message(SPAN_XENODANGER("[xeno] ruffles its bone-shard quills, forming a defensive shell!"), SPAN_XENODANGER("We ruffle our bone-shard quills, forming a defensive shell!")) @@ -468,10 +456,8 @@ return FALSE else if (cooldown_timer_id == TIMER_ID_NULL) var/mob/living/carbon/xenomorph/xeno = owner - if (xeno.mutation_type == RAVAGER_HEDGEHOG) - var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate - return behavior.check_shards(shard_cost) - return TRUE + var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate + return behavior.check_shards(shard_cost) return FALSE /datum/action/xeno_action/onclick/spike_shield/proc/remove_shield() @@ -502,12 +488,11 @@ if(!affected_atom || affected_atom.layer >= FLY_LAYER || !isturf(xeno.loc) || !xeno.check_state()) return - if (xeno.mutation_type == RAVAGER_HEDGEHOG) - var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate - if (!behavior.check_shards(shard_cost)) - to_chat(xeno, SPAN_DANGER("Not enough shards! We need [shard_cost - behavior.shards] more!")) - return - behavior.use_shards(shard_cost) + var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate + if (!behavior.check_shards(shard_cost)) + to_chat(xeno, SPAN_DANGER("Not enough shards! We need [shard_cost - behavior.shards] more!")) + return + behavior.use_shards(shard_cost) xeno.visible_message(SPAN_XENOWARNING("[xeno] fires their spikes at [affected_atom]!"), SPAN_XENOWARNING("We fire our spikes at [affected_atom]!")) @@ -531,11 +516,8 @@ var/mob/living/carbon/xenomorph/xeno = owner if(!istype(xeno)) return FALSE - if (xeno.mutation_type == RAVAGER_HEDGEHOG) - var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate - return behavior.check_shards(shard_cost) - - return TRUE + var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate + return behavior.check_shards(shard_cost) else return FALSE @@ -548,13 +530,12 @@ if (!xeno.check_state()) return - if (xeno.mutation_type == RAVAGER_HEDGEHOG) - var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate - if (!behavior.check_shards(shard_cost)) - to_chat(xeno, SPAN_DANGER("Not enough shards! We need [shard_cost - behavior.shards] more!")) - return - behavior.use_shards(shard_cost) - behavior.lock_shards() + var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate + if (!behavior.check_shards(shard_cost)) + to_chat(xeno, SPAN_DANGER("Not enough shards! We need [shard_cost - behavior.shards] more!")) + return + behavior.use_shards(shard_cost) + behavior.lock_shards() xeno.visible_message(SPAN_XENOWARNING("[xeno] sheds their spikes, firing them in all directions!"), SPAN_XENOWARNING("We shed our spikes, firing them in all directions!!")) xeno.spin_circle() @@ -567,10 +548,7 @@ /datum/action/xeno_action/onclick/spike_shed/action_cooldown_check() if (cooldown_timer_id == TIMER_ID_NULL) var/mob/living/carbon/xenomorph/xeno = owner - if (xeno.mutation_type == RAVAGER_HEDGEHOG) - var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate - return behavior.check_shards(shard_cost) - - return TRUE + var/datum/behavior_delegate/ravager_hedgehog/behavior = xeno.behavior_delegate + return behavior.check_shards(shard_cost) else return FALSE diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/runner/runner_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/runner/runner_powers.dm index b907a382dda1..f5e090bc7e4b 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/runner/runner_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/runner/runner_powers.dm @@ -45,7 +45,7 @@ return ..() /mob/living/carbon/xenomorph/runner/corrosive_acid(atom/affected_atom, acid_type, plasma_cost) - if (mutation_type != RUNNER_ACIDER) + if(!istype(strain, /datum/xeno_strain/acider)) return ..() if(!affected_atom.Adjacent(src)) if(istype(affected_atom,/obj/item/explosive/plastic)) @@ -159,9 +159,6 @@ if(!action_cooldown_check()) return - if(xeno.mutation_type != RUNNER_ACIDER) - return - var/datum/behavior_delegate/runner_acider/behavior_delegate = xeno.behavior_delegate if(!istype(behavior_delegate)) return diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/sentinel/sentinel_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/sentinel/sentinel_powers.dm index 1ddec771d075..1ed8863c231a 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/sentinel/sentinel_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/sentinel/sentinel_powers.dm @@ -35,9 +35,6 @@ if(!xeno.check_state()) return - if(xeno.mutation_type != SENTINEL_NORMAL) - return - if(!action_cooldown_check()) to_chat(src, SPAN_WARNING("We must wait for your spit glands to refill.")) return @@ -77,9 +74,6 @@ if (!check_and_use_plasma_owner()) return - if (xeno.mutation_type != SENTINEL_NORMAL) - return - var/datum/behavior_delegate/sentinel_base/behavior = xeno.behavior_delegate if (istype(behavior)) behavior.next_slash_buffed = TRUE diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm index c800f129e3ff..9c8478a93eb2 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm @@ -78,6 +78,8 @@ /mob/living/carbon/xenomorph/proc/set_hugger_reserve_for_morpher, ) + behavior_delegate = /datum/behavior_delegate/carrier_base + icon_xenonid = 'icons/mob/xenonids/carrier.dmi' weed_food_icon = 'icons/mob/xenos/weeds_64x64.dmi' @@ -96,18 +98,9 @@ var/eggs_max = 0 var/laid_egg = 0 -/mob/living/carbon/xenomorph/carrier/update_icons() - . = ..() - if (mutation_type == CARRIER_NORMAL) - update_hugger_overlays() - if (mutation_type == CARRIER_EGGSAC) - update_eggsac_overlays() - /mob/living/carbon/xenomorph/carrier/proc/update_hugger_overlays() if(!hugger_overlays_icon) return - if(mutation_type != CARRIER_NORMAL) - return overlays -= hugger_overlays_icon hugger_overlays_icon.overlays.Cut() @@ -147,8 +140,6 @@ /mob/living/carbon/xenomorph/carrier/proc/update_eggsac_overlays() if(!eggsac_overlays_icon) return - if(mutation_type != CARRIER_EGGSAC) - return overlays -= eggsac_overlays_icon eggsac_overlays_icon.overlays.Cut() @@ -185,9 +176,6 @@ . = ..(cause, gibbed) if(.) var/chance = 75 //75% to drop an egg or hugger. - if(mutation_type == CARRIER_EGGSAC) - visible_message(SPAN_XENOWARNING("[src] throes as its eggsac bursts into a mess of acid!")) - playsound(src.loc, 'sound/effects/alien_egg_burst.ogg', 25, 1) if(huggers_cur) //Hugger explosion, like an egg morpher @@ -403,3 +391,10 @@ return GLOB.hive_datum[hivenumber].spawn_as_hugger(user, src) huggers_cur-- + +/datum/behavior_delegate/carrier_base + name = "Base Carrier Behavior Delegate" + +/datum/behavior_delegate/carrier_base/on_update_icons() + var/mob/living/carbon/xenomorph/carrier/bound_carrier = bound_xeno + bound_carrier.update_hugger_overlays() diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm index f7d986570f9f..38b1e5816ffe 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm @@ -280,5 +280,5 @@ /datum/behavior_delegate/crusher_base/on_update_icons() if(bound_xeno.throwing || is_charging) //Let it build up a bit so we're not changing icons every single turf - bound_xeno.icon_state = "[bound_xeno.mutation_icon_state || bound_xeno.mutation_type] Crusher Charging" + bound_xeno.icon_state = "[bound_xeno.get_strain_icon()] Crusher Charging" return TRUE diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm b/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm index 23ba08e294ba..a63bafb5d2b0 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm @@ -88,8 +88,8 @@ return if(bound_xeno.fortify && bound_xeno.health > 0) - bound_xeno.icon_state = "[bound_xeno.mutation_icon_state || bound_xeno.mutation_type] Defender Fortify" + bound_xeno.icon_state = "[bound_xeno.get_strain_icon()] Defender Fortify" return TRUE if(bound_xeno.crest_defense && bound_xeno.health > 0) - bound_xeno.icon_state = "[bound_xeno.mutation_icon_state || bound_xeno.mutation_type] Defender Crest" + bound_xeno.icon_state = "[bound_xeno.get_strain_icon()] Defender Crest" return TRUE diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm b/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm index 83c61358e49d..b9c5b140047e 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm @@ -58,6 +58,8 @@ /mob/living/carbon/xenomorph/proc/vent_crawl, ) + behavior_delegate = /datum/behavior_delegate/facehugger_base + icon_xeno = 'icons/mob/xenos/facehugger.dmi' icon_xenonid = 'icons/mob/xenonids/facehugger.dmi' @@ -75,34 +77,16 @@ if(stat == DEAD) return ..() - if(body_position == STANDING_UP && !(mutation_type == FACEHUGGER_WATCHER) && !(locate(/obj/effect/alien/weeds) in get_turf(src))) - adjustBruteLoss(1) - return ..() - if(!client && !aghosted && away_timer > XENO_FACEHUGGER_LEAVE_TIMER) // Become a npc once again new /obj/item/clothing/mask/facehugger(loc, hivenumber) qdel(src) return ..() -/mob/living/carbon/xenomorph/facehugger/update_icons(is_pouncing) - if(!caste) - return - - if(stat == DEAD) - icon_state = "[mutation_type] [caste.caste_type] Dead" - else if(body_position == LYING_DOWN) - if(!HAS_TRAIT(src, TRAIT_INCAPACITATED) && !HAS_TRAIT(src, TRAIT_FLOORED)) - icon_state = "[mutation_type] [caste.caste_type] Sleeping" - else - icon_state = "[mutation_type] [caste.caste_type] Knocked Down" - else if(is_pouncing) - icon_state = "[mutation_type] [caste.caste_type] Thrown" - else - icon_state = "[mutation_type] [caste.caste_type] Running" - - update_fire() //the fire overlay depends on the xeno's stance, so we must update it. - update_wounds() +/mob/living/carbon/xenomorph/facehugger/update_icons() + . = ..() + if(throwing) + icon_state = "[get_strain_icon()] [caste.caste_type] Thrown" /mob/living/carbon/xenomorph/facehugger/start_pulling(atom/movable/AM) return @@ -235,3 +219,10 @@ . += "Lifetime Hugs: [total_facehugs] / [next_facehug_goal]" else . += "Lifetime Hugs: [total_facehugs]" + +/datum/behavior_delegate/facehugger_base + name = "Base Facehugger Behavior Delegate" + +/datum/behavior_delegate/facehugger_base/on_life() + if(bound_xeno.body_position == STANDING_UP && !(locate(/obj/effect/alien/weeds) in get_turf(src))) + bound_xeno.adjustBruteLoss(1) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm b/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm index c821fbc49208..ee4157a67d84 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm @@ -121,10 +121,3 @@ toggle_resin_walker() to_chat(bound_xeno, SPAN_WARNING("You feel dizzy as the world slows down.")) bound_xeno.recalculate_move_delay = TRUE - -/// This check mainly exists because of the new resin node ability for resin whisperer. -/mob/living/carbon/xenomorph/hivelord/proc/on_weeds() - var/turf/turf = get_turf(src) - if(locate(/obj/effect/alien/weeds) in turf) - return TRUE - return FALSE diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm index db2a9b4a38de..1957487bf778 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm @@ -517,7 +517,7 @@ overwatch(observed_xeno, TRUE) if(ovipositor && !is_mob_incapacitated(TRUE)) - egg_amount += 0.07 * mutators.egg_laying_multiplier //one egg approximately every 30 seconds + egg_amount += 0.07 //one egg approximately every 30 seconds if(egg_amount >= 1) if(isturf(loc)) var/turf/T = loc @@ -950,7 +950,7 @@ var/mob/living/carbon/xenomorph/queen/Queen = bound_xeno if(Queen.ovipositor) Queen.icon = Queen.queen_ovipositor_icon - Queen.icon_state = "[Queen.mutation_icon_state || Queen.mutation_type] Queen Ovipositor" + Queen.icon_state = "Normal Queen Ovipositor" return TRUE // Switch icon back and then let normal icon behavior happen diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm index c2229122a99a..f1ba672d63e5 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm @@ -50,6 +50,10 @@ . = list() . += "Eggs sustained: [length(eggs_sustained)] / [egg_sustain_cap]" +/datum/behavior_delegate/carrier_eggsac/on_update_icons() + var/mob/living/carbon/xenomorph/carrier/bound_carrier = bound_xeno + bound_carrier.update_eggsac_overlays() + /datum/behavior_delegate/carrier_eggsac/on_life() if(length(eggs_sustained) > egg_sustain_cap) var/obj/effect/alien/egg/carrier_egg/my_egg = eggs_sustained[1] @@ -65,6 +69,10 @@ else my_egg.check_decay() +/datum/behavior_delegate/carrier_eggsac/handle_death(mob/M) + M.visible_message(SPAN_XENOWARNING("[M] throes as its eggsac bursts into a mess of acid!")) + playsound(M.loc, 'sound/effects/alien_egg_burst.ogg', 25, TRUE) + ///Remove owner of egg /datum/behavior_delegate/carrier_eggsac/proc/remove_egg_owner(obj/effect/alien/egg/carrier_egg/egg) if(!egg.owner || egg.owner != bound_xeno) diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm index 5f1f85b5b1bd..891c1ce08e1e 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm @@ -5,9 +5,13 @@ xeno_icon_state = DEFENDER_STEELCREST actions_to_remove = list( + /datum/action/xeno_action/activable/headbutt, + /datum/action/xeno_action/activable/fortify, /datum/action/xeno_action/onclick/tail_sweep, ) actions_to_add = list( + /datum/action/xeno_action/activable/headbutt/steel_crest, + /datum/action/xeno_action/activable/fortify/steel_crest, /datum/action/xeno_action/onclick/soak, ) diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm index 3f698345193e..bca247899428 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm @@ -111,13 +111,14 @@ to_chat(src, SPAN_XENOWARNING("[target_xeno] is already at max health!")) return -///Tiny xenos (Larva and Facehuggers), don't need as much health so don't cost as much. - if(target_xeno.mob_size == 0) + //Tiny xenos (Larva and Facehuggers), don't need as much health so don't cost as much. + if(target_xeno.mob_size == MOB_SIZE_SMALL) amount = amount * 0.15 damage_taken_mod = 1 -//Forces an equivalent exchange of health between healers so they do not spam heal each other to full health. - if(target_xeno.mutation_type == DRONE_HEALER) + //Forces an equivalent exchange of health between healers so they do not spam heal each other to full health. + var/target_is_healer = istype(target_xeno.strain, /datum/xeno_strain/healer) + if(target_is_healer) damage_taken_mod = 1 face_atom(target_xeno) @@ -132,7 +133,7 @@ playsound(src, "alien_drool", 25) var/datum/behavior_delegate/drone_healer/healer_delegate = behavior_delegate healer_delegate.salve_applied_recently = TRUE - if(target_xeno.mutation_type != DRONE_HEALER && !isfacehugger(target_xeno)) // no cheap grinding + if(!target_is_healer && !isfacehugger(target_xeno)) // no cheap grinding healer_delegate.modify_transferred(amount * damage_taken_mod) update_icons() addtimer(CALLBACK(healer_delegate, /datum/behavior_delegate/drone_healer/proc/un_salve), 10 SECONDS, TIMER_OVERRIDE|TIMER_UNIQUE) diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/facehugger/watcher.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/facehugger/watcher.dm index 1b7e09a584ef..c5d9986c7b6a 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/facehugger/watcher.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/facehugger/watcher.dm @@ -10,9 +10,15 @@ /datum/action/xeno_action/onclick/toggle_long_range/runner, ) + behavior_delegate_type = /datum/behavior_delegate/facehugger_watcher + /datum/xeno_strain/watcher/apply_strain(mob/living/carbon/xenomorph/facehugger/huggy) . = ..() huggy.viewsize = 10 huggy.layer = initial(huggy.layer) return TRUE + +// This has no special effects, it's just here to skip `/datum/behavior_delegate/facehugger_base/on_life()`. +/datum/behavior_delegate/facehugger_watcher + name = "Watcher Facehugger Behavior Delegate" diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm index a2013470df8a..2b3e790ab21b 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm @@ -58,12 +58,9 @@ action_type = XENO_ACTION_CLICK /datum/action/xeno_action/activable/secrete_resin/remote/use_ability(atom/target_atom, mods) - var/mob/living/carbon/xenomorph/xeno_owner = owner - if(xeno_owner.mutation_type == HIVELORD_RESIN_WHISPERER) - var/mob/living/carbon/xenomorph/hivelord/hivelord_mob = owner - if(!hivelord_mob.on_weeds()) // There is a chance that queen can't place down buildings in ovi build view so we place the rein whisperer check here. - to_chat(owner, SPAN_XENONOTICE("We must be standing on weeds to establish a connection to the resin.")) - return + if(!can_remote_build()) + to_chat(owner, SPAN_XENONOTICE("We must be standing on weeds to establish a connection to the resin.")) + return if(!action_cooldown_check()) return @@ -105,6 +102,12 @@ playsound(target_turf, "alien_resin_build", 25) return TRUE +// By default, the xeno must be on a weed tile in order to build from a distance. +/datum/action/xeno_action/activable/secrete_resin/remote/proc/can_remote_build() + if(!locate(/obj/effect/alien/weeds) in get_turf(owner)) + return FALSE + return TRUE + /datum/action/xeno_action/verb/verb_coerce_resin() set category = "Alien" set name = "Coerce Resin" From 874d730b146a75688327f526bb8ffde1618aea44 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:25:45 +0000 Subject: [PATCH 08/17] xeno_strain streamlining --- code/_globalvars/global_lists.dm | 3 - .../carbon/xenomorph/strains/xeno_strain.dm | 74 ++++++++++--------- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/code/_globalvars/global_lists.dm b/code/_globalvars/global_lists.dm index 00a3bc256e6a..4ea67bab3905 100644 --- a/code/_globalvars/global_lists.dm +++ b/code/_globalvars/global_lists.dm @@ -163,9 +163,6 @@ GLOBAL_LIST_INIT(language_keys, setup_language_keys()) //table of say codes for GLOBAL_REFERENCE_LIST_INDEXED(origins, /datum/origin, name) GLOBAL_LIST_INIT(player_origins, USCM_ORIGINS) -//Xeno strains -GLOBAL_SUBTYPE_PATHS_LIST_INDEXED(xeno_strain_list, /datum/xeno_strain, name) - //Xeno hives GLOBAL_LIST_INIT_TYPED(hive_datum, /datum/hive_status, list( XENO_HIVE_NORMAL = new /datum/hive_status(), diff --git a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm index 57ba97050075..0098f61b1e29 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm @@ -16,79 +16,81 @@ /// Typepath of the [/datum/behavior_delegate] to add. var/behavior_delegate_type -/// TODO: documentation -/// Returns a bool indicating if the strain was successfully applied. +/** + * Add this strain to `xeno`, replacing their actions and behavior holder. + * + * Returns a bool indicating if the strain was successfully applied. + */ /datum/xeno_strain/proc/apply_strain(mob/living/carbon/xenomorph/xeno) SHOULD_CALL_PARENT(TRUE) xeno.strain = src - update_actions(xeno) register_signals(xeno) - apply_behavior_holder(xeno) - update_mob(xeno) + // Update the xeno's actions. + for(var/action_path in actions_to_remove) + remove_action(xeno, action_path) + for(var/action_path in actions_to_add) + give_action(xeno, action_path) + + // Update the xeno's behavior delegate. + if(behavior_delegate_type) + if(xeno.behavior_delegate) + qdel(xeno.behavior_delegate) + xeno.behavior_delegate = new behavior_delegate_type() + xeno.behavior_delegate.bound_xeno = xeno + xeno.behavior_delegate.add_to_xeno() + + xeno.update_icons() xeno.hive.hive_ui.update_xeno_info() + // Give them all the info about the strain. to_chat(xeno, SPAN_XENOANNOUNCE(description)) if(flavor_description) to_chat(xeno, SPAN_XENOLEADER(flavor_description)) return TRUE -/// Update the `xeno`'s action buttons based on [/datum/xeno_strain/var/actions_to_remove] and [/datum/xeno_strain/var/actions_to_add]. -/datum/xeno_strain/proc/update_actions(mob/living/carbon/xenomorph/xeno) - for(var/action_path in actions_to_remove) - remove_action(xeno, action_path) - for(var/action_path in actions_to_add) - give_action(xeno, action_path) - /// TODO: documentation /datum/xeno_strain/proc/register_signals(mob/living/carbon/xenomorph/xeno) return -/// TODO: documentation -/datum/xeno_strain/proc/apply_behavior_holder(mob/living/carbon/xenomorph/xeno) - if(!behavior_delegate_type) - // don't need to do anything - return - - if(xeno.behavior_delegate) - qdel(xeno.behavior_delegate) - xeno.behavior_delegate = new behavior_delegate_type() - xeno.behavior_delegate.bound_xeno = xeno - xeno.behavior_delegate.add_to_xeno() - -/// TODO: documentation -/datum/xeno_strain/proc/update_mob(mob/living/carbon/xenomorph/xeno) - xeno.xeno_jitter(1.5 SECONDS) - xeno.update_icons() - /mob/living/carbon/xenomorph/verb/purchase_strain() set name = "Purchase Strain" set desc = "Purchase a strain for yourself" set category = "Alien" + // Firstly, make sure the xeno is actually able to take a strain. if(!can_take_strain()) return - var/strain_choice = tgui_input_list(usr, "Which strain would you like to take?", "Choose Strain", GLOB.xeno_strain_list, theme = "hive_status") - var/datum/xeno_strain/strain_path = GLOB.xeno_strain_list[strain_choice] - // Check again after the user has picked one. + // Make an assoc list of {name: typepath} from the strains available to the xeno's caste. + var/list/strain_list = list() + for(var/datum/xeno_strain/strain_type as anything in caste.available_strains) + strain_list[initial(strain_type.name)] = strain_type + + // Ask the user which strain they want. + var/strain_choice = tgui_input_list(usr, "Which strain would you like to take?", "Choose Strain", strain_list, theme = "hive_status") + var/datum/xeno_strain/chosen_strain = strain_list[strain_choice] + + // Check again after the user picks one, in case anything changed. if(!can_take_strain()) return // Show the user the strain's description, and double check that they want it. - if(alert(usr, "[initial(strain_path.description)]\n\nConfirm mutation?", "Choose Strain", "Yes", "No") != "Yes") + if(alert(usr, "[initial(chosen_strain.description)]\n\nConfirm mutation?", "Choose Strain", "Yes", "No") != "Yes") return // One more time after they confirm. if(!can_take_strain()) return - var/datum/xeno_strain/strain_instance = new strain_path() - // Apply the strain to the xeno. + // Create the strain datum and apply it to the xeno. + var/datum/xeno_strain/strain_instance = new chosen_strain() if(strain_instance.apply_strain(src)) - // And log it if it was successful. + xeno_jitter(1.5 SECONDS) + // If it applied successfully, add it to the logs. log_strain("[name] purchased strain '[strain_instance.type]'") +/// Is this xeno currently able to take a strain? /mob/living/carbon/xenomorph/proc/can_take_strain() if(!length(caste.available_strains) || !check_state(TRUE)) return FALSE From d566cfe16ba1fdd5525bbc0064dc096550a25b8f Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:43:20 +0000 Subject: [PATCH 09/17] eg I don't like using `istype()`, but I think one's needed here. (woo final error fixed!!) --- code/modules/mob/living/carbon/xenomorph/egg_item.dm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/egg_item.dm b/code/modules/mob/living/carbon/xenomorph/egg_item.dm index 1bc41b881129..59e2b964d848 100644 --- a/code/modules/mob/living/carbon/xenomorph/egg_item.dm +++ b/code/modules/mob/living/carbon/xenomorph/egg_item.dm @@ -104,12 +104,15 @@ if(weed.weed_strength >= WEED_LEVEL_WEAK && weed.linked_hive.hivenumber == hivenumber) //check for ANY weeds any_weeds = weed + // If the user isn't an eggsac carrier, they're only able to plant eggs on hive weeds. + var/needs_hive_weeds = !istype(user.strain, /datum/xeno_strain/eggsac) + var/datum/hive_status/hive = GLOB.hive_datum[hivenumber] if(!any_weeds && !hive_weeds) //you need at least some weeds to plant on. to_chat(user, SPAN_XENOWARNING("[src] must be planted on [lowertext(hive.prefix)]weeds.")) return - if(!hive_weeds && user.mutation_type != CARRIER_EGGSAC) + if(!hive_weeds && needs_hive_weeds) to_chat(user, SPAN_XENOWARNING("[src] can only be planted on [lowertext(hive.prefix)]hive weeds.")) return @@ -138,7 +141,7 @@ return for(var/obj/effect/alien/weeds/weed in T) - if(weed.weed_strength >= WEED_LEVEL_HIVE || user.mutation_type == CARRIER_EGGSAC) + if(weed.weed_strength >= WEED_LEVEL_HIVE || !needs_hive_weeds) user.use_plasma(30) var/obj/effect/alien/egg/newegg if(weed.weed_strength >= WEED_LEVEL_HIVE) From f4a153aca7a129e49041dc3c751c1c10249948e8 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Tue, 23 Jan 2024 23:19:25 +0000 Subject: [PATCH 10/17] Splitting off `apply_strain()` Mainly just so that `update_icons()` can be called after it. --- .../strains/castes/boiler/trapper.dm | 2 -- .../strains/castes/carrier/eggsac.dm | 2 -- .../strains/castes/crusher/charger.dm | 3 --- .../strains/castes/defender/steel_crest.dm | 2 -- .../strains/castes/drone/gardener.dm | 2 -- .../xenomorph/strains/castes/drone/healer.dm | 2 -- .../strains/castes/facehugger/watcher.dm | 3 --- .../castes/hivelord/resin_whisperer.dm | 2 -- .../strains/castes/lurker/vampire.dm | 2 -- .../strains/castes/praetorian/dancer.dm | 2 -- .../strains/castes/praetorian/oppressor.dm | 2 -- .../strains/castes/praetorian/vanguard.dm | 2 -- .../strains/castes/praetorian/warden.dm | 2 -- .../strains/castes/ravager/berserker.dm | 2 -- .../strains/castes/ravager/hedgehog.dm | 2 -- .../xenomorph/strains/castes/runner/acid.dm | 3 --- .../carbon/xenomorph/strains/xeno_strain.dm | 21 ++++++++++++------- 17 files changed, 14 insertions(+), 42 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm index c18973209220..e6c8061bd0fe 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm @@ -20,7 +20,6 @@ behavior_delegate_type = /datum/behavior_delegate/boiler_trapper /datum/xeno_strain/trapper/apply_strain(mob/living/carbon/xenomorph/boiler/boiler) - . = ..() if(!istype(boiler)) return FALSE @@ -35,7 +34,6 @@ boiler.speed_modifier += XENO_SPEED_SLOWMOD_TIER_5 // compensating for base buffs boiler.recalculate_everything() - return TRUE /datum/behavior_delegate/boiler_trapper name = "Boiler Trapper Behavior Delegate" diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm index f1ba672d63e5..97d6770be33c 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm @@ -17,7 +17,6 @@ behavior_delegate_type = /datum/behavior_delegate/carrier_eggsac /datum/xeno_strain/eggsac/apply_strain(mob/living/carbon/xenomorph/carrier/carrier) - . = ..() carrier.plasma_types = list(PLASMA_EGG) carrier.phero_modifier += XENO_PHERO_MOD_LARGE // praetorian level pheremones @@ -32,7 +31,6 @@ carrier.eggs_max = 12 carrier.egg_planting_range = 2 carrier.update_eggsac_overlays() - return TRUE #define EGGSAC_OFF_WEED_EGGCAP 4 #define EGGSAC_EGG_SUSTAIN_DISTANCE 14 diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/crusher/charger.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/crusher/charger.dm index f2dd564cb2ee..84877b43571e 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/crusher/charger.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/crusher/charger.dm @@ -32,8 +32,6 @@ behavior_delegate_type = /datum/behavior_delegate/crusher_charger /datum/xeno_strain/charger/apply_strain(mob/living/carbon/xenomorph/crusher/crusher) - . = ..() - crusher.small_explosives_stun = FALSE crusher.health_modifier += XENO_HEALTH_MOD_LARGE crusher.speed_modifier += XENO_SPEED_FASTMOD_TIER_3 @@ -42,7 +40,6 @@ crusher.ignore_aura = "frenzy" // no funny crushers going 7 morbillion kilometers per second crusher.phero_modifier = -crusher.caste.aura_strength crusher.recalculate_everything() - return TRUE /datum/behavior_delegate/crusher_charger name = "Charger Crusher Behavior Delegate" diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm index 891c1ce08e1e..1560387c218b 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm @@ -18,8 +18,6 @@ behavior_delegate_type = /datum/behavior_delegate/defender_steel_crest /datum/xeno_strain/steel_crest/apply_strain(mob/living/carbon/xenomorph/defender/defender) - . = ..() - defender.damage_modifier -= XENO_DAMAGE_MOD_VERY_SMALL if(defender.fortify) defender.ability_speed_modifier += 2.5 diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/gardener.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/gardener.dm index 456768cdd25a..88a6cb50148b 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/gardener.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/gardener.dm @@ -19,8 +19,6 @@ behavior_delegate_type = /datum/behavior_delegate/drone_gardener /datum/xeno_strain/gardener/apply_strain(mob/living/carbon/xenomorph/drone/drone) - . = ..() - drone.available_fruits = list( /obj/effect/alien/resin/fruit/greater, /obj/effect/alien/resin/fruit/unstable, diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm index bca247899428..6a985eb8d7ec 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm @@ -22,8 +22,6 @@ behavior_delegate_type = /datum/behavior_delegate/drone_healer /datum/xeno_strain/healer/apply_strain(mob/living/carbon/xenomorph/drone/drone) - . = ..() - drone.phero_modifier += XENO_PHERO_MOD_LARGE drone.plasma_types += PLASMA_PHEROMONE drone.damage_modifier -= XENO_DAMAGE_MOD_VERY_SMALL diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/facehugger/watcher.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/facehugger/watcher.dm index c5d9986c7b6a..7fba30b6f352 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/facehugger/watcher.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/facehugger/watcher.dm @@ -13,11 +13,8 @@ behavior_delegate_type = /datum/behavior_delegate/facehugger_watcher /datum/xeno_strain/watcher/apply_strain(mob/living/carbon/xenomorph/facehugger/huggy) - . = ..() - huggy.viewsize = 10 huggy.layer = initial(huggy.layer) - return TRUE // This has no special effects, it's just here to skip `/datum/behavior_delegate/facehugger_base/on_life()`. /datum/behavior_delegate/facehugger_watcher diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm index 2b3e790ab21b..cca2210a30b4 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm @@ -17,8 +17,6 @@ ) /datum/xeno_strain/resin_whisperer/apply_strain(mob/living/carbon/xenomorph/hivelord/hivelord) - . = ..() - hivelord.plasmapool_modifier = 0.8 // -20% plasma pool hivelord.extra_build_dist = 12 // 1 + 12 = 13 tile build range hivelord.can_stack_builds = TRUE diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm index 4beec851c420..1f220a02dd79 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm @@ -16,8 +16,6 @@ ) /datum/xeno_strain/vampire/apply_strain(mob/living/carbon/xenomorph/lurker/lurker) - . = ..() - lurker.plasmapool_modifier = 0 lurker.health_modifier -= XENO_HEALTH_MOD_MED lurker.speed_modifier += XENO_SPEED_FASTMOD_TIER_1 diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm index 2d6d7bb7b15d..ef2eb377d01e 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm @@ -20,8 +20,6 @@ behavior_delegate_type = /datum/behavior_delegate/praetorian_dancer /datum/xeno_strain/dancer/apply_strain(mob/living/carbon/xenomorph/praetorian/prae) - . = ..() - prae.armor_modifier -= XENO_ARMOR_MOD_VERY_SMALL prae.speed_modifier += XENO_SPEED_FASTMOD_TIER_5 prae.plasma_types = list(PLASMA_CATECHOLAMINE) diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm index 6d3d50c1d12d..74dc1b9d6ecd 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm @@ -23,8 +23,6 @@ behavior_delegate_type = /datum/behavior_delegate/oppressor_praetorian /datum/xeno_strain/oppressor/apply_strain(mob/living/carbon/xenomorph/praetorian/prae) - . = ..() - prae.damage_modifier -= XENO_DAMAGE_MOD_SMALL prae.explosivearmor_modifier += XENO_EXPOSIVEARMOR_MOD_SMALL prae.small_explosives_stun = FALSE diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm index b8baef5e518f..a5d4b757cf6d 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm @@ -21,8 +21,6 @@ behavior_delegate_type = /datum/behavior_delegate/praetorian_vanguard /datum/xeno_strain/vanguard/apply_strain(mob/living/carbon/xenomorph/praetorian/prae) - . = ..() - prae.speed_modifier += XENO_SPEED_FASTMOD_TIER_3 prae.health_modifier -= XENO_HEALTH_MOD_MED prae.claw_type = CLAW_TYPE_SHARP diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm index 3cb42e59e175..56dfca99a732 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm @@ -21,8 +21,6 @@ behavior_delegate_type = /datum/behavior_delegate/praetorian_warden /datum/xeno_strain/warden/apply_strain(mob/living/carbon/xenomorph/praetorian/prae) - . = ..() - // Make a 'halftank' prae.speed_modifier += XENO_SPEED_SLOWMOD_TIER_5 prae.damage_modifier -= XENO_DAMAGE_MOD_SMALL diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/berserker.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/berserker.dm index 80261d295ab6..7b912cc620a0 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/berserker.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/berserker.dm @@ -17,8 +17,6 @@ behavior_delegate_type = /datum/behavior_delegate/ravager_berserker /datum/xeno_strain/berserker/apply_strain(mob/living/carbon/xenomorph/ravager/ravager) - . = ..() - ravager.plasma_max = 0 ravager.health_modifier -= XENO_HEALTH_MOD_MED ravager.armor_modifier += XENO_ARMOR_MOD_VERY_SMALL diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm index 75a85ca3e72e..4e452fb1a18a 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm @@ -17,8 +17,6 @@ behavior_delegate_type = /datum/behavior_delegate/ravager_hedgehog /datum/xeno_strain/hedgehog/apply_strain(mob/living/carbon/xenomorph/ravager/ravager) - . = ..() - ravager.plasma_max = 0 ravager.small_explosives_stun = FALSE ravager.explosivearmor_modifier += XENO_EXPOSIVEARMOR_MOD_SMALL diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm index d768ad61ce2d..8f2ce0ef7150 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm @@ -17,15 +17,12 @@ behavior_delegate_type = /datum/behavior_delegate/runner_acider /datum/xeno_strain/acider/apply_strain(mob/living/carbon/xenomorph/runner/runner) - . = ..() - runner.speed_modifier += XENO_SPEED_SLOWMOD_TIER_5 runner.armor_modifier += XENO_ARMOR_MOD_MED runner.health_modifier += XENO_HEALTH_MOD_ACIDER runner.recalculate_everything() - /datum/behavior_delegate/runner_acider var/acid_amount = 0 diff --git a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm index 0098f61b1e29..586bf95aec7b 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm @@ -21,11 +21,11 @@ * * Returns a bool indicating if the strain was successfully applied. */ -/datum/xeno_strain/proc/apply_strain(mob/living/carbon/xenomorph/xeno) - SHOULD_CALL_PARENT(TRUE) +/datum/xeno_strain/proc/_add_to_xeno(mob/living/carbon/xenomorph/xeno) + // Override `apply_changes()`, not this! (Unless you know what you're doing.) + SHOULD_NOT_OVERRIDE(TRUE) xeno.strain = src - register_signals(xeno) // Update the xeno's actions. for(var/action_path in actions_to_remove) @@ -41,17 +41,24 @@ xeno.behavior_delegate.bound_xeno = xeno xeno.behavior_delegate.add_to_xeno() + apply_strain() + xeno.update_icons() xeno.hive.hive_ui.update_xeno_info() - // Give them all the info about the strain. + // Give them all of the info about the strain. to_chat(xeno, SPAN_XENOANNOUNCE(description)) if(flavor_description) to_chat(xeno, SPAN_XENOLEADER(flavor_description)) return TRUE -/// TODO: documentation -/datum/xeno_strain/proc/register_signals(mob/living/carbon/xenomorph/xeno) +/** + * Adds any special modifiers/changes from this strain to `xeno`. + * + * Called when the strain is first added to the player. + */ +/datum/xeno_strain/proc/apply_strain(mob/living/carbon/xenomorph/xeno) + // Override with custom behaviour. return @@ -85,7 +92,7 @@ // Create the strain datum and apply it to the xeno. var/datum/xeno_strain/strain_instance = new chosen_strain() - if(strain_instance.apply_strain(src)) + if(strain_instance._add_to_xeno(src)) xeno_jitter(1.5 SECONDS) // If it applied successfully, add it to the logs. log_strain("[name] purchased strain '[strain_instance.type]'") From 8ffee8e0d78e0c876d10ea71eb9ffd19ad715791 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Wed, 24 Jan 2024 20:43:19 +0000 Subject: [PATCH 11/17] Initial fixes from testing --- code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm | 3 +-- code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm | 3 +-- .../living/carbon/xenomorph/strains/castes/drone/gardener.dm | 3 --- .../mob/living/carbon/xenomorph/strains/xeno_strain.dm | 4 ++++ 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm index 9c8478a93eb2..d290b917e945 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm @@ -15,6 +15,7 @@ speed = XENO_SPEED_TIER_4 available_strains = list(/datum/xeno_strain/eggsac) + behavior_delegate_type = /datum/behavior_delegate/carrier_base evolution_allowed = FALSE deevolves_to = list(XENO_CASTE_DRONE) @@ -78,8 +79,6 @@ /mob/living/carbon/xenomorph/proc/set_hugger_reserve_for_morpher, ) - behavior_delegate = /datum/behavior_delegate/carrier_base - icon_xenonid = 'icons/mob/xenonids/carrier.dmi' weed_food_icon = 'icons/mob/xenos/weeds_64x64.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm b/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm index b9c5b140047e..00feaa44b9a3 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm @@ -10,6 +10,7 @@ speed = XENO_SPEED_TIER_8 available_strains = list(/datum/xeno_strain/watcher) + behavior_delegate_type = /datum/behavior_delegate/facehugger_base evolution_allowed = FALSE can_be_revived = FALSE @@ -58,8 +59,6 @@ /mob/living/carbon/xenomorph/proc/vent_crawl, ) - behavior_delegate = /datum/behavior_delegate/facehugger_base - icon_xeno = 'icons/mob/xenos/facehugger.dmi' icon_xenonid = 'icons/mob/xenonids/facehugger.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/gardener.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/gardener.dm index 88a6cb50148b..6bb2f87dbb77 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/gardener.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/gardener.dm @@ -363,9 +363,6 @@ var/mutable_appearance/fruit_sac_overlay_icon -/datum/behavior_delegate/drone_gardener/add_to_xeno() - on_update_icons() - /datum/behavior_delegate/drone_gardener/on_update_icons() if(!fruit_sac_overlay_icon) fruit_sac_overlay_icon = mutable_appearance('icons/mob/xenos/drone_strain_overlays.dmi', "Gardener Drone Walking") diff --git a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm index 586bf95aec7b..1b260f4647a1 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm @@ -102,6 +102,10 @@ if(!length(caste.available_strains) || !check_state(TRUE)) return FALSE + if(strain) + to_chat(src, SPAN_WARNING("We have already chosen a strain.")) + return FALSE + if(is_ventcrawling) to_chat(src, SPAN_WARNING("This place is too constraining to take a strain.")) return FALSE From bd43b18df9c0926706adb3b3740f615ee58e1e38 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Wed, 24 Jan 2024 21:02:54 +0000 Subject: [PATCH 12/17] todo removal to appease the CI I still need to test this though --- tgui/packages/tgui/interfaces/HiveStatus.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgui/packages/tgui/interfaces/HiveStatus.jsx b/tgui/packages/tgui/interfaces/HiveStatus.jsx index 72d9476f96dd..ea23b73aca55 100644 --- a/tgui/packages/tgui/interfaces/HiveStatus.jsx +++ b/tgui/packages/tgui/interfaces/HiveStatus.jsx @@ -359,7 +359,7 @@ const XenoList = (props) => { {entry.name} - {entry.strain} // TODO make sure this still works + {entry.strain} {entry.location} {entry.health < 30 ? ( From 4f283bb2a73014bc14562e76eba66fbd87fe5734 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:30:24 +0000 Subject: [PATCH 13/17] More testing --- .../mob/living/carbon/xenomorph/Xenomorph.dm | 3 +-- .../xenomorph/abilities/queen/queen_abilities.dm | 2 +- .../living/carbon/xenomorph/castes/Facehugger.dm | 2 +- .../mob/living/carbon/xenomorph/egg_item.dm | 2 +- .../mob/living/carbon/xenomorph/hive_status.dm | 2 +- .../xenomorph/strains/castes/carrier/eggsac.dm | 7 +++---- .../strains/castes/defender/steel_crest.dm | 16 ---------------- .../carbon/xenomorph/strains/xeno_strain.dm | 4 +++- .../mob/living/carbon/xenomorph/xeno_helpers.dm | 10 +++++++++- 9 files changed, 20 insertions(+), 28 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index cb1704c8be5b..c8d3df91c975 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -1020,8 +1020,7 @@ handle_ghost_message() /mob/living/carbon/xenomorph/proc/handle_ghost_message() - var/strain_name = strain ? strain.name : "Normal" - notify_ghosts("[src] ([strain_name] [caste_type]) has ghosted and their body is up for grabs!", source = src) + notify_ghosts("[src] ([get_strain_name()] [caste_type]) has ghosted and their body is up for grabs!", source = src) /mob/living/carbon/xenomorph/larva/handle_ghost_message() if(locate(/obj/effect/alien/resin/special/pylon/core) in range(2, get_turf(src))) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_abilities.dm index 307f28261d28..9ec61b4c95ca 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_abilities.dm @@ -62,7 +62,7 @@ . = ..() SSticker.OnRoundstart(CALLBACK(src, PROC_REF(apply_queen_build_boost))) -// queenos don't need weeds under them to build +// queenos don't need weeds under them to build on ovi /datum/action/xeno_action/activable/secrete_resin/remote/queen/can_remote_build() return TRUE diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm b/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm index 00feaa44b9a3..4d164c289dc1 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm @@ -223,5 +223,5 @@ name = "Base Facehugger Behavior Delegate" /datum/behavior_delegate/facehugger_base/on_life() - if(bound_xeno.body_position == STANDING_UP && !(locate(/obj/effect/alien/weeds) in get_turf(src))) + if(bound_xeno.body_position == STANDING_UP && !(locate(/obj/effect/alien/weeds) in get_turf(bound_xeno))) bound_xeno.adjustBruteLoss(1) diff --git a/code/modules/mob/living/carbon/xenomorph/egg_item.dm b/code/modules/mob/living/carbon/xenomorph/egg_item.dm index 59e2b964d848..f349b8acfb8d 100644 --- a/code/modules/mob/living/carbon/xenomorph/egg_item.dm +++ b/code/modules/mob/living/carbon/xenomorph/egg_item.dm @@ -104,7 +104,7 @@ if(weed.weed_strength >= WEED_LEVEL_WEAK && weed.linked_hive.hivenumber == hivenumber) //check for ANY weeds any_weeds = weed - // If the user isn't an eggsac carrier, they're only able to plant eggs on hive weeds. + // If the user isn't an eggsac carrier, then they can only plant eggs on hive weeds. var/needs_hive_weeds = !istype(user.strain, /datum/xeno_strain/eggsac) var/datum/hive_status/hive = GLOB.hive_datum[hivenumber] diff --git a/code/modules/mob/living/carbon/xenomorph/hive_status.dm b/code/modules/mob/living/carbon/xenomorph/hive_status.dm index c6d0b158c8b3..4b6c0f4b279e 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_status.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_status.dm @@ -514,7 +514,7 @@ xeno_name = "Larva ([X.nicknumber])" xenos["[X.nicknumber]"] = list( "name" = xeno_name, - "strain" = X.strain, + "strain" = X.get_strain_name(), "ref" = "\ref[X]" ) diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm index 97d6770be33c..9cc0ab14db8e 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm @@ -67,10 +67,6 @@ else my_egg.check_decay() -/datum/behavior_delegate/carrier_eggsac/handle_death(mob/M) - M.visible_message(SPAN_XENOWARNING("[M] throes as its eggsac bursts into a mess of acid!")) - playsound(M.loc, 'sound/effects/alien_egg_burst.ogg', 25, TRUE) - ///Remove owner of egg /datum/behavior_delegate/carrier_eggsac/proc/remove_egg_owner(obj/effect/alien/egg/carrier_egg/egg) if(!egg.owner || egg.owner != bound_xeno) @@ -83,6 +79,9 @@ remove_egg_owner(my_egg) my_egg.start_unstoppable_decay() + M.visible_message(SPAN_XENOWARNING("[M] throes as its eggsac bursts into a mess of acid!")) + playsound(M.loc, 'sound/effects/alien_egg_burst.ogg', 25, TRUE) + ///Remove all references to src in eggs_sustained /datum/behavior_delegate/carrier_eggsac/Destroy() for(var/obj/effect/alien/egg/carrier_egg/my_egg as anything in eggs_sustained) diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm index 1560387c218b..eb547e2201a1 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm @@ -15,24 +15,8 @@ /datum/action/xeno_action/onclick/soak, ) - behavior_delegate_type = /datum/behavior_delegate/defender_steel_crest - /datum/xeno_strain/steel_crest/apply_strain(mob/living/carbon/xenomorph/defender/defender) defender.damage_modifier -= XENO_DAMAGE_MOD_VERY_SMALL if(defender.fortify) defender.ability_speed_modifier += 2.5 defender.recalculate_stats() - -/datum/behavior_delegate/defender_steel_crest - name = "Steel Crest Defender Behavior Delegate" - -/datum/behavior_delegate/defender_steel_crest/on_update_icons() - if(bound_xeno.stat == DEAD) - return - - if(bound_xeno.fortify) - bound_xeno.icon_state = "[bound_xeno.get_strain_icon()] Steelcrest Defender Fortify" - return TRUE - if(bound_xeno.crest_defense) - bound_xeno.icon_state = "[bound_xeno.get_strain_icon()] Steelcrest Defender Crest" - return TRUE diff --git a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm index 1b260f4647a1..5022289a0231 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm @@ -41,7 +41,7 @@ xeno.behavior_delegate.bound_xeno = xeno xeno.behavior_delegate.add_to_xeno() - apply_strain() + apply_strain(xeno) xeno.update_icons() xeno.hive.hive_ui.update_xeno_info() @@ -78,6 +78,8 @@ // Ask the user which strain they want. var/strain_choice = tgui_input_list(usr, "Which strain would you like to take?", "Choose Strain", strain_list, theme = "hive_status") + if(!strain_choice) + return var/datum/xeno_strain/chosen_strain = strain_list[strain_choice] // Check again after the user picks one, in case anything changed. diff --git a/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm b/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm index af1511a3601e..0391afd1a4f3 100644 --- a/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm +++ b/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm @@ -34,10 +34,18 @@ return 100 return round(armor_integrity * 100 / armor_integrity_max) +/** + * Returns the name of the xeno's strain, if it has one. + * + * If that can't be found, returns "Normal". + */ +/mob/living/carbon/xenomorph/proc/get_strain_name() + return strain?.name || "Normal" + /** * Returns the custom icon state from the xeno's strain, if it has one. * - * If that isn't available, returns "Normal" + * If that can't be found, returns "Normal" */ /mob/living/carbon/xenomorph/proc/get_strain_icon() return strain?.xeno_icon_state || "Normal" From e129cfd6494555b5c8b44d529cab7c5258a454d4 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Mon, 5 Feb 2024 19:28:00 +0000 Subject: [PATCH 14/17] guh (forgot to run dreamchecker before I pushed) The mutation_type check was added by a review in #5615, but removing it probably makes the most sense here since that's what I've done with the others. --- .../xenomorph/abilities/praetorian/praetorian_powers.dm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm index 4dbd0ad3ff18..11ff4de20745 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm @@ -853,9 +853,7 @@ targetXeno.visible_message(SPAN_BOLDNOTICE("[X] places its claws on [targetXeno], and its wounds are quickly sealed!")) //marines probably should know if a xeno gets healed X.gain_health(heal_amount*0.5 + bonus_heal*0.5) X.flick_heal_overlay(3 SECONDS, "#00B800") - if(X.mutation_type == PRAETORIAN_WARDEN) - var/datum/behavior_delegate/praetorian_warden/warden_delegate = X.behavior_delegate - warden_delegate.transferred_healing += heal_amount + BD.transferred_healing += heal_amount use_plasma = TRUE //it's already hard enough to gauge health without hp showing on the mob targetXeno.flick_heal_overlay(3 SECONDS, "#00B800")//so the visible_message and recovery overlay will warn marines and possibly predators that the xenomorph has been healed! From 47a8a62d6aac3a6d50a8e1b16b9fa8f55598a47d Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Tue, 6 Feb 2024 19:06:20 +0000 Subject: [PATCH 15/17] Review the 1st (Thank you!) --- .../shield_types/vanguard_shield.dm | 6 +- .../abilities/defender/defender_powers.dm | 64 +++++++++---------- .../abilities/lurker/lurker_powers.dm | 3 +- .../abilities/praetorian/praetorian_powers.dm | 46 ++++++------- .../living/carbon/xenomorph/castes/Queen.dm | 2 +- .../carbon/xenomorph/strains/xeno_strain.dm | 2 +- 6 files changed, 61 insertions(+), 62 deletions(-) diff --git a/code/datums/xeno_shields/shield_types/vanguard_shield.dm b/code/datums/xeno_shields/shield_types/vanguard_shield.dm index faf38e466e99..21d9fb12cfd7 100644 --- a/code/datums/xeno_shields/shield_types/vanguard_shield.dm +++ b/code/datums/xeno_shields/shield_types/vanguard_shield.dm @@ -50,6 +50,6 @@ if (!istype(linked_xeno)) return - var/datum/behavior_delegate/praetorian_vanguard/BD = linked_xeno.behavior_delegate - if (istype(BD)) - BD.last_combat_time = world.time + var/datum/behavior_delegate/praetorian_vanguard/behavior = linked_xeno.behavior_delegate + if (istype(behavior)) + behavior.last_combat_time = world.time diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_powers.dm index 28d31b0e479f..98c0c19f68f7 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/defender/defender_powers.dm @@ -196,52 +196,52 @@ if(xeno.fortify) button.icon_state = "template_active" -/datum/action/xeno_action/activable/fortify/proc/fortify_switch(mob/living/carbon/xenomorph/X, fortify_state) - if(X.fortify == fortify_state) +/datum/action/xeno_action/activable/fortify/proc/fortify_switch(mob/living/carbon/xenomorph/xeno, fortify_state) + if(xeno.fortify == fortify_state) return if(fortify_state) - to_chat(X, SPAN_XENOWARNING("We tuck ourself into a defensive stance.")) + to_chat(xeno, SPAN_XENOWARNING("We tuck ourself into a defensive stance.")) RegisterSignal(owner, COMSIG_XENO_PRE_CALCULATE_ARMOURED_DAMAGE_PROJECTILE, PROC_REF(check_directional_armor)) - X.mob_size = MOB_SIZE_IMMOBILE //knockback immune - X.mob_flags &= ~SQUEEZE_UNDER_VEHICLES - X.fortify = TRUE + xeno.mob_size = MOB_SIZE_IMMOBILE //knockback immune + xeno.mob_flags &= ~SQUEEZE_UNDER_VEHICLES + xeno.fortify = TRUE else - to_chat(X, SPAN_XENOWARNING("We resume our normal stance.")) - REMOVE_TRAIT(X, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Fortify")) - X.anchored = FALSE + to_chat(xeno, SPAN_XENOWARNING("We resume our normal stance.")) + REMOVE_TRAIT(xeno, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Fortify")) + xeno.anchored = FALSE UnregisterSignal(owner, COMSIG_XENO_PRE_CALCULATE_ARMOURED_DAMAGE_PROJECTILE) - X.mob_size = MOB_SIZE_XENO //no longer knockback immune - X.mob_flags |= SQUEEZE_UNDER_VEHICLES - X.fortify = FALSE + xeno.mob_size = MOB_SIZE_XENO //no longer knockback immune + xeno.mob_flags |= SQUEEZE_UNDER_VEHICLES + xeno.fortify = FALSE - apply_modifiers(X, fortify_state) - X.update_icons() + apply_modifiers(xeno, fortify_state) + xeno.update_icons() -/datum/action/xeno_action/activable/fortify/proc/apply_modifiers(mob/living/carbon/xenomorph/X, fortify_state) +/datum/action/xeno_action/activable/fortify/proc/apply_modifiers(mob/living/carbon/xenomorph/xeno, fortify_state) if(fortify_state) - X.armor_deflection_buff += 30 - X.armor_explosive_buff += 60 - ADD_TRAIT(X, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Fortify")) - X.anchored = TRUE - X.small_explosives_stun = FALSE + xeno.armor_deflection_buff += 30 + xeno.armor_explosive_buff += 60 + ADD_TRAIT(xeno, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Fortify")) + xeno.anchored = TRUE + xeno.small_explosives_stun = FALSE else - X.armor_deflection_buff -= 30 - X.armor_explosive_buff -= 60 - X.small_explosives_stun = TRUE + xeno.armor_deflection_buff -= 30 + xeno.armor_explosive_buff -= 60 + xeno.small_explosives_stun = TRUE // Steel crest override -/datum/action/xeno_action/activable/fortify/steel_crest/apply_modifiers(mob/living/carbon/xenomorph/X, fortify_state) +/datum/action/xeno_action/activable/fortify/steel_crest/apply_modifiers(mob/living/carbon/xenomorph/xeno, fortify_state) if(fortify_state) - X.armor_deflection_buff += 10 - X.armor_explosive_buff += 60 - X.ability_speed_modifier += 3 - X.damage_modifier -= XENO_DAMAGE_MOD_SMALL + xeno.armor_deflection_buff += 10 + xeno.armor_explosive_buff += 60 + xeno.ability_speed_modifier += 3 + xeno.damage_modifier -= XENO_DAMAGE_MOD_SMALL else - X.armor_deflection_buff -= 10 - X.armor_explosive_buff -= 60 - X.ability_speed_modifier -= 3 - X.damage_modifier += XENO_DAMAGE_MOD_SMALL + xeno.armor_deflection_buff -= 10 + xeno.armor_explosive_buff -= 60 + xeno.ability_speed_modifier -= 3 + xeno.damage_modifier += XENO_DAMAGE_MOD_SMALL /datum/action/xeno_action/activable/fortify/proc/check_directional_armor(mob/living/carbon/xenomorph/defendy, list/damagedata) SIGNAL_HANDLER diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm index f47fba353543..373c2701ce37 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm @@ -12,8 +12,7 @@ if(found) var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invis = get_xeno_action_by_type(xeno, /datum/action/xeno_action/onclick/lurker_invisibility) - if(istype(lurker_invis)) - lurker_invis.invisibility_off() + lurker_invis.invisibility_off() /datum/action/xeno_action/activable/pounce/lurker/additional_effects(mob/living/living_mob) var/mob/living/carbon/xenomorph/xeno = owner diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm index 11ff4de20745..bc5e81cb46bc 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/praetorian/praetorian_powers.dm @@ -70,9 +70,9 @@ playsound(current_mob, 'sound/weapons/alien_tail_attack.ogg', 30, TRUE) if (target_mobs.len >= shield_regen_threshold) - var/datum/behavior_delegate/praetorian_vanguard/BD = source_xeno.behavior_delegate - if (istype(BD)) - BD.regen_shield() + var/datum/behavior_delegate/praetorian_vanguard/behavior = source_xeno.behavior_delegate + if (istype(behavior)) + behavior.regen_shield() apply_cooldown() return ..() @@ -134,9 +134,9 @@ playsound(get_turf(H), "alien_claw_flesh", 30, 1) if (target_mobs.len >= shield_regen_threshold) - var/datum/behavior_delegate/praetorian_vanguard/BD = X.behavior_delegate - if (istype(BD)) - BD.regen_shield() + var/datum/behavior_delegate/praetorian_vanguard/behavior = X.behavior_delegate + if (istype(behavior)) + behavior.regen_shield() /datum/action/xeno_action/activable/cleave/use_ability(atom/target_atom) var/mob/living/carbon/xenomorph/vanguard_user = owner @@ -794,15 +794,15 @@ var/bonus_shield = 0 - var/datum/behavior_delegate/praetorian_warden/BD = X.behavior_delegate - if (!istype(BD)) + var/datum/behavior_delegate/praetorian_warden/behavior = X.behavior_delegate + if (!istype(behavior)) return - if (!BD.use_internal_hp_ability(shield_cost)) + if (!behavior.use_internal_hp_ability(shield_cost)) return - bonus_shield = BD.internal_hitpoints*0.5 - if (!BD.use_internal_hp_ability(bonus_shield)) + bonus_shield = behavior.internal_hitpoints*0.5 + if (!behavior.use_internal_hp_ability(bonus_shield)) bonus_shield = 0 var/total_shield_amount = shield_amount + bonus_shield @@ -836,15 +836,15 @@ return var/bonus_heal = 0 - var/datum/behavior_delegate/praetorian_warden/BD = X.behavior_delegate - if (!istype(BD)) + var/datum/behavior_delegate/praetorian_warden/behavior = X.behavior_delegate + if (!istype(behavior)) return - if (!BD.use_internal_hp_ability(heal_cost)) + if (!behavior.use_internal_hp_ability(heal_cost)) return - bonus_heal = BD.internal_hitpoints*0.5 - if (!BD.use_internal_hp_ability(bonus_heal)) + bonus_heal = behavior.internal_hitpoints*0.5 + if (!behavior.use_internal_hp_ability(bonus_heal)) bonus_heal = 0 to_chat(X, SPAN_XENODANGER("We heal [targetXeno]!")) @@ -853,7 +853,7 @@ targetXeno.visible_message(SPAN_BOLDNOTICE("[X] places its claws on [targetXeno], and its wounds are quickly sealed!")) //marines probably should know if a xeno gets healed X.gain_health(heal_amount*0.5 + bonus_heal*0.5) X.flick_heal_overlay(3 SECONDS, "#00B800") - BD.transferred_healing += heal_amount + behavior.transferred_healing += heal_amount use_plasma = TRUE //it's already hard enough to gauge health without hp showing on the mob targetXeno.flick_heal_overlay(3 SECONDS, "#00B800")//so the visible_message and recovery overlay will warn marines and possibly predators that the xenomorph has been healed! @@ -862,11 +862,11 @@ to_chat(X, SPAN_XENOHIGHDANGER("We cannot rejuvenate targets through overwatch!")) return - var/datum/behavior_delegate/praetorian_warden/BD = X.behavior_delegate - if (!istype(BD)) + var/datum/behavior_delegate/praetorian_warden/behavior = X.behavior_delegate + if (!istype(behavior)) return - if (!BD.use_internal_hp_ability(debuff_cost)) + if (!behavior.use_internal_hp_ability(debuff_cost)) return to_chat(X, SPAN_XENODANGER("We rejuvenate [targetXeno]!")) @@ -892,8 +892,8 @@ if(!istype(X)) return - var/datum/behavior_delegate/praetorian_warden/BD = X.behavior_delegate - if(!istype(BD)) + var/datum/behavior_delegate/praetorian_warden/behavior = X.behavior_delegate + if(!istype(behavior)) return if(X.observed_xeno != null) @@ -936,7 +936,7 @@ if(!check_plasma_owner()) return - if(!BD.use_internal_hp_ability(retrieve_cost)) + if(!behavior.use_internal_hp_ability(retrieve_cost)) return if(!check_and_use_plasma_owner()) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm index d48bd1608f88..d5def4ddee88 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm @@ -934,7 +934,7 @@ var/mob/living/carbon/xenomorph/queen/Queen = bound_xeno if(Queen.ovipositor) Queen.icon = Queen.queen_ovipositor_icon - Queen.icon_state = "Normal Queen Ovipositor" + Queen.icon_state = "[Queen.get_strain_name()] Queen Ovipositor" return TRUE // Switch icon back and then let normal icon behavior happen diff --git a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm index 5022289a0231..278e99a5e118 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm @@ -20,9 +20,9 @@ * Add this strain to `xeno`, replacing their actions and behavior holder. * * Returns a bool indicating if the strain was successfully applied. + * **Override [/datum/xeno_strain/proc/apply_strain], not this! (Unless you know what you're doing.)** */ /datum/xeno_strain/proc/_add_to_xeno(mob/living/carbon/xenomorph/xeno) - // Override `apply_changes()`, not this! (Unless you know what you're doing.) SHOULD_NOT_OVERRIDE(TRUE) xeno.strain = src From 3a9289bf2677733cb79873661772a7e897dfd084 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Sun, 11 Feb 2024 18:04:26 +0000 Subject: [PATCH 16/17] Strain sprites fix Renamed the variable to be a bit more descriptive, and replaced the defines with their strings. --- .../carbon/xenomorph/strains/castes/defender/steel_crest.dm | 2 +- .../mob/living/carbon/xenomorph/strains/castes/drone/healer.dm | 1 + .../carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm | 1 + .../living/carbon/xenomorph/strains/castes/lurker/vampire.dm | 1 + .../living/carbon/xenomorph/strains/castes/praetorian/dancer.dm | 2 +- .../carbon/xenomorph/strains/castes/praetorian/oppressor.dm | 2 +- .../carbon/xenomorph/strains/castes/praetorian/vanguard.dm | 2 +- .../living/carbon/xenomorph/strains/castes/praetorian/warden.dm | 2 +- .../living/carbon/xenomorph/strains/castes/ravager/berserker.dm | 1 + .../living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm | 1 + .../mob/living/carbon/xenomorph/strains/castes/runner/acid.dm | 2 +- code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm | 2 +- code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm | 2 +- 13 files changed, 13 insertions(+), 8 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm index eb547e2201a1..f84566e9c841 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm @@ -2,7 +2,7 @@ name = DEFENDER_STEELCREST description = "You trade your tail sweep and a small amount of your slash damage for slightly increased headbutt knockback and damage and the ability to slowly move and headbutt while fortified. Along with this, you gain a unique ability to accumulate damage, and use it to recover a slight amount of health and refresh your tail slam." flavor_description = "To handle yourself, use your head. To handle others, use your head." - xeno_icon_state = DEFENDER_STEELCREST + icon_state_prefix = "Steelcrest" actions_to_remove = list( /datum/action/xeno_action/activable/headbutt, diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm index 6a985eb8d7ec..0fcbb2ecf09a 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm @@ -2,6 +2,7 @@ name = DRONE_HEALER description = "You lose your choice of resin secretions, a chunk of your slash damage, and you will experience a slighty-increased difficulty in tackling tallhosts in exchange for strong pheromones, the ability to use a bit of your health to plant a maximum of three lesser resin fruits, and the ability to heal your sisters' wounds by secreting a regenerative resin salve by using your vital fluids and a fifth of your plasma. Be wary, this is a dangerous process; overexert yourself and you may exhaust yourself to unconsciousness, or die..." flavor_description = "To the very last drop, your blood belongs to The Hive; share it with your sisters to keep them fighting." + icon_state_prefix = "Healer" actions_to_remove = list( /datum/action/xeno_action/activable/secrete_resin, diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm index cca2210a30b4..8bdcd1311f94 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm @@ -2,6 +2,7 @@ name = HIVELORD_RESIN_WHISPERER description = "You lose your corrosive acid, your ability to secrete thick resin, your ability to reinforce resin secretions, sacrifice your ability to plant resin nodes outside of weeds, and you sacrifice a fifth of your plasma reserves to enhance your vision and gain a stronger connection to the resin. You can now remotely place resin secretions including resin nodes up to a distance of twelve paces!" flavor_description = "Let the resin guide you. It whispers, so listen closely." + icon_state_prefix = "Resin Whisperer" actions_to_remove = list( /datum/action/xeno_action/onclick/plant_weeds, diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm index 1f220a02dd79..1df49092e783 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm @@ -2,6 +2,7 @@ name = LURKER_VAMPIRE description = "You lose all of your abilities and you forefeit a chunk of your health and damage in exchange for a large amount of armor, a little bit of movement speed, increased attack speed, and brand new abilities that make you an assassin. Rush on your opponent to disorient them and Flurry to unleash a forward cleave that can hit and slow three talls and heal you for every tall you hit. Use your special AoE Tail Jab to knock talls away, doing more damage with direct hits and even more damage and a stun if they smack into walls. Finally, execute unconscious talls with a headbite that bypasses armor and heals you for a grand amount of health." flavor_description = "Your thirst for tallhost blood surpasses even mine, child. Show no mercy! Slaughter them all!" + icon_state_prefix = "Vampire" actions_to_remove = list( /datum/action/xeno_action/onclick/lurker_invisibility, diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm index ef2eb377d01e..f9a5dbedb614 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm @@ -3,7 +3,7 @@ name = PRAETORIAN_DANCER description = "You lose all of your acid-based abilities and a small amount of your armor in exchange for increased movement speed, evasion, and unparalleled agility that gives you an ability to move even more quickly, dodge bullets, and phase through tallhosts. By slashing tallhosts, you temporarily increase your movement speed and you also you apply a tag that changes how your two new tail abilities function. By tagging hosts, you will make Impale hit twice instead of once and make Tail Trip knock hosts down instead of stunning them." flavor_description = "Demonstrate to the talls what 'there is beauty in death' truly symbolizes, then dance upon their graves!" - xeno_icon_state = PRAETORIAN_DANCER + icon_state_prefix = "Dancer" actions_to_remove = list( /datum/action/xeno_action/activable/xeno_spit, diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm index 74dc1b9d6ecd..91ea59661462 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm @@ -3,7 +3,7 @@ name = PRAETORIAN_OPPRESSOR description = "You abandon all of your acid-based abilities, your dash, some speed, and a bit of your slash damage for some resistance against small explosives, slashes that deal extra damage to prone targets, and a powerful hook ability that pulls up to three talls towards you, slows them, and has varying effects depending on how many talls you pull. You also gain a powerful punch that reduces your other abilities' cooldowns, pierces through armor, and does double damage in addition to rooting slowed targets. You can also knock talls back and slow them with your new Tail Lash and quickly grab a tall, slow it, and pull it towards you with your unique Tail Stab." flavor_description = "Dread it. Run from it. The Hive arrives all the same, or, more accurately, you do." - xeno_icon_state = PRAETORIAN_OPPRESSOR + icon_state_prefix = "Oppressor" actions_to_remove = list( /datum/action/xeno_action/activable/tail_stab, diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm index a5d4b757cf6d..2a344523e974 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm @@ -2,7 +2,7 @@ name = PRAETORIAN_VANGUARD description = "You forfeit all of your acid-based abilities and some health for some extra speed and a rechargable shield that can block one attack. Use your Pierce from up to three paces away to stab through talls, while stabbing through several will completely recharge your shield. Use your charge to plow through enemies and use it again to unleash a powerful AoE slash that reaches up to three paces. You also have a Cleave ability, amplified by your shield, which you can toggle to either immobilize or fling a target away." flavor_description = "They are my bulwark against the tallhosts. They are my Vanguard and they shall know no fear." - xeno_icon_state = PRAETORIAN_VANGUARD + icon_state_prefix = "Vanguard" actions_to_remove = list( /datum/action/xeno_action/activable/xeno_spit, diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm index 77f9279d6711..313778baf038 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm @@ -3,7 +3,7 @@ name = PRAETORIAN_WARDEN description = "You trade your acid ball, acid spray, dash, and a small bit of your slash damage and speed to become an effective medic. You gain the ability to emit strong pheromones, an ability that retrieves endangered, knocked-down or sitting allies and pulls them to your location, and you gain an internal hitpoint pool that fills with every slash against your enemies, which can be spent to aid your allies and yourself by healing them or curing their ailments." flavor_description = "Only in death does your sisters' service to the Queen end. They will be untouched by plague or disease; no sickness will blight them." - xeno_icon_state = PRAETORIAN_WARDEN + icon_state_prefix = "Warden" actions_to_remove = list( /datum/action/xeno_action/activable/xeno_spit, diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/berserker.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/berserker.dm index 7b912cc620a0..c12324aa5b2a 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/berserker.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/berserker.dm @@ -2,6 +2,7 @@ name = RAVAGER_BERSERKER description = "You lose your empower, charge, and scissor cut, decrease your health, and sacrifice a bit of your influence under frenzy pheromones to increase your movement speed, slightly increase your armor, and gain a new set of abilities that make you a terrifying melee monster. By slashing, you heal yourself and gain a stack of rage that increases your armor, movement speed, attack speed, and your heals per slash, to a maximum of six rage. Use your new Appehend ability to increase your movement speed and apply a slow on the next target you slash and use your Clothesline ability to fling your target to heal yourself, even more-so if you have a rage stack that will be used up. Finally, use your Eviscerate to unleash a devastating windmill attack that heals you for every host you hit after an immobilizing wind-up." flavor_description = "They shall be my finest warriors. They will rend and tear, crush and butcher, and maim and rage until every tallhost falls." + icon_state_prefix = "Berserker" actions_to_remove = list( /datum/action/xeno_action/onclick/empower, diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm index 4e452fb1a18a..e1d6dc583416 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm @@ -2,6 +2,7 @@ name = RAVAGER_HEDGEHOG description = "You lose your empower, charge, scissor cut and some slash damage, for a bit more explosive resistance, immunity to small explosions, and you gain several new abilities that allow you to become a spiky tank. You build up shards internally over time and also when taking damage that increase your armor's resilience. You can use these shards to power three new abilities: Spike Shield, which gives you a temporary shield that spits bone shards around you when damaged, Fire Spikes, which launches spikes at your target that slows them and does extra damage if they move, and finally, Spike Shed, which launches spikes all around yourself and gives you a temporary speed boost as an escape plan at the cost of all your stored shards and being unable to gain shards for thirty seconds." flavor_description = "They will be of iron will and steely muscle. In great armor shall they be clad, and with the mightiest spikes will they be armed." + icon_state_prefix = "Hedgehog" actions_to_remove = list( /datum/action/xeno_action/onclick/empower, diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm index 8f2ce0ef7150..7b9bafadeb7b 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm @@ -2,7 +2,7 @@ name = RUNNER_ACIDER description = "At the cost of a little bit of your speed and all of your current abilities, you gain a considerable amount of health, some armor, and a new organ that fills with volatile acid over time. Your Tail Stab and slashes apply acid to living lifeforms that slowly burns them, and slashes against targets with acid stacks fill your acid glands. You also gain Corrosive Acid equivalent to that of a boiler that you can deploy more quickly than any other caste, at the cost of a chunk of your acid reserves with each use. Finally, after a twenty second windup, you can force your body to explode, covering everything near you with acid. The more acid you have stored, the more devastating the explosion will be, but during those twenty seconds before detonation you are slowed and give off several warning signals which give talls an opportunity to end you before you can detonate. If you successfully explode, you will reincarnate as a larva again!" flavor_description = "Burn their walls, maim their faces! Your life, for The Hive!" - xeno_icon_state = RUNNER_ACIDER + icon_state_prefix = "Acider" actions_to_remove = list( /datum/action/xeno_action/activable/pounce/runner, diff --git a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm index 278e99a5e118..18f1f892ddfa 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm @@ -6,7 +6,7 @@ /// (OPTIONAL) Flavor text to be shown on purchase. Semi-OOC var/flavor_description /// (OPTIONAL) A custom icon state prefix for xenos who have taken the strain. - var/xeno_icon_state + var/icon_state_prefix /// A list of action typepaths which should be removed when a xeno takes the strain. var/list/actions_to_remove diff --git a/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm b/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm index 0391afd1a4f3..2e4b968d5a59 100644 --- a/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm +++ b/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm @@ -48,7 +48,7 @@ * If that can't be found, returns "Normal" */ /mob/living/carbon/xenomorph/proc/get_strain_icon() - return strain?.xeno_icon_state || "Normal" + return strain?.icon_state_prefix || "Normal" // TODO: Go through xeno/xenoid sprites and remove "Normal", so that this isn't needed. //These don't do much currently. Or anything? Only around for legacy code. From ca7be6fdea49db4de6450930b4e9a50e7e1bd127 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Mon, 12 Feb 2024 18:30:38 +0000 Subject: [PATCH 17/17] And this I'm SURE this was working before, but obviously it broke at some point --- .../living/carbon/xenomorph/strains/castes/carrier/eggsac.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm index 9cc0ab14db8e..a73a7082fbdb 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm @@ -2,6 +2,7 @@ name = CARRIER_EGGSAC description = "In exchange for your ability to store huggers and place traps, you gain larger plasma stores, strong pheromones, and the ability to lay eggs by using your plasma stores. In addition, you can now carry twelve eggs at once and can place eggs one pace further than normal. \n\nYou can also place a small number of fragile eggs on normal weeds. These eggs have a lifetime of five minutes while you remain within 14 tiles. Or one minute if you leave this range." flavor_description = "An egg is always an adventure; the next one may be different." + icon_state_prefix = "Eggsac" actions_to_remove = list( /datum/action/xeno_action/activable/throw_hugger, @@ -17,7 +18,6 @@ behavior_delegate_type = /datum/behavior_delegate/carrier_eggsac /datum/xeno_strain/eggsac/apply_strain(mob/living/carbon/xenomorph/carrier/carrier) - carrier.plasma_types = list(PLASMA_EGG) carrier.phero_modifier += XENO_PHERO_MOD_LARGE // praetorian level pheremones carrier.recalculate_plasma()