diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 7ec2ab8b975e..e2bd868f9a80 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -309,77 +309,6 @@ #define CAN_HOLD_TWO_HANDS 1 #define CAN_HOLD_ONE_HAND 2 -// ------------ // -// 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" -// Ravager strain flags -#define RAVAGER_NORMAL "Normal" -#define RAVAGER_HEDGEHOG "Hedgehog" -#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" - 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', @@ -452,4 +381,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/__DEFINES/xeno.dm b/code/__DEFINES/xeno.dm index 2761bc12acf0..6f6e4eef7c20 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/__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 1f3404f403f2..7d9cd3324067 100644 --- a/code/_globalvars/global_lists.dm +++ b/code/_globalvars/global_lists.dm @@ -166,9 +166,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 mutators -GLOBAL_REFERENCE_LIST_INDEXED_SORTED(xeno_mutator_list, /datum/xeno_mutator, name) - //Xeno hives GLOBAL_LIST_INIT_TYPED(hive_datum, /datum/hive_status, list( XENO_HIVE_NORMAL = new /datum/hive_status(), diff --git a/code/datums/xeno_shields/shield_types/vanguard_shield.dm b/code/datums/xeno_shields/shield_types/vanguard_shield.dm index 5b9eebc04ab8..21d9fb12cfd7 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/behavior = linked_xeno.behavior_delegate + if (istype(behavior)) + behavior.last_combat_time = world.time diff --git a/code/game/world.dm b/code/game/world.dm index 627e245bc4c1..2b7dacee373a 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -125,7 +125,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) @@ -134,7 +134,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..c8d3df91c975 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -130,10 +130,8 @@ 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 + /// The xeno's strain, if they've taken one. + var/datum/xeno_strain/strain = null // Hive-related vars var/datum/hive_status/hive @@ -389,8 +387,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 +657,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(strain) + . += "It has specialized into a [strain.name]." if(iff_tag) . += SPAN_NOTICE("It has an IFF tag sticking out of its carapace.") @@ -693,7 +689,7 @@ selected_ability = null queued_action = null - QDEL_NULL(mutators) + QDEL_NULL(strain) QDEL_NULL(behavior_delegate) built_structures = null @@ -709,18 +705,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 +812,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() @@ -850,8 +839,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 @@ -907,18 +894,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) @@ -1043,7 +1020,7 @@ 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) + 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/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 9326ae78bf9d..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 @@ -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 @@ -201,55 +196,59 @@ 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.")) - 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 + 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.update_icons() - 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 - 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 + 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.update_icons() - X.fortify = FALSE + xeno.mob_size = MOB_SIZE_XENO //no longer knockback immune + xeno.mob_flags |= SQUEEZE_UNDER_VEHICLES + xeno.fortify = FALSE + + apply_modifiers(xeno, fortify_state) + xeno.update_icons() + +/datum/action/xeno_action/activable/fortify/proc/apply_modifiers(mob/living/carbon/xenomorph/xeno, fortify_state) + if(fortify_state) + 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 + 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/xeno, fortify_state) + if(fortify_state) + xeno.armor_deflection_buff += 10 + xeno.armor_explosive_buff += 60 + xeno.ability_speed_modifier += 3 + xeno.damage_modifier -= XENO_DAMAGE_MOD_SMALL + else + 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 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/unconscious_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 24aa94727ca9..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 @@ -1,3 +1,34 @@ +/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) + 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 +47,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 +75,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 +95,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 605fe290b468..647bf7936195 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/behavior = source_xeno.behavior_delegate + if (istype(behavior)) + behavior.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/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 @@ -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/behavior = X.behavior_delegate + if (!istype(behavior)) + return - if (!BD.use_internal_hp_ability(shield_cost)) - return + 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 = 0 + 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 @@ -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/behavior = X.behavior_delegate + if (!istype(behavior)) + 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 (!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 = 0 + 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]!")) to_chat(targetXeno, SPAN_XENOHIGHDANGER("We are healed by [X]!")) @@ -868,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 + 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! @@ -879,13 +862,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/behavior = X.behavior_delegate + if (!istype(behavior)) + return - if (!BD.use_internal_hp_ability(debuff_cost)) - return + if (!behavior.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]!")) @@ -910,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) @@ -954,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/abilities/queen/queen_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_abilities.dm index d245449fa2cf..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,6 +62,10 @@ . = ..() SSticker.OnRoundstart(CALLBACK(src, PROC_REF(apply_queen_build_boost))) +// 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 + /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/Boiler.dm b/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm index 074af92d69fa..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 @@ -50,7 +51,6 @@ 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 @@ -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/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/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm index 2e106743514a..d290b917e945 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm @@ -14,6 +14,9 @@ evasion = XENO_EVASION_NONE 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) throwspeed = SPEED_AVERAGE @@ -75,7 +78,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' @@ -95,18 +97,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() @@ -146,8 +139,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() @@ -184,9 +175,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 @@ -207,6 +195,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) @@ -397,3 +390,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 d2c0b0e40e59..38b1e5816ffe 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,8 +64,6 @@ ) claw_type = CLAW_TYPE_VERY_SHARP - mutation_icon_state = CRUSHER_NORMAL - mutation_type = CRUSHER_NORMAL icon_xeno = 'icons/mob/xenos/crusher.dmi' icon_xenonid = 'icons/mob/xenonids/crusher.dmi' @@ -281,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 8ec53d51046e..a63bafb5d2b0 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,9 +52,6 @@ /datum/action/xeno_action/onclick/tacmap, ) - mutation_icon_state = DEFENDER_NORMAL - mutation_type = DEFENDER_NORMAL - icon_xeno = 'icons/mob/xenos/defender.dmi' icon_xenonid = 'icons/mob/xenonids/defender.dmi' @@ -90,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/Drone.dm b/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm index c4c9b11b37e4..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,7 +74,6 @@ /mob/living/carbon/xenomorph/proc/rename_tunnel, /mob/living/carbon/xenomorph/proc/set_hugger_reserve_for_morpher, ) - mutation_type = DRONE_NORMAL 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..4d164c289dc1 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm @@ -9,6 +9,9 @@ caste_desc = "Ewwww, that's disgusting!" 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 @@ -55,7 +58,6 @@ inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, ) - mutation_type = "Normal" icon_xeno = 'icons/mob/xenos/facehugger.dmi' icon_xenonid = 'icons/mob/xenonids/facehugger.dmi' @@ -74,34 +76,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,34 +219,9 @@ else . += "Lifetime Hugs: [total_facehugs]" +/datum/behavior_delegate/facehugger_base + name = "Base Facehugger Behavior Delegate" -/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) +/datum/behavior_delegate/facehugger_base/on_life() + 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/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/Hivelord.dm b/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm index b00ec2a9c1eb..ee4157a67d84 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, ) - mutation_type = HIVELORD_NORMAL - icon_xeno = 'icons/mob/xenos/hivelord.dmi' icon_xenonid = 'icons/mob/xenonids/hivelord.dmi' @@ -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/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/Lurker.dm b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm index 469b9a78d063..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, ) - mutation_type = LURKER_NORMAL 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..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,7 +52,6 @@ mob_size = MOB_SIZE_BIG drag_delay = 6 //pulling a big dead xeno is hard tier = 3 - mutation_type = PRAETORIAN_NORMAL base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, 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 d89e8572caff..f5207e6abf30 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 @@ -519,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 @@ -936,7 +934,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 = "[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/castes/Ravager.dm b/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm index 6d19a1b8feec..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,7 +49,6 @@ tier = 3 pixel_x = -16 old_x = -16 - mutation_type = RAVAGER_NORMAL 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 3a23afc145d1..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, ) - mutation_type = RUNNER_NORMAL icon_xeno = 'icons/mob/xenos/runner.dmi' icon_xenonid = 'icons/mob/xenonids/runner.dmi' @@ -77,6 +78,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/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/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/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/egg_item.dm b/code/modules/mob/living/carbon/xenomorph/egg_item.dm index 1bc41b881129..f349b8acfb8d 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, 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] 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) diff --git a/code/modules/mob/living/carbon/xenomorph/hive_status.dm b/code/modules/mob/living/carbon/xenomorph/hive_status.dm index bb67eaa055a8..4b6c0f4b279e 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.get_strain_name(), "ref" = "\ref[X]" ) 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/strains/defender/steel_crest.dm b/code/modules/mob/living/carbon/xenomorph/mutators/strains/defender/steel_crest.dm deleted file mode 100644 index 957e7f1b8926..000000000000 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/defender/steel_crest.dm +++ /dev/null @@ -1,44 +0,0 @@ -/datum/xeno_mutator/steel_crest - name = "STRAIN: Defender - Steel Crest" - 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( - /datum/action/xeno_action/onclick/tail_sweep, - ) - mutator_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) - . = ..() - 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 - 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.mutation_icon_state || bound_xeno.mutation_type] 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" - return TRUE 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 87% 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 index c14d2c6773cf..e6c8061bd0fe 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/boiler/trapper.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm @@ -1,40 +1,33 @@ - -/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) - . = ..() - if(. == 0) - return +/datum/xeno_strain/trapper/apply_strain(mob/living/carbon/xenomorph/boiler/boiler) + 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 @@ -42,12 +35,6 @@ 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) - - /datum/behavior_delegate/boiler_trapper name = "Boiler Trapper Behavior Delegate" 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 86% 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 index 10cbc29f51b0..a73a7082fbdb 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/carrier/eggsac.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/carrier/eggsac.dm @@ -1,48 +1,36 @@ -/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( + icon_state_prefix = "Eggsac" + + 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) - . = ..() - if (!.) - return - var/mob/living/carbon/xenomorph/carrier/carrier = mutator_set.xeno - if(!istype(carrier)) - return FALSE +/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.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) - return TRUE + carrier.update_eggsac_overlays() #define EGGSAC_OFF_WEED_EGGCAP 4 #define EGGSAC_EGG_SUSTAIN_DISTANCE 14 @@ -60,6 +48,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] @@ -87,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/mutators/strains/crusher/charger.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/crusher/charger.dm similarity index 96% 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 index 17b5cf62052c..84877b43571e 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/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,26 @@ #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) - . = ..() - if (. == 0) - return + behavior_delegate_type = /datum/behavior_delegate/crusher_charger - var/mob/living/carbon/xenomorph/crusher/crusher = mutator_set.xeno - crusher.mutation_type = 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 @@ -49,10 +39,6 @@ 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() /datum/behavior_delegate/crusher_charger @@ -83,7 +69,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 +629,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 new file mode 100644 index 000000000000..f84566e9c841 --- /dev/null +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/defender/steel_crest.dm @@ -0,0 +1,22 @@ +/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." + icon_state_prefix = "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, + ) + +/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() 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 93% 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 index da354b465331..d54d268f12d9 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/drone/gardener.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/gardener.dm @@ -1,45 +1,41 @@ -/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. You can use Resin Surge to speed up the growth of your fruits." 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, /datum/action/xeno_action/activable/transfer_plasma, ) - keystone = TRUE - behavior_delegate_type = /datum/behavior_delegate/drone_gardener -/datum/xeno_mutator/gardener/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) - . = ..() - if (. == 0) - return + behavior_delegate_type = /datum/behavior_delegate/drone_gardener - 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) +/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, + /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)" @@ -368,9 +364,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/mutators/strains/drone/healer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm similarity index 90% 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 index 86f50b47e080..0fcbb2ecf09a 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/drone/healer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/drone/healer.dm @@ -1,18 +1,17 @@ -/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( + icon_state_prefix = "Healer" + + 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 +19,20 @@ /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 - -/datum/xeno_mutator/healer/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) - . = ..() - if (. == 0) - return + behavior_delegate_type = /datum/behavior_delegate/drone_healer - var/mob/living/carbon/xenomorph/drone/drone = mutator_set.xeno - drone.mutation_type = 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 + 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 @@ -123,13 +110,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) @@ -144,7 +132,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) @@ -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..7fba30b6f352 --- /dev/null +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/facehugger/watcher.dm @@ -0,0 +1,21 @@ +/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, + ) + + 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) + +// 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/mutators/strains/hivelord/resin_whisperer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/resin_whisperer.dm similarity index 80% 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 index 3653209b78f2..8bdcd1311f94 100644 --- 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 @@ -1,41 +1,30 @@ -/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( + icon_state_prefix = "Resin Whisperer" + + 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) - . = ..() - if(!.) - return - var/mob/living/carbon/xenomorph/hivelord/hivelord = mutator_set.xeno +/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 + 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 @@ -68,12 +57,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 @@ -115,6 +101,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" 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 71% 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 index 72214d06332e..1df49092e783 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/lurker/vampire.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/lurker/vampire.dm @@ -1,31 +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( + icon_state_prefix = "Vampire" + + 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) - . = ..() - if (. == FALSE) - return - - var/mob/living/carbon/xenomorph/lurker/lurker = mutator_set.xeno +/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 @@ -34,7 +25,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/mutators/strains/praetorian/dancer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm similarity index 68% 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 index a21f549ea8cd..f9a5dbedb614 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/praetorian/dancer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/dancer.dm @@ -1,44 +1,31 @@ -/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( + icon_state_prefix = "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) - . = ..() - 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) + behavior_delegate_type = /datum/behavior_delegate/praetorian_dancer - praetorian.recalculate_everything() +/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) + 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/mutators/strains/praetorian/oppressor.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/oppressor.dm similarity index 67% 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 index 4beaedf8d6a8..91ea59661462 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/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( + icon_state_prefix = "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,24 @@ /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) - . = ..() - 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 - - mutator_update_actions(praetorian) - - mutator_set.recalculate_actions(description, flavor_description) + behavior_delegate_type = /datum/behavior_delegate/oppressor_praetorian - apply_behavior_holder(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 + prae.speed_modifier += XENO_SPEED_SLOWMOD_TIER_5 + prae.plasma_types = list(PLASMA_NEUROTOXIN, PLASMA_CHITIN) + prae.claw_type = CLAW_TYPE_SHARP - 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 +45,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/mutators/strains/praetorian/vanguard.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm similarity index 80% 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 index d5ca8c4d6aad..2a344523e974 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/praetorian/vanguard.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/vanguard.dm @@ -1,43 +1,31 @@ -/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( + icon_state_prefix = "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) - . = ..() - 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() + behavior_delegate_type = /datum/behavior_delegate/praetorian_vanguard - praetorian.mutation_icon_state = PRAETORIAN_VANGUARD - praetorian.mutation_type = 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 - apply_behavior_holder(praetorian) + prae.recalculate_everything() /datum/behavior_delegate/praetorian_vanguard name = "Praetorian Vanguard Behavior Delegate" @@ -103,8 +91,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/mutators/strains/praetorian/warden.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm similarity index 80% 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 index d9946fb9ec64..313778baf038 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/praetorian/warden.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/praetorian/warden.dm @@ -1,19 +1,18 @@ -/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( + icon_state_prefix = "Warden" + + 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/onclick/tacmap, ) - mutator_actions_to_add = list( + actions_to_add = list( /datum/action/xeno_action/onclick/emit_pheromones, /datum/action/xeno_action/activable/xeno_spit, /datum/action/xeno_action/activable/spray_acid/prae_warden, @@ -22,28 +21,15 @@ /datum/action/xeno_action/onclick/prae_switch_heal_type, /datum/action/xeno_action/onclick/tacmap, ) - behavior_delegate_type = /datum/behavior_delegate/praetorian_warden - keystone = TRUE - -/datum/xeno_mutator/praetorian_warden/apply_mutator(datum/mutator_set/individual_mutators/mutator_set) - . = ..() - if (. == 0) - return - var/mob/living/carbon/xenomorph/praetorian/praetorian = mutator_set.xeno + behavior_delegate_type = /datum/behavior_delegate/praetorian_warden +/datum/xeno_strain/warden/apply_strain(mob/living/carbon/xenomorph/praetorian/prae) // 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) + prae.speed_modifier += XENO_SPEED_SLOWMOD_TIER_5 + prae.damage_modifier -= XENO_DAMAGE_MOD_SMALL - praetorian.recalculate_everything() - - 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" @@ -58,7 +44,6 @@ var/internal_hitpoints = 0 var/transferred_healing = 0 - /datum/behavior_delegate/praetorian_warden/append_to_stat() . = list() . += "Energy Reserves: [internal_hitpoints]/[internal_hitpoints_max]" 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 90% 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 index 7881c9aa75f1..c12324aa5b2a 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/ravager/berserker.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/berserker.dm @@ -1,39 +1,28 @@ -/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( + icon_state_prefix = "Berserker" + + 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) - . = ..() - if (. == 0) - return + behavior_delegate_type = /datum/behavior_delegate/ravager_berserker - var/mob/living/carbon/xenomorph/ravager/ravager = mutator_set.xeno - ravager.mutation_type = 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 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/mutators/strains/ravager/hedgehog.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm similarity index 87% 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 index 913883549fba..e1d6dc583416 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/ravager/hedgehog.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/ravager/hedgehog.dm @@ -1,41 +1,28 @@ -/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( + icon_state_prefix = "Hedgehog" + + 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) - . = ..() - if (. == 0) - return - var/mob/living/carbon/xenomorph/ravager/ravager = mutator_set.xeno + behavior_delegate_type = /datum/behavior_delegate/ravager_hedgehog - ravager.mutation_type = 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 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/mutators/strains/runner/acid.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm similarity index 90% 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 index 490e5ca36cba..7b9bafadeb7b 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/runner/acid.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/runner/acid.dm @@ -1,37 +1,27 @@ -/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( + icon_state_prefix = "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) - . = ..() - if (. == 0) - return + behavior_delegate_type = /datum/behavior_delegate/runner_acider - var/mob/living/carbon/xenomorph/runner/runner = mutator_set.xeno - runner.mutation_icon_state = RUNNER_ACIDER - runner.mutation_type = 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 - 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/strains/xeno_strain.dm b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm new file mode 100644 index 000000000000..18f1f892ddfa --- /dev/null +++ b/code/modules/mob/living/carbon/xenomorph/strains/xeno_strain.dm @@ -0,0 +1,131 @@ +/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/icon_state_prefix + + /// 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 + +/** + * 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) + SHOULD_NOT_OVERRIDE(TRUE) + + xeno.strain = src + + // 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() + + apply_strain(xeno) + + xeno.update_icons() + xeno.hive.hive_ui.update_xeno_info() + + // 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 + +/** + * 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 + + +/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 + + // 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") + 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. + if(!can_take_strain()) + return + // Show the user the strain's description, and double check that they want it. + 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 + + // Create the strain datum and apply it to the xeno. + var/datum/xeno_strain/strain_instance = new chosen_strain() + 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]'") + +/// 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 + + 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 + + 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..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 = "[mutation_type] [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 = "[mutation_icon_state || mutation_type] [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))) diff --git a/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm b/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm index 7324a3af6892..2e4b968d5a59 100644 --- a/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm +++ b/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm @@ -34,6 +34,23 @@ 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 can't be found, returns "Normal" + */ +/mob/living/carbon/xenomorph/proc/get_strain_icon() + 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. /mob/living/carbon/xenomorph/is_mob_restrained() return 0 @@ -58,4 +75,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_icon()] [caste.caste_type] Running" diff --git a/colonialmarines.dme b/colonialmarines.dme index 42e46e15ef3c..fdec2227d2bd 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -1969,7 +1969,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" @@ -2049,23 +2048,24 @@ #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\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" +#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" diff --git a/icons/mob/xenos/burrower.dmi b/icons/mob/xenos/burrower.dmi index f546776e6b27..c54684e61bc9 100644 Binary files a/icons/mob/xenos/burrower.dmi and b/icons/mob/xenos/burrower.dmi differ