diff --git a/code/__DEFINES/dcs/signals/signals.dm b/code/__DEFINES/dcs/signals/signals.dm index a8b1decc85325..c6bfe47ffbf81 100644 --- a/code/__DEFINES/dcs/signals/signals.dm +++ b/code/__DEFINES/dcs/signals/signals.dm @@ -729,6 +729,11 @@ #define COMSIG_XENOMORPH_LEAP_BUMP "xenomorph_leap_bump" //from /mob/living/carbon/xenomorph/bump +// Xeno upgrade chambers +#define COMSIG_UPGRADE_CHAMBER_SURVIVAL "upgrade_chamber_survival" +#define COMSIG_UPGRADE_CHAMBER_ATTACK "upgrade_chamber_attack" +#define COMSIG_UPGRADE_CHAMBER_UTILITY "upgrade_chamber_utility" + //human signals #define COMSIG_CLICK_QUICKEQUIP "click_quickequip" diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 0cd074464345b..38fb91e269d6e 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -589,12 +589,13 @@ GLOBAL_LIST_INIT(layers_to_offset, list( #define CASTE_STAGGER_RESISTANT (1<<15) //Resistant to some forms of stagger, such as projectiles #define CASTE_HAS_WOUND_MASK (1<<16) //uses an alpha mask for wounded states #define CASTE_EXCLUDE_STRAINS (1<<17) // denotes castes/basetypes that should be excluded from being evoable as a strain +#define CASTE_NO_MUTATION (1<<18) // Xenos are excluded from getting any mutations. // Xeno defines that affect evolution, considering making a new var for these -#define CASTE_LEADER_TYPE (1<<16) //Whether we are a leader type caste, such as the queen, shrike or ?king?, and is affected by queen ban and playtime restrictions -#define CASTE_CANNOT_EVOLVE_IN_CAPTIVITY (1<<17) //Whether we cannot evolve in the research lab -#define CASTE_REQUIRES_FREE_TILE (1<<18) //Whether we require a free tile to evolve -#define CASTE_INSTANT_EVOLUTION (1<<19) //Whether we require no evolution progress to evolve to this caste +#define CASTE_LEADER_TYPE (1<<19) //Whether we are a leader type caste, such as the queen, shrike or ?king?, and is affected by queen ban and playtime restrictions +#define CASTE_CANNOT_EVOLVE_IN_CAPTIVITY (1<<20) //Whether we cannot evolve in the research lab +#define CASTE_REQUIRES_FREE_TILE (1<<21) //Whether we require a free tile to evolve +#define CASTE_INSTANT_EVOLUTION (1<<22) //Whether we require no evolution progress to evolve to this caste #define CASTE_CAN_HOLD_FACEHUGGERS (1<<0) #define CASTE_CAN_BE_QUEEN_HEALED (1<<1) diff --git a/code/__DEFINES/mode.dm b/code/__DEFINES/mode.dm index ac92848b50f90..7b7c4bea09346 100644 --- a/code/__DEFINES/mode.dm +++ b/code/__DEFINES/mode.dm @@ -50,6 +50,7 @@ #define MODE_ALLOW_XENO_QUICKBUILD (1<<14) #define MODE_DISALLOW_RAILGUN (1<<15) #define MODE_FORCE_CUSTOMSQUAD_UI (1<<16) +#define MODE_BIOMASS_POINTS (1<<17) #define MODE_INFESTATION_X_MAJOR "Xenomorph Major Victory" #define MODE_INFESTATION_M_MAJOR "Marine Major Victory" diff --git a/code/__DEFINES/movespeed_modification.dm b/code/__DEFINES/movespeed_modification.dm index b8e4deeb20b35..b72ed7d134eae 100644 --- a/code/__DEFINES/movespeed_modification.dm +++ b/code/__DEFINES/movespeed_modification.dm @@ -32,6 +32,7 @@ #define MOVESPEED_ID_WARLOCK_CHANNELING "WARLOCK_CHANNELING" #define MOVESPEED_ID_XENO_DREAD "DREADXENO" #define MOVESPEED_ID_BEHEMOTH_PRIMAL_WRATH "BEHEMOTH_PRIMAL_WRATH" +#define MOVESPEED_ID_CELERITY_BUFF "UPGRADE_CHAMBER_CELERITY_BUFF" #define MOVESPEED_ID_PRAETORIAN_DANCER_DODGE_SPEED "PRAETORIAN_DANCER_DODGE_SPEED" #define MOVESPEED_ID_SIMPLEMOB_VARSPEED "SIMPLEMOB_VARSPEED_MODIFIER" diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 64fb57c8ba1af..961f191cfc0c6 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -39,6 +39,24 @@ #define STATUS_EFFECT_DRAIN_SURGE /datum/status_effect/drain_surge +#define STATUS_EFFECT_UPGRADE_CARAPACE /datum/status_effect/mutation_upgrade/carapace + +#define STATUS_EFFECT_UPGRADE_REGENERATION /datum/status_effect/mutation_upgrade/regeneration + +#define STATUS_EFFECT_UPGRADE_VAMPIRISM /datum/status_effect/mutation_upgrade/vampirism + +#define STATUS_EFFECT_UPGRADE_CELERITY /datum/status_effect/mutation_upgrade/celerity + +#define STATUS_EFFECT_UPGRADE_ADRENALINE /datum/status_effect/mutation_upgrade/adrenaline + +#define STATUS_EFFECT_UPGRADE_CRUSH /datum/status_effect/mutation_upgrade/crush + +#define STATUS_EFFECT_UPGRADE_FOCUS /datum/status_effect/mutation_upgrade/focus + +#define STATUS_EFFECT_UPGRADE_PHERO /datum/status_effect/mutation_upgrade/pheromones + +#define STATUS_EFFECT_UPGRADE_CAMOUFLAGE /datum/status_effect/mutation_upgrade/camouflage + #define STATUS_EFFECT_MINDMEND /datum/status_effect/mindmeld #define STATUS_EFFECT_REKNIT_FORM /datum/status_effect/reknit_form diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 856b0b64d65fc..817045e3e490f 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -80,6 +80,7 @@ #define SPECIES_TRAIT "species" // /datum/species innate trait #define CRYOPOD_TRAIT "cryopod" #define XENO_TRAIT "xeno" +#define XENO_BUFF_TRAIT "xenobuff" #define ARMOR_TRAIT "armor" #define STAT_TRAIT "stat" #define NECKGRAB_TRAIT "neckgrab" @@ -187,7 +188,8 @@ #define TRAIT_TANK_DESANT "tank_desant" ///Builds things better #define TRAIT_SUPERIOR_BUILDER "superior_builder" - +/// Does not ping tactical sensor +#define TRAIT_TACTICAL_SENSOR_IMMUNE "tactical_sensor_immune" /// Prevents usage of manipulation appendages (picking, holding or using items, manipulating storage). #define TRAIT_HANDS_BLOCKED "handsblocked" diff --git a/code/__DEFINES/xeno.dm b/code/__DEFINES/xeno.dm index 87a0bec6b1ff7..458b0f832203c 100644 --- a/code/__DEFINES/xeno.dm +++ b/code/__DEFINES/xeno.dm @@ -92,6 +92,14 @@ GLOBAL_LIST_INIT(defiler_toxin_type_list, list( /datum/reagent/toxin/xeno_ozelomelyn, )) +//List of Defiler toxin images +GLOBAL_LIST_INIT(defiler_toxin_images_list, list( + DEFILER_OZELOMELYN = image('icons/Xeno/actions/defiler.dmi', icon_state = DEFILER_OZELOMELYN), + DEFILER_HEMODILE = image('icons/Xeno/actions/defiler.dmi', icon_state = DEFILER_HEMODILE), + DEFILER_TRANSVITOX = image('icons/Xeno/actions/defiler.dmi', icon_state = DEFILER_TRANSVITOX), + DEFILER_NEUROTOXIN = image('icons/Xeno/actions/defiler.dmi', icon_state = DEFILER_NEUROTOXIN) +)) + //List of toxins improving defile's damage GLOBAL_LIST_INIT(defiler_toxins_typecache_list, typecacheof(list( /datum/reagent/toxin/xeno_ozelomelyn, @@ -210,3 +218,31 @@ GLOBAL_LIST_INIT(xeno_ai_spawnable, list( /// Life runs every 2 seconds, but we don't want to multiply all healing by 2 due to seconds_per_tick #define XENO_PER_SECOND_LIFE_MOD 0.5 + +// Mutations +GLOBAL_DATUM_INIT(mutation_selector, /datum/mutation_datum, new) + +GLOBAL_LIST_INIT(mutation_upgrades_buyable, list( + /datum/mutation_upgrade/survival/carapace, + /datum/mutation_upgrade/survival/regeneration, + /datum/mutation_upgrade/survival/vampirism, + /datum/mutation_upgrade/attack/celerity, + /datum/mutation_upgrade/attack/adrenaline, + /datum/mutation_upgrade/attack/crush, + /datum/mutation_upgrade/utility/focus, + /datum/mutation_upgrade/utility/pheromones, + /datum/mutation_upgrade/utility/camouflage +)) + +#define MUTATION_CATEGORY_SURVIVAL "Survival" +#define MUTATION_CATEGORY_ATTACK "Attack" +#define MUTATION_CATEGORY_UTILITY "Utility" + +#define MUTATION_STRUCTURE_CHAMBER "shell" +#define MUTATION_STRUCTURE_SPUR "spur" +#define MUTATION_STRUCTURE_VEIL "veil" + +#define XENO_UPGRADE_BIOMASS_COST_T1 15 +#define XENO_UPGRADE_BIOMASS_COST_T2 20 +#define XENO_UPGRADE_BIOMASS_COST_T3 25 +#define XENO_UPGRADE_BIOMASS_COST_T4 30 diff --git a/code/controllers/subsystem/points.dm b/code/controllers/subsystem/points.dm index a5b4bb0903c8e..3f50c567b5e93 100644 --- a/code/controllers/subsystem/points.dm +++ b/code/controllers/subsystem/points.dm @@ -16,6 +16,8 @@ SUBSYSTEM_DEF(points) var/list/xeno_strategic_points_by_hive = list() ///Assoc list of xeno tactical points: xeno_tactical_points_by_hive["hivenum"] var/list/xeno_tactical_points_by_hive = list() + ///Assoc list of xeno biomass points: xeno_biomass_points_by_hive["hivenum"] + var/list/xeno_biomass_points_by_hive = list() var/ordernum = 1 //order number given to next order @@ -92,6 +94,13 @@ SUBSYSTEM_DEF(points) return xeno_tactical_points_by_hive[hivenumber] += amount + +///Add amount of tactical psy points to the selected hive only if the gamemode support biomass +/datum/controller/subsystem/points/proc/add_biomass_points(hivenumber, amount) + if(!CHECK_BITFIELD(SSticker.mode.round_type_flags, MODE_BIOMASS_POINTS)) + return + xeno_biomass_points_by_hive[hivenumber] = clamp(xeno_biomass_points_by_hive[hivenumber] + amount, 0, 500) + /datum/controller/subsystem/points/proc/approve_request(datum/supply_order/O, mob/living/user) var/cost = 0 for(var/i in O.pack) diff --git a/code/datums/gamemodes/nuclear_war.dm b/code/datums/gamemodes/nuclear_war.dm index 2ddbee953f332..f69493f783728 100644 --- a/code/datums/gamemodes/nuclear_war.dm +++ b/code/datums/gamemodes/nuclear_war.dm @@ -2,7 +2,7 @@ name = "Nuclear War" config_tag = "Nuclear War" silo_scaling = 2 - round_type_flags = MODE_INFESTATION|MODE_LATE_OPENING_SHUTTER_TIMER|MODE_XENO_RULER|MODE_PSY_POINTS|MODE_PSY_POINTS_ADVANCED|MODE_DEAD_GRAB_FORBIDDEN|MODE_HIJACK_POSSIBLE|MODE_SILO_RESPAWN|MODE_SILOS_SPAWN_MINIONS|MODE_ALLOW_XENO_QUICKBUILD|MODE_FORCE_CUSTOMSQUAD_UI + round_type_flags = MODE_INFESTATION|MODE_LATE_OPENING_SHUTTER_TIMER|MODE_XENO_RULER|MODE_PSY_POINTS|MODE_PSY_POINTS_ADVANCED|MODE_DEAD_GRAB_FORBIDDEN|MODE_HIJACK_POSSIBLE|MODE_SILO_RESPAWN|MODE_SILOS_SPAWN_MINIONS|MODE_ALLOW_XENO_QUICKBUILD|MODE_FORCE_CUSTOMSQUAD_UI|MODE_BIOMASS_POINTS xeno_abilities_flags = ABILITY_NUCLEARWAR valid_job_types = list( /datum/job/terragov/command/captain = 1, diff --git a/code/datums/status_effects/xeno_buffs.dm b/code/datums/status_effects/xeno_buffs.dm index 630fd1dfde48d..3490750cb1dbc 100644 --- a/code/datums/status_effects/xeno_buffs.dm +++ b/code/datums/status_effects/xeno_buffs.dm @@ -870,3 +870,485 @@ xeno_owner.xeno_melee_damage_modifier -= modifier xeno_owner.remove_filter("frenzy_screech_outline") return ..() + +// *************************************** +// *********** Upgrade Chambers Buffs +// *************************************** +/datum/status_effect/mutation_upgrade + /// Owner typed as an xenomorph. + var/mob/living/carbon/xenomorph/buff_owner + /// The structure to base chamber_scaling on. + var/chamber_structure + /// The amount of times to multiply the main effect by. + var/chamber_scaling = 0 + +/datum/status_effect/mutation_upgrade/on_apply() + if(!isxeno(owner)) + return FALSE + buff_owner = owner + update_chamber_scaling() + return TRUE + +/// Sets the chamber_scaling based on the amount of chambers in the xeno's hive. +/datum/status_effect/mutation_upgrade/proc/update_chamber_scaling() + switch(chamber_structure) + if(MUTATION_STRUCTURE_CHAMBER) + chamber_scaling = length(buff_owner.hive?.shell_chambers) + if(MUTATION_STRUCTURE_SPUR) + chamber_scaling = length(buff_owner.hive?.spur_chambers) + if(MUTATION_STRUCTURE_VEIL) + chamber_scaling = length(buff_owner.hive?.veil_chambers) + +// *************************************** +// *********** Upgrade Chambers Buffs - Survival +// *************************************** +/atom/movable/screen/alert/status_effect/carapace + name = "Carapace" + desc = "Armor increased." + icon_state = "xenobuff_carapace" + +/datum/status_effect/mutation_upgrade/carapace + id = "mutation_upgrade_carapace" + alert_type = /atom/movable/screen/alert/status_effect/carapace + chamber_structure = MUTATION_STRUCTURE_CHAMBER + /// The amount of hard armor given. + var/armor_buff_per_chamber = 1 + +/datum/status_effect/mutation_upgrade/carapace/on_apply() + if(!..()) + return FALSE + RegisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_SURVIVAL, PROC_REF(update_buff)) + buff_owner.hard_armor = buff_owner.hard_armor.modifyAllRatings(armor_buff_per_chamber * chamber_scaling) + return TRUE + +/datum/status_effect/mutation_upgrade/carapace/on_remove() + UnregisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_SURVIVAL) + buff_owner.hard_armor = buff_owner.hard_armor.modifyAllRatings(-armor_buff_per_chamber * chamber_scaling) + return ..() + +/// Sets the chamber_scaling to the amount of active survival chambers and adjusts soft armor accordingly. +/datum/status_effect/mutation_upgrade/carapace/proc/update_buff() + SIGNAL_HANDLER + buff_owner.hard_armor = buff_owner.hard_armor.modifyAllRatings(armor_buff_per_chamber * (length(buff_owner.hive.shell_chambers) - chamber_scaling)) + update_chamber_scaling() + + +// *************************************** +// *************************************** +// *************************************** +/atom/movable/screen/alert/status_effect/regeneration + name = "Regeneration" + desc = "Regeneration increased." + icon_state = "xenobuff_regeneration" + +/datum/status_effect/mutation_upgrade/regeneration + id = "mutation_upgrade_regeneration" + alert_type = /atom/movable/screen/alert/status_effect/regeneration + chamber_structure = MUTATION_STRUCTURE_CHAMBER + /// The amount of max health to be regenerated everytime the proc 'heal_wounds' is called. + var/health_regen_per_chamber = 0.008 // 0.8% + /// The amount of sunder to be regenerated everytime the proc 'heal_wounds' is called. + var/sunder_regen_per_chamber = 0.166 + +/datum/status_effect/mutation_upgrade/regeneration/on_apply() + if(!..()) + return FALSE + RegisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_SURVIVAL, PROC_REF(update_buff)) + RegisterSignal(buff_owner, COMSIG_XENOMORPH_HEALTH_REGEN, PROC_REF(on_heal_wounds)) + return TRUE + +/datum/status_effect/mutation_upgrade/regeneration/on_remove() + UnregisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_SURVIVAL) + UnregisterSignal(buff_owner, COMSIG_XENOMORPH_HEALTH_REGEN) + return ..() + +/// Sets the chamber_scaling to the amount of active survival chambers. +/datum/status_effect/mutation_upgrade/regeneration/proc/update_buff() + SIGNAL_HANDLER + update_chamber_scaling() + +/// Heals the xenomorph's health and sunder based on assigned variables. +/datum/status_effect/mutation_upgrade/regeneration/proc/on_heal_wounds(mob/living/carbon/xenomorph/source_xenomorph, heal_data, seconds_per_tick) + SIGNAL_HANDLER + if(!chamber_scaling) + return + var/health_amount = buff_owner.maxHealth * health_regen_per_chamber * chamber_scaling + var/sunder_amount = -sunder_regen_per_chamber * chamber_scaling + HEAL_XENO_DAMAGE(buff_owner, health_amount, FALSE) + buff_owner.adjust_sunder(sunder_amount) + +// *************************************** +// *************************************** +// *************************************** +/atom/movable/screen/alert/status_effect/vampirism + name = "Vampirism" + desc = "Leech from attacks." + icon_state = "xenobuff_vampirism" + +/datum/status_effect/mutation_upgrade/vampirism + id = "mutation_upgrade_vampirism" + alert_type = /atom/movable/screen/alert/status_effect/vampirism + chamber_structure = MUTATION_STRUCTURE_CHAMBER + /// The percentage of damage dealt to be healed after hitting an alive human. + var/leech_buff_per_chamber = 0.1 + +/datum/status_effect/mutation_upgrade/vampirism/on_apply() + if(!..()) + return FALSE + RegisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_SURVIVAL, PROC_REF(update_buff)) + RegisterSignal(buff_owner, COMSIG_XENOMORPH_POSTATTACK_LIVING, PROC_REF(on_postattack)) + return TRUE + +/datum/status_effect/mutation_upgrade/vampirism/on_remove() + UnregisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_SURVIVAL) + UnregisterSignal(buff_owner, COMSIG_XENOMORPH_POSTATTACK_LIVING) + return ..() + +/// Sets the chamber_scaling to the amount of active survival chambers. +/datum/status_effect/mutation_upgrade/vampirism/proc/update_buff() + SIGNAL_HANDLER + update_chamber_scaling() + +/// Heals the xenomorph for hitting a non-dead human by a percentage of their max health. +/datum/status_effect/mutation_upgrade/vampirism/proc/on_postattack(datum/source, mob/living/target, damage_done) + SIGNAL_HANDLER + if(target.stat == DEAD || !ishuman(target)) + return + var/health_amount = damage_done * leech_buff_per_chamber * chamber_scaling + HEAL_XENO_DAMAGE(buff_owner, health_amount, FALSE) + +// *************************************** +// *********** Upgrade Chambers Buffs - Attack +// *************************************** +/atom/movable/screen/alert/status_effect/celerity + name = "Celerity" + desc = "Run faster." + icon_state = "xenobuff_attack" + +/datum/status_effect/mutation_upgrade/celerity + id = "mutation_upgrade_celerity" + alert_type = /atom/movable/screen/alert/status_effect/celerity + chamber_structure = MUTATION_STRUCTURE_SPUR + /// The amount of movement speed the owner get. + var/speed_buff_per_chamber = 0.05 + +/datum/status_effect/mutation_upgrade/celerity/on_apply() + if(!..()) + return FALSE + RegisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_ATTACK, PROC_REF(update_buff)) + buff_owner.add_movespeed_modifier(MOVESPEED_ID_CELERITY_BUFF, TRUE, 0, NONE, TRUE, -speed_buff_per_chamber * chamber_scaling) + return TRUE + +/datum/status_effect/mutation_upgrade/celerity/on_remove() + UnregisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_ATTACK) + buff_owner.remove_movespeed_modifier(MOVESPEED_ID_CELERITY_BUFF) + return ..() + +/// Sets the chamber_scaling to the amount of active spur chambers and adjusts movement speed accordingly. +/datum/status_effect/mutation_upgrade/celerity/proc/update_buff() + SIGNAL_HANDLER + update_chamber_scaling() + buff_owner.add_movespeed_modifier(MOVESPEED_ID_CELERITY_BUFF, TRUE, 0, NONE, TRUE, -speed_buff_per_chamber * chamber_scaling) + +// *************************************** +// *************************************** +// *************************************** +/atom/movable/screen/alert/status_effect/adrenaline + name = "Adrenaline" + desc = "Regenerate plasma." + icon_state = "xenobuff_attack" + +/datum/status_effect/mutation_upgrade/adrenaline + id = "mutation_upgrade_adrenaline" + alert_type = /atom/movable/screen/alert/status_effect/adrenaline + chamber_structure = MUTATION_STRUCTURE_SPUR + /// The amount of plasma to regenerate based on their caste's plasma regeneration. + var/plasma_regen_buff_per_chamber = 0.1 // 10% + /// The amount of plasma to regenerate based on their caste's maximum plasma. + var/plasma_maximum_buff_per_chamber = 0.01 // 1% + +/datum/status_effect/mutation_upgrade/adrenaline/on_apply() + if(!..()) + return FALSE + RegisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_ATTACK, PROC_REF(update_buff)) + RegisterSignal(buff_owner, COMSIG_XENOMORPH_PLASMA_REGEN, PROC_REF(on_plasma_regen)) + return TRUE + +/datum/status_effect/mutation_upgrade/adrenaline/on_remove() + UnregisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_ATTACK) + UnregisterSignal(buff_owner, COMSIG_XENOMORPH_PLASMA_REGEN) + return ..() + +/// Sets the chamber_scaling to the amount of active spur chambers. +/datum/status_effect/mutation_upgrade/adrenaline/proc/update_buff() + SIGNAL_HANDLER + update_chamber_scaling() + +/// Gives the xenomorph more plasma (according to their plasma regeneration and adjusted maximum) everytime they are suppose to regen plasma up to their adjusted maximum. +/datum/status_effect/mutation_upgrade/adrenaline/proc/on_plasma_regen(mob/living/carbon/xenomorph/source_xenomorph, plasma_mod, seconds_per_tick) + SIGNAL_HANDLER + if(!chamber_scaling) + return + + var/adjusted_plasma_maximum = buff_owner.xeno_caste.plasma_max * buff_owner.xeno_caste.plasma_regen_limit + var/plasma_from_regeneration = buff_owner.xeno_caste.plasma_gain * plasma_regen_buff_per_chamber * chamber_scaling + var/plasma_from_maximum = adjusted_plasma_maximum * plasma_maximum_buff_per_chamber * chamber_scaling + var/plasma_to_give = (plasma_from_regeneration + plasma_from_maximum) * ((buff_owner.resting || buff_owner.lying_angle) ? 2 : 1) + plasma_to_give = clamp(plasma_to_give, 0, adjusted_plasma_maximum - buff_owner.plasma_stored) + buff_owner.gain_plasma(plasma_to_give) + +// *************************************** +// *************************************** +// *************************************** +/atom/movable/screen/alert/status_effect/crush + name = "Crush" + desc = "Additional damage to objects." + icon_state = "xenobuff_attack" + +/datum/status_effect/mutation_upgrade/crush + id = "mutation_upgrade_crush" + alert_type = /atom/movable/screen/alert/status_effect/crush + chamber_structure = MUTATION_STRUCTURE_SPUR + /// The bonus damage to deal as percentage. + var/damage_buff_per_chamber = 0.333 // 33.3% + /// The armour pentration the damage damage has. + var/penetration_buff_per_chamber = 10 + +/datum/status_effect/mutation_upgrade/crush/on_apply() + if(!..()) + return FALSE + RegisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_ATTACK, PROC_REF(update_buff)) + RegisterSignal(buff_owner, COMSIG_XENOMORPH_ATTACK_OBJ, PROC_REF(on_obj_attack)) + return TRUE + +/datum/status_effect/mutation_upgrade/crush/on_remove() + UnregisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_ATTACK) + UnregisterSignal(buff_owner, COMSIG_XENOMORPH_ATTACK_OBJ) + return ..() + +/// Sets the chamber_scaling to the amount of active spur chambers. +/datum/status_effect/mutation_upgrade/crush/proc/update_buff() + SIGNAL_HANDLER + update_chamber_scaling() + +/// Deals bonus damage along with armour pentration to the object. +/datum/status_effect/mutation_upgrade/crush/proc/on_obj_attack(datum/source, obj/attacked) + SIGNAL_HANDLER + if(!chamber_scaling) + return + if(attacked.resistance_flags & XENO_DAMAGEABLE) + var/adjusted_armour_penetration = penetration_buff_per_chamber * chamber_scaling + var/adjusted_damage = buff_owner.xeno_caste.melee_damage * damage_buff_per_chamber * chamber_scaling + var/expected_damage = round(attacked.modify_by_armor(adjusted_damage, MELEE, adjusted_armour_penetration, null, null), DAMAGE_PRECISION) + var/expected_integrity = max(attacked.obj_integrity - expected_damage, 0) + // Since this signal is called before they actually attack themselves, we do just enough so the main attack does the finishing blow. + if(!expected_integrity) + attacked.take_damage(expected_integrity - 0.1, BRUTE, MELEE, FALSE, armour_penetration = 100) + return + attacked.take_damage(buff_owner.xeno_caste.melee_damage * damage_buff_per_chamber * chamber_scaling, BRUTE, MELEE, FALSE, armour_penetration = (penetration_buff_per_chamber * chamber_scaling)) + +// *************************************** +// *********** Upgrade Chambers Buffs - Utility +// *************************************** +/atom/movable/screen/alert/status_effect/focus + name = "Focus" + desc = "Increases attack damage." + icon_state = "xenobuff_generic" + +/datum/status_effect/mutation_upgrade/focus + id = "mutation_upgrade_focus" + alert_type = /atom/movable/screen/alert/status_effect/focus + chamber_structure = MUTATION_STRUCTURE_VEIL + /// The bonus melee damage for each chamber. + var/damage_buff_per_chamber = 1 + +/datum/status_effect/mutation_upgrade/focus/on_apply() + if(!..()) + return FALSE + RegisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_UTILITY, PROC_REF(update_buff)) + buff_owner.xeno_caste.melee_damage += damage_buff_per_chamber * chamber_scaling + return TRUE + +/datum/status_effect/mutation_upgrade/focus/on_remove() + UnregisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_UTILITY) + buff_owner.xeno_caste.melee_damage -= damage_buff_per_chamber * chamber_scaling + return ..() + +/// Sets the chamber_scaling to the amount of active veil chambers. +/datum/status_effect/mutation_upgrade/focus/proc/update_buff() + SIGNAL_HANDLER + buff_owner.xeno_caste.melee_damage -= damage_buff_per_chamber * chamber_scaling + update_chamber_scaling() + buff_owner.xeno_caste.melee_damage += damage_buff_per_chamber * chamber_scaling + +// *************************************** +// *************************************** +// *************************************** +/atom/movable/screen/alert/status_effect/camouflage + name = "Camouflage" + desc = "Increases your capabilities of stealth." + icon_state = "xenobuff_generic" + +/datum/status_effect/mutation_upgrade/camouflage + id = "mutation_upgrade_camouflage" + alert_type = /atom/movable/screen/alert/status_effect/camouflage + chamber_structure = MUTATION_STRUCTURE_VEIL + var/actively_cloaked = FALSE + +/datum/status_effect/mutation_upgrade/camouflage/on_apply() + if(!..()) + return FALSE + RegisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_UTILITY, PROC_REF(update_buff)) + ADD_TRAIT(buff_owner, TRAIT_SILENT_FOOTSTEPS, XENO_BUFF_TRAIT) + if(chamber_scaling >= 2) + ADD_TRAIT(buff_owner, TRAIT_TACTICAL_SENSOR_IMMUNE, XENO_BUFF_TRAIT) + if(chamber_scaling >= 3) + RegisterSignal(buff_owner, COMSIG_XENOMORPH_HEALTH_REGEN, PROC_REF(give_camouflage)) + return TRUE + +/datum/status_effect/mutation_upgrade/camouflage/on_remove() + UnregisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_UTILITY) + REMOVE_TRAIT(buff_owner, TRAIT_SILENT_FOOTSTEPS, XENO_BUFF_TRAIT) + if(chamber_scaling >= 2) + REMOVE_TRAIT(buff_owner, TRAIT_TACTICAL_SENSOR_IMMUNE, XENO_BUFF_TRAIT) + if(chamber_scaling >= 3) + remove_camouflage() + UnregisterSignal(buff_owner, COMSIG_XENOMORPH_HEALTH_REGEN, PROC_REF(give_camouflage)) + return ..() + +/// Sets the chamber_scaling to the amount of active veil chambers. +/datum/status_effect/mutation_upgrade/camouflage/proc/update_buff() + SIGNAL_HANDLER + var/previous_chamber_scale = chamber_scaling + update_chamber_scaling() + // No change at all. + if(previous_chamber_scale == chamber_scaling) + return + // Scaling down. + if(previous_chamber_scale > chamber_scaling) + // Removes things based on the difference. + for(var/i = (chamber_scaling + 1) to previous_chamber_scale) + switch(i) + if(1) + REMOVE_TRAIT(buff_owner, TRAIT_SILENT_FOOTSTEPS, XENO_BUFF_TRAIT) + if(2) + REMOVE_TRAIT(buff_owner, TRAIT_TACTICAL_SENSOR_IMMUNE, XENO_BUFF_TRAIT) + if(3) + remove_camouflage() + UnregisterSignal(buff_owner, COMSIG_XENOMORPH_HEALTH_REGEN) + return + // Scaling up. + for(var/i = (previous_chamber_scale + 1) to chamber_scaling) + switch(i) + if(1) + ADD_TRAIT(buff_owner, TRAIT_SILENT_FOOTSTEPS, XENO_BUFF_TRAIT) + if(2) + ADD_TRAIT(buff_owner, TRAIT_TACTICAL_SENSOR_IMMUNE, XENO_BUFF_TRAIT) + if(3) + give_camouflage() + RegisterSignal(buff_owner, COMSIG_XENOMORPH_HEALTH_REGEN, PROC_REF(give_camouflage)) + +/// Sets the alpha of the owner to normal. +/datum/status_effect/mutation_upgrade/camouflage/proc/remove_camouflage() + buff_owner.alpha = initial(buff_owner.alpha) + UnregisterSignal(buff_owner, COMSIG_XENOMORPH_TAKING_DAMAGE) + +/// Sets the alpha of the owner if their alpha is normal. +/datum/status_effect/mutation_upgrade/camouflage/proc/give_camouflage() + // No giving camouflage if they already got it or getting their alpha set by something else. + if(buff_owner.alpha != 255) + return + buff_owner.alpha = 64 + RegisterSignal(buff_owner, COMSIG_XENOMORPH_TAKING_DAMAGE, PROC_REF(remove_camouflage)) + +// *************************************** +// *************************************** +// *************************************** +/atom/movable/screen/alert/status_effect/pheromones + name = "Pheromones" + desc = "Allows to emit pheromones. Click to change pheromones." + icon_state = "xenobuff_phero" + +/atom/movable/screen/alert/status_effect/pheromones/Click() + var/datum/status_effect/mutation_upgrade/pheromones/status_effect = attached_effect + var/phero_choice = show_radial_menu(status_effect.buff_owner, status_effect.buff_owner, GLOB.pheromone_images_list, radius = 35, require_near = TRUE) + if(!phero_choice) + return + QDEL_NULL(status_effect.current_aura) + status_effect.emitted_aura = phero_choice + status_effect.create_aura() + +/datum/status_effect/mutation_upgrade/pheromones + id = "mutation_upgrade_pheromones" + alert_type = /atom/movable/screen/alert/status_effect/pheromones + chamber_structure = MUTATION_STRUCTURE_VEIL + /// The aura if it is not using the xeno's aura from pheromones ability. + var/datum/aura_bearer/current_aura + /// The aura to emit. + var/emitted_aura = AURA_XENO_RECOVERY + /// The initial value of the aura's power. + var/aura_power_base = 1 + /// The phero power to increase by. + var/aura_power_per_chamber = 0.25 + +/datum/status_effect/mutation_upgrade/pheromones/on_apply() + if(!..()) + return FALSE + RegisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_UTILITY, PROC_REF(update_buff)) + create_aura() + return TRUE + +/datum/status_effect/mutation_upgrade/pheromones/on_remove() + UnregisterSignal(SSdcs, COMSIG_UPGRADE_CHAMBER_UTILITY) + if(current_aura) + current_aura.stop_emitting() + switch(emitted_aura) + if(AURA_XENO_RECOVERY) + var/datum/action/ability/xeno_action/pheromones/emit_recovery/recovery_pheromones = buff_owner.actions_by_path[/datum/action/ability/xeno_action/pheromones/emit_recovery] + if(recovery_pheromones) + recovery_pheromones.bonus_aura_strength = initial(recovery_pheromones.bonus_aura_strength) + recovery_pheromones.apply_pheros(AURA_XENO_RECOVERY) + if(AURA_XENO_WARDING) + var/datum/action/ability/xeno_action/pheromones/emit_warding/warding_pheromones = buff_owner.actions_by_path[/datum/action/ability/xeno_action/pheromones/emit_warding] + if(warding_pheromones) + warding_pheromones.bonus_aura_strength = initial(warding_pheromones.bonus_aura_strength) + warding_pheromones.apply_pheros(AURA_XENO_WARDING) + if(AURA_XENO_FRENZY) + var/datum/action/ability/xeno_action/pheromones/emit_frenzy/frenzy_pheromones = buff_owner.actions_by_path[/datum/action/ability/xeno_action/pheromones/emit_frenzy] + if(frenzy_pheromones) + frenzy_pheromones.bonus_aura_strength = initial(frenzy_pheromones.bonus_aura_strength) + frenzy_pheromones.apply_pheros(AURA_XENO_FRENZY) + return ..() + +/// Boosts the current aura (if they have pheromones already) or creates a aura. +/datum/status_effect/mutation_upgrade/pheromones/proc/create_aura() + if(current_aura) + current_aura.stop_emitting() + switch(emitted_aura) + if(AURA_XENO_RECOVERY) + var/datum/action/ability/xeno_action/pheromones/emit_recovery/recovery_pheromones = buff_owner.actions_by_path[/datum/action/ability/xeno_action/pheromones/emit_recovery] + if(recovery_pheromones) + recovery_pheromones.bonus_aura_strength = aura_power_per_chamber * chamber_scaling + recovery_pheromones.apply_pheros(AURA_XENO_RECOVERY) + return + if(AURA_XENO_WARDING) + var/datum/action/ability/xeno_action/pheromones/emit_warding/warding_pheromones = buff_owner.actions_by_path[/datum/action/ability/xeno_action/pheromones/emit_warding] + if(warding_pheromones) + warding_pheromones.bonus_aura_strength = aura_power_per_chamber * chamber_scaling + warding_pheromones.apply_pheros(AURA_XENO_WARDING) + return + if(AURA_XENO_FRENZY) + var/datum/action/ability/xeno_action/pheromones/emit_frenzy/frenzy_pheromones = buff_owner.actions_by_path[/datum/action/ability/xeno_action/pheromones/emit_frenzy] + if(frenzy_pheromones) + frenzy_pheromones.bonus_aura_strength = aura_power_per_chamber * chamber_scaling + frenzy_pheromones.apply_pheros(AURA_XENO_FRENZY) + return + if(!chamber_scaling) + return + current_aura = SSaura.add_emitter(buff_owner, emitted_aura, 6 + aura_power_per_chamber * chamber_scaling * 2, aura_power_base + aura_power_per_chamber * chamber_scaling, -1, FACTION_XENO, buff_owner.hivenumber) + +/// Sets the chamber_scaling to the amount of active veil chambers and recreates the aura. +/datum/status_effect/mutation_upgrade/pheromones/proc/update_buff() + SIGNAL_HANDLER + update_chamber_scaling() + create_aura() diff --git a/code/game/objects/items/cocoon.dm b/code/game/objects/items/cocoon.dm index 1073e7361a96c..9265b61242297 100644 --- a/code/game/objects/items/cocoon.dm +++ b/code/game/objects/items/cocoon.dm @@ -44,8 +44,10 @@ psych_points_output = clamp(psych_points_output, COCOON_PSY_POINTS_REWARD_MIN, COCOON_PSY_POINTS_REWARD_MAX) SSpoints.add_strategic_psy_points(hivenumber, psych_points_output) SSpoints.add_tactical_psy_points(hivenumber, psych_points_output*0.25) - //Gives marine cloneloss for a total of 30. + // Gives marine cloneloss for a total of 30. victim.adjustCloneLoss(0.5) + // Slowly give biomass over time up to 18 biomass (assuming the time based on comment above is correct). + SSpoints.add_biomass_points(hivenumber, 0.3) /obj/structure/cocoon/take_damage(damage_amount, damage_type = BRUTE, armor_type = null, effects = TRUE, attack_dir, armour_penetration = 0, mob/living/blame_mob) . = ..() @@ -71,6 +73,8 @@ var/datum/hive_status/hive_status = GLOB.hive_datums[hivenumber] hive_status.update_tier_limits() GLOB.round_statistics.larva_from_cocoon += larva_point_reward / xeno_job.job_points_needed + SSpoints.add_biomass_points(hivenumber, 12) + release_victim() update_icon() diff --git a/code/game/objects/items/motion_detector.dm b/code/game/objects/items/motion_detector.dm index 1f0bce3d96a6a..2cc15c41c6473 100644 --- a/code/game/objects/items/motion_detector.dm +++ b/code/game/objects/items/motion_detector.dm @@ -136,7 +136,9 @@ continue prepare_blip(nearby_human, nearby_human.wear_id?.iff_signal & operator.wear_id.iff_signal ? MOTION_DETECTOR_FRIENDLY : MOTION_DETECTOR_HOSTILE) for (var/mob/living/carbon/xenomorph/nearby_xeno AS in cheap_get_xenos_near(operator, range)) - if(nearby_xeno.last_move_time + move_sensitivity < world.time ) + if(nearby_xeno.last_move_time + move_sensitivity < world.time) + continue + if(HAS_TRAIT(nearby_xeno, TRAIT_TACTICAL_SENSOR_IMMUNE)) continue prepare_blip(nearby_xeno, MOTION_DETECTOR_HOSTILE) if(hostile_detected) diff --git a/code/game/objects/structures/xeno.dm b/code/game/objects/structures/xeno.dm index 1d6f768981852..7a582b6a70fda 100644 --- a/code/game/objects/structures/xeno.dm +++ b/code/game/objects/structures/xeno.dm @@ -145,6 +145,10 @@ ignore_weed_destruction = FALSE refundable = FALSE +/obj/alien/resin/sticky/thin/temporary/Initialize(mapload) + . = ..() + addtimer(CALLBACK(src, PROC_REF(obj_destruction), MELEE), 3 SECONDS) + //Resin Doors /obj/structure/mineral_door/resin name = RESIN_DOOR diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 10c85e8c91ba9..57b555009f7ba 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -907,6 +907,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) new_xeno.apply_assigned_role_to_spawn(xallhala_job) SSpoints.xeno_strategic_points_by_hive[XENO_HIVE_FALLEN] = 10000 SSpoints.xeno_tactical_points_by_hive[XENO_HIVE_FALLEN] = 10000 + SSpoints.xeno_biomass_points_by_hive[XENO_HIVE_FALLEN] = 500 mind.transfer_to(new_xeno, TRUE) xallhala_job.after_spawn(new_xeno) return diff --git a/code/modules/mob/living/carbon/xenomorph/abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities.dm index 51c774ef65351..22a82282e6661 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities.dm @@ -633,6 +633,8 @@ ability_cost = 30 desc = "Opens your pheromone options." use_state_flags = ABILITY_USE_STAGGERED|ABILITY_USE_NOTTURF|ABILITY_USE_BUSY|ABILITY_USE_LYING + /// Additional aura strength which will be added to the caste's aura strength. + var/bonus_aura_strength = 0 /datum/action/ability/xeno_action/pheromones/proc/apply_pheros(phero_choice) var/mob/living/carbon/xenomorph/X = owner @@ -645,7 +647,8 @@ X.hud_set_pheromone() return fail_activate() QDEL_NULL(X.current_aura) - X.current_aura = SSaura.add_emitter(X, phero_choice, 6 + X.xeno_caste.aura_strength * 2, X.xeno_caste.aura_strength, -1, X.faction, X.hivenumber) + var/aura_strength = X.xeno_caste.aura_strength + bonus_aura_strength + X.current_aura = SSaura.add_emitter(X, phero_choice, 6 + aura_strength * 2, aura_strength, -1, X.faction, X.hivenumber) X.balloon_alert(X, "[phero_choice]") playsound(X.loc, SFX_ALIEN_DROOL, 25) @@ -1398,6 +1401,7 @@ victim.do_jitter_animation(2) victim.adjustCloneLoss(20) + SSpoints.add_biomass_points(X.hivenumber, 15) ADD_TRAIT(victim, TRAIT_PSY_DRAINED, TRAIT_PSY_DRAINED) if(HAS_TRAIT(victim, TRAIT_UNDEFIBBABLE)) @@ -1509,6 +1513,7 @@ victim.dead_ticks = 0 ADD_TRAIT(victim, TRAIT_STASIS, TRAIT_STASIS) X.eject_victim(TRUE, starting_turf) + if(owner.client) var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[owner.ckey] personal_statistics.cocooned++ diff --git a/code/modules/mob/living/carbon/xenomorph/castes/baneling/castedatum_baneling.dm b/code/modules/mob/living/carbon/xenomorph/castes/baneling/castedatum_baneling.dm index 705d0a4fc4850..f3356533ed536 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/baneling/castedatum_baneling.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/baneling/castedatum_baneling.dm @@ -24,7 +24,7 @@ max_health = 100 // *** Flags *** // - caste_flags = CASTE_DO_NOT_ALERT_LOW_LIFE|CASTE_IS_A_MINION + caste_flags = CASTE_DO_NOT_ALERT_LOW_LIFE|CASTE_IS_A_MINION|CASTE_NO_MUTATION can_flags = CASTE_CAN_BE_QUEEN_HEALED caste_traits = null diff --git a/code/modules/mob/living/carbon/xenomorph/castes/beetle/castedatum_beetle.dm b/code/modules/mob/living/carbon/xenomorph/castes/beetle/castedatum_beetle.dm index 94dc092dc0630..21c46d7720a3a 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/beetle/castedatum_beetle.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/beetle/castedatum_beetle.dm @@ -24,7 +24,7 @@ max_health = 260 // *** Flags *** // - caste_flags = CASTE_DO_NOT_ALERT_LOW_LIFE|CASTE_IS_A_MINION + caste_flags = CASTE_DO_NOT_ALERT_LOW_LIFE|CASTE_IS_A_MINION|CASTE_NO_MUTATION can_flags = CASTE_CAN_BE_QUEEN_HEALED|CASTE_CAN_RIDE_CRUSHER caste_traits = null diff --git a/code/modules/mob/living/carbon/xenomorph/castes/hivemind/castedatum_hivemind.dm b/code/modules/mob/living/carbon/xenomorph/castes/hivemind/castedatum_hivemind.dm index 32fff1412c34f..a0512db0764b4 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/hivemind/castedatum_hivemind.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/hivemind/castedatum_hivemind.dm @@ -22,7 +22,7 @@ maximum_active_caste = 1 // *** Flags *** // - caste_flags = CASTE_INNATE_PLASMA_REGEN|CASTE_FIRE_IMMUNE|CASTE_IS_BUILDER|CASTE_DO_NOT_ALERT_LOW_LIFE + caste_flags = CASTE_INNATE_PLASMA_REGEN|CASTE_FIRE_IMMUNE|CASTE_IS_BUILDER|CASTE_DO_NOT_ALERT_LOW_LIFE|CASTE_NO_MUTATION can_flags = CASTE_CAN_BE_QUEEN_HEALED|CASTE_CAN_BE_GIVEN_PLASMA caste_traits = null @@ -74,7 +74,7 @@ upgrade = XENO_UPGRADE_MANIFESTATION // *** Flags *** // - caste_flags = CASTE_IS_BUILDER|CASTE_FIRE_IMMUNE + caste_flags = CASTE_IS_BUILDER|CASTE_FIRE_IMMUNE|CASTE_NO_MUTATION aura_strength = 4 //Good pheros diff --git a/code/modules/mob/living/carbon/xenomorph/castes/mantis/castedatum_mantis.dm b/code/modules/mob/living/carbon/xenomorph/castes/mantis/castedatum_mantis.dm index 190fa40955b4b..9b71d0df965fd 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/mantis/castedatum_mantis.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/mantis/castedatum_mantis.dm @@ -25,7 +25,7 @@ max_health = 150 // *** Flags *** // - caste_flags = CASTE_DO_NOT_ALERT_LOW_LIFE|CASTE_IS_A_MINION + caste_flags = CASTE_DO_NOT_ALERT_LOW_LIFE|CASTE_IS_A_MINION|CASTE_NO_MUTATION can_flags = CASTE_CAN_BE_QUEEN_HEALED|CASTE_CAN_BE_GIVEN_PLASMA|CASTE_CAN_RIDE_CRUSHER caste_traits = null diff --git a/code/modules/mob/living/carbon/xenomorph/castes/nymph/castedatum_nymph.dm b/code/modules/mob/living/carbon/xenomorph/castes/nymph/castedatum_nymph.dm index ad381f39c107f..f897a8ccfffc6 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/nymph/castedatum_nymph.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/nymph/castedatum_nymph.dm @@ -24,7 +24,7 @@ max_health = 120 // *** Flags *** // - caste_flags = CASTE_DO_NOT_ALERT_LOW_LIFE|CASTE_IS_A_MINION|CASTE_IS_BUILDER + caste_flags = CASTE_DO_NOT_ALERT_LOW_LIFE|CASTE_IS_A_MINION|CASTE_IS_BUILDER|CASTE_NO_MUTATION can_flags = CASTE_CAN_BE_QUEEN_HEALED|CASTE_CAN_BE_GIVEN_PLASMA // *** Defense *** // diff --git a/code/modules/mob/living/carbon/xenomorph/castes/puppet/castedatum_puppet.dm b/code/modules/mob/living/carbon/xenomorph/castes/puppet/castedatum_puppet.dm index 6840b7fb279cd..82f8fa4d00b5e 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/puppet/castedatum_puppet.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/puppet/castedatum_puppet.dm @@ -15,7 +15,7 @@ plasma_max = 2 plasma_gain = 0 max_health = 250 - caste_flags = CASTE_NOT_IN_BIOSCAN|CASTE_DO_NOT_ANNOUNCE_DEATH|CASTE_DO_NOT_ALERT_LOW_LIFE + caste_flags = CASTE_NOT_IN_BIOSCAN|CASTE_DO_NOT_ANNOUNCE_DEATH|CASTE_DO_NOT_ALERT_LOW_LIFE|CASTE_NO_MUTATION minimap_icon = "puppet" soft_armor = list(MELEE = 14, BULLET = 3, LASER = 5, ENERGY = 3, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/scorpion/castedatum_scorpion.dm b/code/modules/mob/living/carbon/xenomorph/castes/scorpion/castedatum_scorpion.dm index 42102310c5e56..6dc30aa83fcfd 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/scorpion/castedatum_scorpion.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/scorpion/castedatum_scorpion.dm @@ -24,7 +24,7 @@ max_health = 130 // *** Flags *** // - caste_flags = CASTE_DO_NOT_ALERT_LOW_LIFE|CASTE_IS_A_MINION + caste_flags = CASTE_DO_NOT_ALERT_LOW_LIFE|CASTE_IS_A_MINION|CASTE_NO_MUTATION can_flags = CASTE_CAN_BE_QUEEN_HEALED|CASTE_CAN_BE_GIVEN_PLASMA|CASTE_CAN_RIDE_CRUSHER caste_traits = null diff --git a/code/modules/mob/living/carbon/xenomorph/castes/spiderling/castedatum_spiderling.dm b/code/modules/mob/living/carbon/xenomorph/castes/spiderling/castedatum_spiderling.dm index 45a9b323f78d3..e9c7964f079ff 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/spiderling/castedatum_spiderling.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/spiderling/castedatum_spiderling.dm @@ -25,7 +25,7 @@ max_health = 125 // *** Flags *** // - caste_flags = CASTE_NOT_IN_BIOSCAN|CASTE_DO_NOT_ANNOUNCE_DEATH|CASTE_DO_NOT_ALERT_LOW_LIFE|CASTE_IS_BUILDER + caste_flags = CASTE_NOT_IN_BIOSCAN|CASTE_DO_NOT_ANNOUNCE_DEATH|CASTE_DO_NOT_ALERT_LOW_LIFE|CASTE_IS_BUILDER|CASTE_NO_MUTATION // *** Minimap Icon *** // minimap_icon = "spiderling" diff --git a/code/modules/mob/living/carbon/xenomorph/hive_datum.dm b/code/modules/mob/living/carbon/xenomorph/hive_datum.dm index 2accf2293d193..36f621f1e5735 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_datum.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_datum.dm @@ -24,6 +24,13 @@ var/list/obj/structure/xeno/pherotower/pherotowers = list() ///list of hivemind cores var/list/obj/structure/xeno/hivemindcore/hivemindcores = list() + /// List of shell upgrade chambers. + var/list/obj/structure/xeno/upgrade_chamber/shell/shell_chambers = list() + /// List of spur upgrade chambers. + var/list/obj/structure/xeno/upgrade_chamber/spur/spur_chambers = list() + /// List of veil upgrade chambers. + var/list/obj/structure/xeno/upgrade_chamber/veil/veil_chambers = list() + var/tier3_xeno_limit var/tier2_xeno_limit /// Queue of all clients wanting to join xeno side @@ -35,6 +42,9 @@ var/datum/hive_purchases/purchases = new /// The nuke HUD timer datum, shown on each xeno's screen var/atom/movable/screen/text/screen_timer/nuke_hud_timer + /// The amount of biomass stored. + var/biomass = 0 + // *************************************** // *********** Init @@ -122,6 +132,13 @@ // Pheromone towers for(var/obj/structure/xeno/pherotower/tower AS in GLOB.hive_datums[hivenumber].pherotowers) .["hive_structures"] += list(get_structure_packet(tower)) + // Upgrade chambers + for(var/obj/structure/xeno/upgrade_chamber/shell/chamber AS in GLOB.hive_datums[hivenumber].shell_chambers) + .["hive_structures"] += list(get_structure_packet(chamber)) + for(var/obj/structure/xeno/upgrade_chamber/spur/chamber AS in GLOB.hive_datums[hivenumber].spur_chambers) + .["hive_structures"] += list(get_structure_packet(chamber)) + for(var/obj/structure/xeno/upgrade_chamber/veil/chamber AS in GLOB.hive_datums[hivenumber].veil_chambers) + .["hive_structures"] += list(get_structure_packet(chamber)) // Hivemind cores for(var/obj/structure/xeno/hivemindcore/core AS in GLOB.hive_datums[hivenumber].hivemindcores) .["hive_structures"] += list(get_structure_packet(core)) @@ -145,6 +162,7 @@ "is_leader" = xeno.xeno_flags & XENO_LEADER, "is_ssd" = !xeno.client, "index" = GLOB.hive_ui_caste_index[caste.caste_type_path], + "mutation_disabled" = caste.caste_flags & CASTE_NO_MUTATION )) var/mob/living/carbon/xenomorph/xeno_user @@ -163,7 +181,7 @@ .["user_maturity"] = isxeno(user) ? xeno_user.upgrade_stored : 0 .["user_next_mat_level"] = isxeno(user) && xeno_user.upgrade_possible() ? xeno_user.xeno_caste.upgrade_threshold : 0 .["user_tracked"] = isxeno(user) && !isnull(xeno_user.tracked) ? REF(xeno_user.tracked) : "" - + .["user_can_mutate"] = !isxeno(user) || (xeno_user.xeno_caste.caste_flags & CASTE_NO_MUTATION) .["user_show_empty"] = !!(user.client.prefs.status_toggle_flags & HIVE_STATUS_SHOW_EMPTY) .["user_show_compact"] = !!(user.client.prefs.status_toggle_flags & HIVE_STATUS_COMPACT_MODE) .["user_show_general"] = !!(user.client.prefs.status_toggle_flags & HIVE_STATUS_SHOW_GENERAL) @@ -262,6 +280,10 @@ if(!isxeno(usr)) return SEND_SIGNAL(usr, COMSIG_XENOABILITY_BLESSINGSMENU) + if("Mutations") + if(!isxeno(usr)) + return + GLOB.mutation_selector.interact(usr) if("Compass") var/atom/target = locate(params["target"]) if(isobserver(usr)) @@ -1589,3 +1611,4 @@ to_chat will check for valid clients itself already so no need to double check f if(faction == FACTION_ZOMBIE) return FACTION_ZOMBIE return FALSE + diff --git a/code/modules/mob/living/carbon/xenomorph/hive_upgrades.dm b/code/modules/mob/living/carbon/xenomorph/hive_upgrades.dm index 6bca6e42502ce..9a51507d5f4e4 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_upgrades.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_upgrades.dm @@ -314,6 +314,50 @@ GLOBAL_LIST_INIT(tier_to_primo_upgrade, list( to_chat(buyer, span_xenowarning("You cannot build in a dense location!")) return FALSE +/datum/hive_upgrade/building/upgrade_chamber + gamemode_flags = ABILITY_NUCLEARWAR + building_loc = 0 + /// The maximum amount of buildings that can exist before being disallowed from buying more. + var/max_chambers = 3 + +/datum/hive_upgrade/building/upgrade_chamber/shell + name = "Shell Upgrade Chamber" + desc = "Constructs a chamber that allows xenos to buy survival mutations. Build up to 3 structures to increase mutation power." + icon = "shell" + psypoint_cost = 250 + building_type = /obj/structure/xeno/upgrade_chamber/shell + +/datum/hive_upgrade/building/upgrade_chamber/shell/can_buy(mob/living/carbon/xenomorph/buyer, silent = TRUE) + . = ..() + if(length(buyer.hive.shell_chambers) >= max_chambers) + to_chat(buyer, span_xenowarning("Hive cannot support more than [max_chambers] active shell chambers!")) + return FALSE + +/datum/hive_upgrade/building/upgrade_chamber/spur + name = "Spur Upgrade Chamber" + desc = "Constructs a chamber that allows xenos to buy attack mutations. Build up to 3 structures to increase mutation power." + icon = "spur" + psypoint_cost = 200 + building_type = /obj/structure/xeno/upgrade_chamber/spur + +/datum/hive_upgrade/building/upgrade_chamber/spur/can_buy(mob/living/carbon/xenomorph/buyer, silent = TRUE) + . = ..() + if(length(buyer.hive.spur_chambers) >= max_chambers) + to_chat(buyer, span_xenowarning("Hive cannot support more than [max_chambers] active spur chambers!")) + return FALSE + +/datum/hive_upgrade/building/upgrade_chamber/veil + name = "Veil Upgrade Chamber" + desc = "Constructs a chamber that allows xenos to buy utility mutations. Build up to 3 structures to increase mutation power." + icon = "veil" + psypoint_cost = 300 + building_type = /obj/structure/xeno/upgrade_chamber/veil + +/datum/hive_upgrade/building/upgrade_chamber/veil/can_buy(mob/living/carbon/xenomorph/buyer, silent = TRUE) + . = ..() + if(length(buyer.hive.veil_chambers) >= max_chambers) + to_chat(buyer, span_xenowarning("Hive cannot support more than [max_chambers] active veil chambers!")) + return FALSE /datum/hive_upgrade/defence category = "Defences" diff --git a/code/modules/mob/living/carbon/xenomorph/mutation_datum.dm b/code/modules/mob/living/carbon/xenomorph/mutation_datum.dm new file mode 100644 index 0000000000000..c517e9c4ea12e --- /dev/null +++ b/code/modules/mob/living/carbon/xenomorph/mutation_datum.dm @@ -0,0 +1,208 @@ +/datum/mutation_datum + interaction_flags = INTERACT_UI_INTERACT + +/datum/mutation_datum/ui_state(mob/user) + return GLOB.hive_ui_state // Similar purpose. + +/datum/mutation_datum/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "MutationSelector", "Mutation Selector") + ui.open() + +/datum/mutation_datum/ui_data(mob/living/carbon/xenomorph/xeno_user) + var/list/data = list() + + data["shell_chambers"] = length(xeno_user.hive?.shell_chambers) + data["spur_chambers"] = length(xeno_user.hive?.spur_chambers) + data["veil_chambers"] = length(xeno_user.hive?.veil_chambers) + data["biomass"] = !isnull(SSpoints.xeno_biomass_points_by_hive[xeno_user.hivenumber]) ? SSpoints.xeno_biomass_points_by_hive[xeno_user.hivenumber] : 0 + return data + +/datum/mutation_datum/ui_static_data(mob/living/carbon/xenomorph/xeno_user) + var/list/data = list() + + // Cost is not expected to change as switching castes closes the UI. + switch(xeno_user.xeno_caste.tier) + if(XENO_TIER_ONE) + data["cost"] = XENO_UPGRADE_BIOMASS_COST_T1 + if(XENO_TIER_TWO) + data["cost"] = XENO_UPGRADE_BIOMASS_COST_T2 + if(XENO_TIER_THREE) + data["cost"] = XENO_UPGRADE_BIOMASS_COST_T3 + else + data["cost"] = XENO_UPGRADE_BIOMASS_COST_T4 + + data["survival_mutations"] = list() + for(var/datum/mutation_upgrade/survival/subtype_survival_mutation AS in subtypesof(/datum/mutation_upgrade/survival)) + data["survival_mutations"] += list(list( // Double listing is how it needs to work. + "name" = subtype_survival_mutation.name, + "desc" = subtype_survival_mutation.desc, + "owned" = locate(subtype_survival_mutation.status_effect) in xeno_user.status_effects + )) + + data["attack_mutations"] = list() + for(var/datum/mutation_upgrade/attack/subtype_attack_mutation AS in subtypesof(/datum/mutation_upgrade/attack)) + data["attack_mutations"] += list(list( + "name" = subtype_attack_mutation.name, + "desc" = subtype_attack_mutation.desc, + "owned" = locate(subtype_attack_mutation.status_effect) in xeno_user.status_effects + )) + + data["utility_mutations"] = list() + for(var/datum/mutation_upgrade/utility/subtype_utility_mutation AS in subtypesof(/datum/mutation_upgrade/utility)) + data["utility_mutations"] += list(list( + "name" = subtype_utility_mutation.name, + "desc" = subtype_utility_mutation.desc, + "owned" = locate(subtype_utility_mutation.status_effect) in xeno_user.status_effects + )) + + return data + +/datum/mutation_datum/ui_act(action, params) + . = ..() + if(.) + return + if(!isxeno(usr)) + return + + switch(action) + if("purchase") + try_purchase_mutation(usr, params["upgrade_name"]) + + SStgui.close_user_uis(usr, src) + +/// Tries to purchase a mutation. Denies if possible. Otherwise, removes conflicting mutations and gives the purchased mutation. +/datum/mutation_datum/proc/try_purchase_mutation(mob/living/carbon/xenomorph/xeno_purchaser, upgrade_name) + if(!xeno_purchaser.hive || !upgrade_name) + return + if((xeno_purchaser.xeno_caste.caste_flags & CASTE_NO_MUTATION)) + return + + var/upgrade_price + switch(xeno_purchaser.xeno_caste.tier) + if(XENO_TIER_ONE) + upgrade_price = XENO_UPGRADE_BIOMASS_COST_T1 + if(XENO_TIER_TWO) + upgrade_price = XENO_UPGRADE_BIOMASS_COST_T2 + if(XENO_TIER_THREE) + upgrade_price = XENO_UPGRADE_BIOMASS_COST_T3 + else + upgrade_price = XENO_UPGRADE_BIOMASS_COST_T4 + + var/current_biomass = !isnull(SSpoints.xeno_biomass_points_by_hive[xeno_purchaser.hivenumber]) ? SSpoints.xeno_biomass_points_by_hive[xeno_purchaser.hivenumber] : 0 + if(current_biomass < upgrade_price) + to_chat(usr, span_warning("The hive does not have enough biomass!")) + return + + var/datum/mutation_upgrade/chosen_mutation_upgrade + for(var/datum/mutation_upgrade/subtype_mutation AS in GLOB.mutation_upgrades_buyable) + if(subtype_mutation.name == upgrade_name) + chosen_mutation_upgrade = subtype_mutation + break + + if(!chosen_mutation_upgrade) + return + + switch(chosen_mutation_upgrade.required_structure) + if(MUTATION_STRUCTURE_CHAMBER) + if(!length(xeno_purchaser.hive.shell_chambers)) + to_chat(usr, span_xenonotice("This mutation requires a shell chamber to exist!")) + return + if(MUTATION_STRUCTURE_SPUR) + if(!length(xeno_purchaser.hive.spur_chambers)) + to_chat(usr, span_xenonotice("This mutation requires a spur chamber to exist!")) + return + if(MUTATION_STRUCTURE_VEIL) + if(!length(xeno_purchaser.hive.veil_chambers)) + to_chat(usr, span_xenonotice("This mutation requires a veil chamber to exist!")) + return + + var/existing_upgrade = locate(chosen_mutation_upgrade.status_effect) in xeno_purchaser.status_effects + if(existing_upgrade) + to_chat(usr, span_xenonotice("Existing mutation chosen. No biomass spent.")) + return + + var/list/mutation_status_effects_to_remove = list() + for(var/datum/mutation_upgrade/subtype_mutation AS in GLOB.mutation_upgrades_buyable) + if(chosen_mutation_upgrade.category == subtype_mutation.category) + mutation_status_effects_to_remove += subtype_mutation.status_effect + + SSpoints.xeno_biomass_points_by_hive[xeno_purchaser.hivenumber] -= upgrade_price + to_chat(xeno_purchaser, span_xenonotice("Mutation gained.")) + for(var/datum/status_effect/removed_status_effect AS in mutation_status_effects_to_remove) + xeno_purchaser.remove_status_effect(removed_status_effect) + xeno_purchaser.do_jitter_animation(500) + xeno_purchaser.apply_status_effect(chosen_mutation_upgrade.status_effect) + xeno_message("[xeno_purchaser] has purchased [chosen_mutation_upgrade.name] Mutation.", "xenoannounce", 5, xeno_purchaser.hivenumber) + +/datum/mutation_upgrade + /// The name that is displayed in the TGUI. + var/name + /// The description that is displayed in the TGUI. + var/desc + /// The category slot that this upgrade takes. Upgrades that conflict with this category slot will be removed/replaced. + var/category + /// The structure that needs to exist for a successful purchase. + var/required_structure + /// The status effect given upon successful purchase. + var/datum/status_effect/status_effect + +/datum/mutation_upgrade/survival + category = MUTATION_CATEGORY_SURVIVAL + required_structure = MUTATION_STRUCTURE_CHAMBER + +/datum/mutation_upgrade/survival/carapace + name = "Carapace" + desc = "Increases our hard armor by 1 per Shell Chamber." + status_effect = STATUS_EFFECT_UPGRADE_CARAPACE + +/datum/mutation_upgrade/survival/regeneration + name = "Regeneration" + desc = "When regenerating health on weeds, regenerate 0.8% max health and 0.167 sunder per Shell Chamber." + status_effect = STATUS_EFFECT_UPGRADE_REGENERATION + +/datum/mutation_upgrade/survival/vampirism + name = "Vampirism" + desc = "When slashing living humans, heal 10% for damage dealt per Shell Chamber." + status_effect = STATUS_EFFECT_UPGRADE_VAMPIRISM + +/datum/mutation_upgrade/attack + category = MUTATION_CATEGORY_ATTACK + required_structure = MUTATION_STRUCTURE_SPUR + +/datum/mutation_upgrade/attack/celerity + name = "Celerity" + desc = "Move -0.1 units faster per Spur Chamber." + category = MUTATION_CATEGORY_ATTACK + required_structure = MUTATION_STRUCTURE_SPUR + status_effect = STATUS_EFFECT_UPGRADE_CELERITY + +/datum/mutation_upgrade/attack/adrenaline + name = "Adrenaline" + desc = "When regenerating plasma on weeds, regenerate 5% additional plasma and 1% maximum plasma per Spur Chamber. It is doubled if resting." + status_effect = STATUS_EFFECT_UPGRADE_ADRENALINE + +/datum/mutation_upgrade/attack/crush + name = "Crush" + desc = "When attacking structures, deal a second instance of damage that is a 1/3 of your melee damage with 15 AP per Spur Chamber." + status_effect = STATUS_EFFECT_UPGRADE_CRUSH + +/datum/mutation_upgrade/utility + category = MUTATION_CATEGORY_UTILITY + required_structure = MUTATION_STRUCTURE_VEIL + +/datum/mutation_upgrade/utility/focus + name = "Focus" + desc = "Deal 1 additional melee damage for every Veil Chamber." + status_effect = STATUS_EFFECT_UPGRADE_FOCUS + +/datum/mutation_upgrade/utility/pheromones + name = "Pheromones" + desc = "Allows you to emit a chosen pheromone starting at a power of 1 and an additional 0.25 per Veil Chamber." + status_effect = STATUS_EFFECT_UPGRADE_PHERO + +/datum/mutation_upgrade/utility/camouflage + name = "Camouflage" + desc = "Grants various stealth effects based on the amount of Veil Chambers: slient step (1), immunity to tactical sensor detection (2), and stealth that is broken when taking damage & regained when healing (3)." + status_effect = STATUS_EFFECT_UPGRADE_CAMOUFLAGE diff --git a/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm b/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm index a173fb124683d..737f1bfe8d58a 100644 --- a/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm +++ b/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm @@ -126,6 +126,9 @@ else //Upgrade process finished or impossible . += "Upgrade Progress: (FINISHED)" + if(!(xeno_caste.caste_flags & CASTE_NO_MUTATION)) + . += "Biomass: [!isnull(SSpoints.xeno_biomass_points_by_hive[hivenumber]) ? SSpoints.xeno_biomass_points_by_hive[hivenumber] : 0]/500" + . += "Health: [health]/[maxHealth][overheal ? " + [overheal]": ""]" //Changes with balance scalar, can't just use the caste if(xeno_caste.plasma_max > 0) diff --git a/code/modules/xenomorph/upgrade_chambers.dm b/code/modules/xenomorph/upgrade_chambers.dm new file mode 100644 index 0000000000000..719d05adb0a09 --- /dev/null +++ b/code/modules/xenomorph/upgrade_chambers.dm @@ -0,0 +1,62 @@ +/obj/structure/xeno/upgrade_chamber + name = "upgrade chamber" + desc = "You shouldn't see this!" + icon = 'icons/Xeno/1x1building.dmi' + icon_state = "shell_chamber" + bound_width = 32 + bound_height = 32 + max_integrity = 500 + resistance_flags = UNACIDABLE | DROPSHIP_IMMUNE + xeno_structure_flags = IGNORE_WEED_REMOVAL | CRITICAL_STRUCTURE + +/obj/structure/xeno/upgrade_chamber/Initialize(mapload, _hivenumber) + . = ..() + SSminimaps.add_marker(src, MINIMAP_FLAG_XENO, image('icons/UI_icons/map_blips.dmi', null, "upgrade_chamber", ABOVE_FLOAT_LAYER)) + +/obj/structure/xeno/upgrade_chamber/shell + name = "Shell Chamber" + desc = "Shell upgrade chamber" + icon_state = "shell_chamber" + +/obj/structure/xeno/upgrade_chamber/shell/Initialize(mapload, _hivenumber) + . = ..() + set_light(3, 1, COLOR_DARK_CYAN) + GLOB.hive_datums[hivenumber].shell_chambers += src + SEND_GLOBAL_SIGNAL(COMSIG_UPGRADE_CHAMBER_SURVIVAL) + +/obj/structure/xeno/upgrade_chamber/shell/Destroy() + GLOB.hive_datums[hivenumber].shell_chambers -= src + SEND_GLOBAL_SIGNAL(COMSIG_UPGRADE_CHAMBER_SURVIVAL) + return ..() + +/obj/structure/xeno/upgrade_chamber/spur + name = "Spur Chamber" + desc = "Spur upgrade chamber" + icon_state = "spur_chamber" + +/obj/structure/xeno/upgrade_chamber/spur/Initialize(mapload, _hivenumber) + . = ..() + set_light(3, 1, COLOR_RED) + GLOB.hive_datums[hivenumber].spur_chambers += src + SEND_GLOBAL_SIGNAL(COMSIG_UPGRADE_CHAMBER_ATTACK) + +/obj/structure/xeno/upgrade_chamber/spur/Destroy() + GLOB.hive_datums[hivenumber].spur_chambers -= src + SEND_GLOBAL_SIGNAL(COMSIG_UPGRADE_CHAMBER_ATTACK) + return ..() + +/obj/structure/xeno/upgrade_chamber/veil + name = "Veil Chamber" + desc = "Veil upgrade chamber" + icon_state = "veil_chamber" + +/obj/structure/xeno/upgrade_chamber/veil/Initialize(mapload, _hivenumber) + . = ..() + set_light(3, 1, COLOR_LIME) + GLOB.hive_datums[hivenumber].veil_chambers += src + SEND_GLOBAL_SIGNAL(COMSIG_UPGRADE_CHAMBER_UTILITY) + +/obj/structure/xeno/upgrade_chamber/veil/Destroy() + GLOB.hive_datums[hivenumber].veil_chambers -= src + SEND_GLOBAL_SIGNAL(COMSIG_UPGRADE_CHAMBER_UTILITY) + return ..() diff --git a/icons/UI_Icons/buyable_icons.dmi b/icons/UI_Icons/buyable_icons.dmi index 0401dbb393f75..985131ed198f3 100644 Binary files a/icons/UI_Icons/buyable_icons.dmi and b/icons/UI_Icons/buyable_icons.dmi differ diff --git a/icons/UI_Icons/map_blips.dmi b/icons/UI_Icons/map_blips.dmi index b38bbe215fb77..fa6c1cd80f6e3 100644 Binary files a/icons/UI_Icons/map_blips.dmi and b/icons/UI_Icons/map_blips.dmi differ diff --git a/icons/Xeno/1x1building.dmi b/icons/Xeno/1x1building.dmi index b58708b539aa3..d4ac402de1aaf 100644 Binary files a/icons/Xeno/1x1building.dmi and b/icons/Xeno/1x1building.dmi differ diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi index ad6e246e92201..af132dd3a6ac6 100644 Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ diff --git a/tgmc.dme b/tgmc.dme index d016dc2755e2d..ab21b3a09e63b 100644 --- a/tgmc.dme +++ b/tgmc.dme @@ -1789,6 +1789,7 @@ F// DM Environment file for baystation12.dme. #include "code\modules\mob\living\carbon\xenomorph\hive_upgrades.dm" #include "code\modules\mob\living\carbon\xenomorph\life.dm" #include "code\modules\mob\living\carbon\xenomorph\login.dm" +#include "code\modules\mob\living\carbon\xenomorph\mutation_datum.dm" #include "code\modules\mob\living\carbon\xenomorph\saddles.dm" #include "code\modules\mob\living\carbon\xenomorph\say.dm" #include "code\modules\mob\living\carbon\xenomorph\update_icons.dm" @@ -2284,6 +2285,7 @@ F// DM Environment file for baystation12.dme. #include "code\modules\xenomorph\spawner.dm" #include "code\modules\xenomorph\trap.dm" #include "code\modules\xenomorph\tunnel.dm" +#include "code\modules\xenomorph\upgrade_chambers.dm" #include "code\modules\xenomorph\xeno_turret.dm" #include "code\modules\xenomorph\xenoplant.dm" #include "code\modules\xenomorph\xenotowers.dm" diff --git a/tgui/packages/tgui/interfaces/HiveStatus.tsx b/tgui/packages/tgui/interfaces/HiveStatus.tsx index 5f89779d85c8e..f7cae197cb00f 100644 --- a/tgui/packages/tgui/interfaces/HiveStatus.tsx +++ b/tgui/packages/tgui/interfaces/HiveStatus.tsx @@ -44,6 +44,7 @@ type InputPack = { user_evolution: number; user_purchase_perms: boolean; user_maturity: number; + user_can_mutate: boolean; user_next_mat_level: number; user_tracked: string; user_show_compact: boolean; @@ -190,15 +191,12 @@ const BlessingsButton = (_props: any) => { const { act, data } = useBackend(); const { user_purchase_perms, user_ref } = data; - if (!user_purchase_perms) { - return ; - } - return ( @@ -206,6 +204,23 @@ const BlessingsButton = (_props: any) => { ); }; +const MutationsButton = (_props: any) => { + const { act, data } = useBackend(); + const { user_ref, user_can_mutate } = data; + + return ( + + + + ); +}; + const GeneralInfo = (_props: any) => { const { data } = useBackend(); const { @@ -253,7 +268,10 @@ const GeneralInfo = (_props: any) => { {' ' + hive_larva_burrowed} - + + + + diff --git a/tgui/packages/tgui/interfaces/MutationSelector.tsx b/tgui/packages/tgui/interfaces/MutationSelector.tsx new file mode 100644 index 0000000000000..03321ae94ba37 --- /dev/null +++ b/tgui/packages/tgui/interfaces/MutationSelector.tsx @@ -0,0 +1,168 @@ +import { useBackend } from '../backend'; +import { + Button, + Collapsible, + Flex, + ProgressBar, + Section, + Tooltip, +} from '../components'; +import { Window } from '../layouts'; + +type Upgrade = { + name: string; + desc: string; + owned: boolean; +}; + +type BiomassData = { + biomass: number; + cost: number; +}; + +type SurvivalMutationData = { + survival_mutations: Upgrade[]; + shell_chambers: number; + biomass: number; + cost: number; +}; + +type AttackMutationData = { + attack_mutations: Upgrade[]; + spur_chambers: number; + biomass: number; + cost: number; +}; + +type UtilityMutationData = { + utility_mutations: Upgrade[]; + veil_chambers: number; + biomass: number; + cost: number; +}; + +export const MutationSelector = (_props: any) => { + return ( + + +
+ +
+ + + +
+
+ ); +}; + +const BiomassBar = (_props: any) => { + const { data } = useBackend(); + const { biomass, cost } = data; + + return ( + + + + + {`${biomass} / 500 `} + + + + + ); +}; + +const SurvivalMutationSection = (_props: any) => { + const { act, data } = useBackend(); + const { survival_mutations, shell_chambers, cost, biomass } = data; + + return ( + + {survival_mutations.map((mutation) => ( +
act('purchase', { upgrade_name: mutation.name })} + disabled={cost > biomass || shell_chambers === 0} + selected={mutation.owned} + /> + } + > + + {mutation.desc} + +
+ ))} +
+ ); +}; + +const AttackMutationSection = (_props: any) => { + const { act, data } = useBackend(); + const { attack_mutations, spur_chambers, cost, biomass } = data; + + return ( + + {attack_mutations.map((mutation) => ( +
act('purchase', { upgrade_name: mutation.name })} + disabled={cost > biomass || spur_chambers === 0} + selected={mutation.owned} + /> + } + > + + {mutation.desc} + +
+ ))} +
+ ); +}; + +const UtilityMutationSection = (_props: any) => { + const { act, data } = useBackend(); + const { utility_mutations, veil_chambers, cost, biomass } = data; + + return ( + + {utility_mutations.map((mutation) => ( +
act('purchase', { upgrade_name: mutation.name })} + disabled={cost > biomass || veil_chambers === 0} + selected={mutation.owned} + /> + } + > + + {mutation.desc} + +
+ ))} +
+ ); +};