diff --git a/code/datums/actions/mobs/defensive_mode.dm b/code/datums/actions/mobs/defensive_mode.dm new file mode 100644 index 00000000000..30cb9a5980a --- /dev/null +++ b/code/datums/actions/mobs/defensive_mode.dm @@ -0,0 +1,49 @@ +/// An ability that allows the viper spider to get in an defensive mode at the cost of speed. +/datum/action/cooldown/mob_cooldown/defensive_mode + name = "Change Mode" + button_icon = 'icons/mob/actions/actions_animal.dmi' + button_icon_state = "defensive_mode" + desc = "Activates a defensive mode to reduce damage but will make you slower." + cooldown_time = 5 SECONDS + click_to_activate = FALSE + /// If the defensive mode is activated or not. + var/defense_active = FALSE + /// Movement speed modifier used. + var/datum/movespeed_modifier/modifier_type = /datum/movespeed_modifier/viper_defensive + +/datum/action/cooldown/mob_cooldown/defensive_mode/Remove(mob/living/remove_from) + var/mob/living/basic/owner_mob = owner + if(defense_active && istype(owner_mob)) + offence(owner_mob) + + return ..() + +/datum/action/cooldown/mob_cooldown/defensive_mode/Activate(atom/target_atom) + StartCooldown(360 SECONDS, 360 SECONDS) + activate_defence(owner) + StartCooldown() + return TRUE + +/datum/action/cooldown/mob_cooldown/defensive_mode/proc/activate_defence(mob/living/basic/owner_mob) + if(!istype(owner_mob)) + return + if(defense_active) + offence(owner_mob) + return + defence(owner_mob) + +/datum/action/cooldown/mob_cooldown/defensive_mode/proc/offence(mob/living/basic/owner_mob) + owner_mob.damage_coeff = list(BRUTE = 1, BURN = 1.25, TOX = 1, CLONE = 1, STAMINA = 1, OXY = 1) + owner_mob.icon_state = initial(owner_mob.icon_state) + owner_mob.icon_living = initial(owner_mob.icon_living) + owner_mob.icon_dead = initial(owner_mob.icon_dead) + owner_mob.remove_movespeed_modifier(modifier_type) + defense_active = FALSE + +/datum/action/cooldown/mob_cooldown/defensive_mode/proc/defence(mob/living/basic/owner_mob) + owner_mob.damage_coeff = list(BRUTE = 0.4, BURN = 0.5, TOX = 1, CLONE = 1, STAMINA = 1, OXY = 1) + owner_mob.icon_dead = "[owner_mob.icon_state]_d_dead" + owner_mob.icon_state = "[owner_mob.icon_state]_d" + owner_mob.icon_living = "[owner_mob.icon_living]_d" + owner_mob.add_movespeed_modifier(modifier_type) + defense_active = TRUE diff --git a/code/datums/elements/bonus_damage.dm b/code/datums/elements/bonus_damage.dm new file mode 100644 index 00000000000..1fce0672c51 --- /dev/null +++ b/code/datums/elements/bonus_damage.dm @@ -0,0 +1,35 @@ +/** + * Attached to a mob that will then deal bonus damage to a victim with low, or potentially in the future, high health. + */ +/datum/element/bonus_damage + /// At which percentage our target has to be for us to deal bonus damage + var/damage_percentage + /// The amount of brute damage we will deal + var/brute_damage_amount + +/datum/element/bonus_damage/Attach(datum/target, damage_percentage = 20, brute_damage_amount = 15) + . = ..() + if(!isliving(target)) + return ELEMENT_INCOMPATIBLE + + src.damage_percentage = damage_percentage + src.brute_damage_amount = brute_damage_amount + RegisterSignal(target, COMSIG_HOSTILE_POST_ATTACKINGTARGET, PROC_REF(attack_target)) + +/datum/element/bonus_damage/Detach(datum/source) + UnregisterSignal(source, COMSIG_HOSTILE_POST_ATTACKINGTARGET) + return ..() + +/// Add potential bonus damage to the person we attacked +/datum/element/bonus_damage/proc/attack_target(mob/living/attacker, atom/target, success) + SIGNAL_HANDLER + + if(!success) + return + if(!isliving(target)) + return + var/mob/living/living_target = target + var/health_percentage = (living_target.health / living_target.maxHealth) * 100 + if(living_target.stat == DEAD || health_percentage > damage_percentage) + return + living_target.adjustBruteLoss(brute_damage_amount) diff --git a/code/datums/elements/tear_wall.dm b/code/datums/elements/tear_wall.dm new file mode 100644 index 00000000000..0d24bbda289 --- /dev/null +++ b/code/datums/elements/tear_wall.dm @@ -0,0 +1,48 @@ +/** + * Attached to a basic mob that will then be able to tear down a wall after some time. + */ +/datum/element/tear_wall + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 3 + /// The rate at which we can break regular walls + var/regular_tear_time + /// The rate at which we can break reinforced walls + var/reinforced_tear_time + +/datum/element/tear_wall/Attach(datum/target, regular_tear_time = 2 SECONDS, reinforced_tear_time = 4 SECONDS) + . = ..() + if(!isbasicmob(target)) + return ELEMENT_INCOMPATIBLE + + src.regular_tear_time = regular_tear_time + src.reinforced_tear_time = reinforced_tear_time + RegisterSignal(target, COMSIG_HOSTILE_POST_ATTACKINGTARGET, PROC_REF(attack_wall)) + +/datum/element/bonus_damage/Detach(datum/source) + UnregisterSignal(source, COMSIG_HOSTILE_POST_ATTACKINGTARGET) + return ..() + +/// Checks if we are attacking a wall +/datum/element/tear_wall/proc/attack_wall(mob/living/basic/attacker, atom/target, success) + SIGNAL_HANDLER + + if(!iswallturf(target)) + return + var/turf/closed/wall/thewall = target + var/prying_time = regular_tear_time + if(istype(thewall, /turf/closed/wall/r_wall)) + prying_time = reinforced_tear_time + INVOKE_ASYNC(src, PROC_REF(async_attack_wall), attacker, thewall, prying_time) + +/// Performs taking down the wall +/datum/element/tear_wall/proc/async_attack_wall(mob/living/basic/attacker, turf/closed/wall/thewall, prying_time) + if(DOING_INTERACTION_WITH_TARGET(attacker, thewall)) + attacker.balloon_alert(attacker, "busy!") + return + to_chat(attacker, span_warning("You begin tearing through the wall...")) + playsound(attacker, 'sound/machines/airlock_alien_prying.ogg', 100, TRUE) + if(do_after(attacker, prying_time, target = thewall)) + if(isopenturf(thewall)) + return + thewall.dismantle_wall(1) + playsound(attacker, 'sound/effects/meteorimpact.ogg', 100, TRUE) diff --git a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_variants.dm b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_variants.dm index 34f6defed72..648174bd603 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_variants.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_variants.dm @@ -149,6 +149,8 @@ datahud.show_to(src) AddComponent(/datum/component/healing_touch,\ + heal_brute = 25,\ + heal_burn = 25,\ interaction_key = DOAFTER_SOURCE_SPIDER,\ valid_targets_typecache = typecacheof(list(/mob/living/basic/giant_spider)),\ action_text = "%SOURCE% begins wrapping the wounds of %TARGET%.",\ @@ -173,8 +175,8 @@ icon_dead = "tangle_dead" gender = FEMALE butcher_results = list(/obj/item/food/meat/slab/spider = 2, /obj/item/food/spiderleg = 8, /obj/item/food/spidereggs = 4) - maxHealth = 40 - health = 40 + maxHealth = 55 + health = 55 melee_damage_lower = 1 melee_damage_upper = 1 poison_per_bite = 5 @@ -203,15 +205,24 @@ AddElement(/datum/element/web_walker, /datum/movespeed_modifier/average_web) AddComponent(/datum/component/healing_touch,\ - heal_brute = maxHealth * 0.5,\ - heal_burn = maxHealth * 0.5,\ + heal_brute = 15,\ + heal_burn = 15,\ + heal_time = 3 SECONDS,\ self_targetting = HEALING_TOUCH_SELF_ONLY,\ interaction_key = DOAFTER_SOURCE_SPIDER,\ valid_targets_typecache = typecacheof(list(/mob/living/basic/giant_spider/tangle)),\ + extra_checks = CALLBACK(src, PROC_REF(can_mend)),\ action_text = "%SOURCE% begins mending themselves...",\ complete_text = "%SOURCE%'s wounds mend together.",\ ) +/// Prevent you from healing other tangle spiders, or healing when on fire +/mob/living/basic/giant_spider/tangle/proc/can_mend(mob/living/source, mob/living/target) + if (on_fire) + balloon_alert(src, "on fire!") + return FALSE + return TRUE + /** * ### Tarantula * @@ -225,25 +236,34 @@ icon_state = "tarantula" icon_living = "tarantula" icon_dead = "tarantula_dead" - maxHealth = 300 // woah nelly - health = 300 + maxHealth = 360 // woah nelly + health = 360 melee_damage_lower = 35 melee_damage_upper = 40 obj_damage = 100 - damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) + damage_coeff = list(BRUTE = 1, BURN = 1.25, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) speed = 6 player_speed_modifier = -5.5 // Doesn't seem that slow but it gets a debuff off web mob_size = MOB_SIZE_LARGE gold_core_spawnable = NO_SPAWN + web_speed = 0.7 + web_type = /datum/action/cooldown/lay_web/sealer menu_description = "Tank spider variant with an enormous amount of health and damage, but is very slow when not on webbing. It also has a charge ability to close distance with a target after a small windup." /// Charging ability var/datum/action/cooldown/mob_cooldown/charge/basic_charge/charge /mob/living/basic/giant_spider/tarantula/Initialize(mapload) . = ..() + var/datum/action/cooldown/lay_web/solid_web/web_solid = new(src) + web_solid.Grant(src) + + var/datum/action/cooldown/lay_web/web_passage/passage_web = new(src) + passage_web.Grant(src) + charge = new /datum/action/cooldown/mob_cooldown/charge/basic_charge() charge.Grant(src) + AddElement(/datum/element/tear_wall) AddElement(/datum/element/web_walker, /datum/movespeed_modifier/slow_web) /mob/living/basic/giant_spider/tarantula/Destroy() @@ -267,8 +287,8 @@ icon_state = "viper" icon_living = "viper" icon_dead = "viper_dead" - maxHealth = 40 - health = 40 + maxHealth = 55 + health = 55 melee_damage_lower = 5 melee_damage_upper = 5 poison_per_bite = 5 @@ -278,6 +298,14 @@ gold_core_spawnable = NO_SPAWN menu_description = "Assassin spider variant with an unmatched speed and very deadly poison, but has very low amount of health and damage." +/mob/living/basic/giant_spider/viper/Initialize(mapload) + . = ..() + + AddElement(/datum/element/bonus_damage) + + var/datum/action/cooldown/mob_cooldown/defensive_mode/defensive_action = new(src) + defensive_action.Grant(src) + /** * ### Spider Broodmother * @@ -435,11 +463,12 @@ * They also occasionally leave puddles of blood when they walk around. Flavorful! */ /mob/living/basic/giant_spider/hunter/flesh - desc = "A odd fleshy creature in the shape of a spider. Its eyes are pitch black and soulless." + name = "flesh spider" + desc = "A odd fleshy creature in the shape of a spider. Its eyes are pitch black and soulless." icon = 'icons/mob/simple/arachnoid.dmi' - icon_state = "flesh_spider" - icon_living = "flesh_spider" - icon_dead = "flesh_spider_dead" + icon_state = "flesh" + icon_living = "flesh" + icon_dead = "flesh_dead" web_speed = 0.7 maxHealth = 90 health = 90 @@ -452,8 +481,8 @@ blood_spawn_chance = 5) // It might be easier and more fitting to just replace this with Regenerator AddComponent(/datum/component/healing_touch,\ - heal_brute = maxHealth * 0.5,\ - heal_burn = maxHealth * 0.5,\ + heal_brute = 45,\ + heal_burn = 45,\ self_targetting = HEALING_TOUCH_SELF_ONLY,\ interaction_key = DOAFTER_SOURCE_SPIDER,\ valid_targets_typecache = typecacheof(list(/mob/living/basic/giant_spider/hunter/flesh)),\ @@ -462,6 +491,12 @@ complete_text = "%SOURCE%'s wounds mend together.",\ ) + var/datum/action/cooldown/lay_web/web_spikes/spikes_web = new(src) + spikes_web.Grant(src) + + var/datum/action/cooldown/lay_web/sticky_web/web_sticky = new(src) + web_sticky.Grant(src) + /// Prevent you from healing other flesh spiders, or healing when on fire /mob/living/basic/giant_spider/hunter/flesh/proc/can_mend(mob/living/source, mob/living/target) if (on_fire) @@ -469,22 +504,24 @@ return FALSE return TRUE -/mob/living/basic/giant_spider/hunter/flesh/Initialize(mapload) - . = ..() - var/datum/action/cooldown/lay_web/web_spikes/spikes_web = new(src) - spikes_web.Grant(src) - - var/datum/action/cooldown/lay_web/sticky_web/web_sticky = new(src) - web_sticky.Grant(src) - /** * ### Viper Spider (Wizard) * * A spider form for wizards. Has the viper spider's extreme speed and strong venom, with additional health and vent crawling abilities. */ /mob/living/basic/giant_spider/viper/wizard + name = "water spider" + desc = "Furry and black, it makes you shudder to look at it. This one has effervescent orange eyes." + icon = 'icons/mob/simple/arachnoid.dmi' + icon_state = "water" + icon_living = "water" + icon_dead = "water_dead" + web_speed = 0.4 maxHealth = 80 health = 80 + damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 1, OXY = 1) + unsuitable_cold_damage = 1 + unsuitable_heat_damage = 1 menu_description = "Stronger assassin spider variant with an unmatched speed, high amount of health and very deadly poison, but deals very low amount of damage. It also has ability to ventcrawl." apply_spider_antag = FALSE @@ -492,6 +529,13 @@ . = ..() ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) + var/datum/action/cooldown/lay_web/web_spikes/spikes_web = new(src) + spikes_web.Grant(src) + + var/datum/action/cooldown/lay_web/sticky_web/web_sticky = new(src) + web_sticky.Grant(src) + + /** * ### Sergeant Araneus * diff --git a/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling.dm b/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling.dm index f4291088474..b8829015980 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling.dm @@ -40,11 +40,13 @@ lighting_cutoff_blue = 5 /// The mob we will grow into. - var/mob/living/basic/giant_spider/grow_as = null + var/mob/living/basic/young_spider/grow_as = null /// The message that the mother left for our big strong selves. var/directive = "" /// Simple boolean that determines if we should apply the spider antag to the player if they possess this mob. TRUE by default since we're always going to evolve into a spider that will have an antagonistic role. var/apply_spider_antag = TRUE + /// The time it takes for the spider to grow into the next stage + var/spider_growth_time = 40 SECONDS /mob/living/basic/spiderling/Initialize(mapload) . = ..() @@ -64,13 +66,13 @@ // it's A-OKAY for grow_as to be null for the purposes of this component since we override that behavior anyhow. AddComponent(\ /datum/component/growth_and_differentiation,\ - growth_time = 1 MINUTES,\ + growth_time = spider_growth_time,\ growth_path = grow_as,\ growth_probability = 25,\ lower_growth_value = 1,\ upper_growth_value = 2,\ optional_checks = CALLBACK(src, PROC_REF(ready_to_grow)),\ - optional_grow_behavior = CALLBACK(src, PROC_REF(grow_into_giant_spider))\ + optional_grow_behavior = CALLBACK(src, PROC_REF(grow_into_young_spider))\ ) // keep in mind we have infinite range (the entire pipenet is our playground, it's just a matter of random choice as to where we end up) so lower and upper both have their gives and takes. @@ -117,15 +119,15 @@ return FALSE -/// Actually grows the spiderling into a giant spider. We have to do a bunch of unique behavior that really can't be genericized, so we have to override the component in this manner. -/mob/living/basic/spiderling/proc/grow_into_giant_spider() +/// Actually grows the spiderling into a young spider. We have to do a bunch of unique behavior that really can't be genericized, so we have to override the component in this manner. +/mob/living/basic/spiderling/proc/grow_into_young_spider() if(isnull(grow_as)) if(prob(3)) - grow_as = pick(/mob/living/basic/giant_spider/tarantula, /mob/living/basic/giant_spider/viper, /mob/living/basic/giant_spider/midwife) + grow_as = pick(/mob/living/basic/young_spider/tarantula, /mob/living/basic/young_spider/viper, /mob/living/basic/young_spider/midwife) else - grow_as = pick(/mob/living/basic/giant_spider, /mob/living/basic/giant_spider/ambush, /mob/living/basic/giant_spider/hunter, /mob/living/basic/giant_spider/scout, /mob/living/basic/giant_spider/nurse, /mob/living/basic/giant_spider/tangle) + grow_as = pick(/mob/living/basic/young_spider/guard, /mob/living/basic/young_spider/ambush, /mob/living/basic/young_spider/hunter, /mob/living/basic/young_spider/scout, /mob/living/basic/young_spider/nurse, /mob/living/basic/young_spider/tangle) - var/mob/living/basic/giant_spider/grown = change_mob_type(grow_as, get_turf(src), initial(grow_as.name)) + var/mob/living/basic/young_spider/grown = change_mob_type(grow_as, get_turf(src), initial(grow_as.name)) ADD_TRAIT(grown, TRAIT_WAS_EVOLVED, REF(src)) grown.faction = faction.Copy() grown.directive = directive diff --git a/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling_subtypes.dm b/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling_subtypes.dm index 13b961a5ffc..866a572453c 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling_subtypes.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/spiderlings/spiderling_subtypes.dm @@ -1,92 +1,90 @@ -// This whole file is just a container for the spiderling subtypes that actually differentiate into different giant spiders. None of them are particularly special as of now. +// This whole file is just a container for the spiderling subtypes that actually differentiate into different young spiders. None of them are particularly special as of now. -/// Will differentiate into the base giant spider (known colloquially as the "guard" spider). +/// Will differentiate into the base young spider (known colloquially as the "guard" spider). /mob/living/basic/spiderling/guard - grow_as = /mob/living/basic/giant_spider/guard + grow_as = /mob/living/basic/young_spider/guard name = "guard spiderling" desc = "Furry and brown, it looks defenseless. This one has sparkling red eyes." - /// Will differentiate into the "ambush" giant spider. +/// Will differentiate into the "ambush" young spider. /mob/living/basic/spiderling/ambush - grow_as = /mob/living/basic/giant_spider/ambush + grow_as = /mob/living/basic/young_spider/ambush name = "ambush spiderling" desc = "Furry and white, it looks defenseless. This one has sparkling pink eyes." icon = 'icons/mob/simple/arachnoid.dmi' icon_state = "ambush_spiderling" icon_dead = "ambush_spiderling_dead" -/// Will differentiate into the "scout" giant spider. +/// Will differentiate into the "scout" young spider. /mob/living/basic/spiderling/scout - grow_as = /mob/living/basic/giant_spider/scout + grow_as = /mob/living/basic/young_spider/scout name = "scout spiderling" - desc = "Furry and black, it looks defenseless. This one has sparkling purple eyes." + desc = "Furry and black, it looks defenseless. This one has sparkling blue eyes." icon = 'icons/mob/simple/arachnoid.dmi' icon_state = "scout_spiderling" icon_dead = "scout_spiderling_dead" + sight = SEE_SELF|SEE_MOBS -/// Will differentiate into the "hunter" giant spider. +/// Will differentiate into the "hunter" young spider. /mob/living/basic/spiderling/hunter - grow_as = /mob/living/basic/giant_spider/hunter + grow_as = /mob/living/basic/young_spider/hunter name = "hunter spiderling" desc = "Furry and black, it looks defenseless. This one has sparkling purple eyes." icon = 'icons/mob/simple/arachnoid.dmi' icon_state = "hunter_spiderling" icon_dead = "hunter_spiderling_dead" -/// Will differentiate into the "nurse" giant spider. +/// Will differentiate into the "nurse" young spider. /mob/living/basic/spiderling/nurse - grow_as = /mob/living/basic/giant_spider/nurse + grow_as = /mob/living/basic/young_spider/nurse name = "nurse spiderling" desc = "Furry and black, it looks defenseless. This one has sparkling green eyes." icon = 'icons/mob/simple/arachnoid.dmi' icon_state = "nurse_spiderling" icon_dead = "nurse_spiderling_dead" - /// Will differentiate into the "tangle" giant spider. +/// Will differentiate into the "tangle" young spider. /mob/living/basic/spiderling/tangle - grow_as = /mob/living/basic/giant_spider/tangle + grow_as = /mob/living/basic/young_spider/tangle name = "tangle spiderling" desc = "Furry and brown, it looks defenseless. This one has dim brown eyes." icon = 'icons/mob/simple/arachnoid.dmi' icon_state = "tangle_spiderling" icon_dead = "tangle_spiderling_dead" -/// Will differentiate into the "midwife" giant spider. +/// Will differentiate into the "midwife" young spider. /mob/living/basic/spiderling/midwife - grow_as = /mob/living/basic/giant_spider/midwife + grow_as = /mob/living/basic/young_spider/midwife name = "broodmother spiderling" desc = "Furry and black, it looks defenseless. This one has scintillating green eyes. Might also be hiding a real knife somewhere." icon = 'icons/mob/simple/arachnoid.dmi' icon_state = "midwife_spiderling" icon_dead = "midwife_spiderling_dead" - gold_core_spawnable = NO_SPAWN -/// Will differentiate into the "viper" giant spider. +/// Will differentiate into the "viper" young spider. /mob/living/basic/spiderling/viper - grow_as = /mob/living/basic/giant_spider/viper + grow_as = /mob/living/basic/young_spider/viper name = "viper spiderling" - desc = "Furry and black, it looks defenseless. This one has sparkling purple eyes." + desc = "Furry and black, it looks defenseless. This one has sparkling magenta eyes." icon = 'icons/mob/simple/arachnoid.dmi' icon_state = "viper_spiderling" icon_dead = "viper_spiderling_dead" - gold_core_spawnable = NO_SPAWN -/// Will differentiate into the "tarantula" giant spider. +/// Will differentiate into the "tarantula" young spider. /mob/living/basic/spiderling/tarantula - grow_as = /mob/living/basic/giant_spider/tarantula + grow_as = /mob/living/basic/young_spider/tarantula name = "tarantula spiderling" desc = "Furry and black, it looks defenseless. This one has abyssal red eyes." icon = 'icons/mob/simple/arachnoid.dmi' icon_state = "tarantula_spiderling" icon_dead = "tarantula_spiderling_dead" - gold_core_spawnable = NO_SPAWN -/// Will differentiate into the "hunter" giant spider. +/// Will differentiate into the "flesh" young spider. /mob/living/basic/spiderling/hunter/flesh - grow_as = /mob/living/basic/giant_spider/hunter/flesh - name = "hunter spiderling" - desc = "Fleshy and red, it looks defenseless. This one has sparkling cerulean eyes." + grow_as = /mob/living/basic/young_spider/hunter/flesh + name = "flesh spiderling" + desc = "Fleshy and red, it looks defenseless. This one has sparkling grey eyes." icon = 'icons/mob/simple/arachnoid.dmi' icon_state = "flesh_spiderling" icon_dead = "flesh_spiderling_dead" - gold_core_spawnable = NO_SPAWN + spider_growth_time = 20 SECONDS diff --git a/code/modules/mob/living/basic/space_fauna/spider/young_spider/young_spider.dm b/code/modules/mob/living/basic/space_fauna/spider/young_spider/young_spider.dm new file mode 100644 index 00000000000..340ff11c7c2 --- /dev/null +++ b/code/modules/mob/living/basic/space_fauna/spider/young_spider/young_spider.dm @@ -0,0 +1,174 @@ +/** + * # Young Spider + * + * A mob which can be created by spiderlings/spider eggs. + * The basic type is the guard, which is slow but sturdy and outputs good damage. + * All spiders can produce webbing. + */ +/mob/living/basic/young_spider + name = "young spider" + desc = "Furry and black, it makes you shudder to look at it. This one has deep red eyes." + icon = 'icons/mob/simple/arachnoid.dmi' + icon_state = "young_guard" + icon_living = "young_guard" + icon_dead = "young_guard_dead" + mob_biotypes = MOB_ORGANIC|MOB_BUG + speak_emote = list("chitters") + butcher_results = list(/obj/item/food/meat/slab/spider = 1) + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + initial_language_holder = /datum/language_holder/spider + speed = 1 + maxHealth = 60 + health = 60 + damage_coeff = list(BRUTE = 1, BURN = 1.25, TOX = 1, CLONE = 1, STAMINA = 1, OXY = 1) + basic_mob_flags = FLAMMABLE_MOB + status_flags = NONE + unsuitable_cold_damage = 4 + unsuitable_heat_damage = 4 + obj_damage = 10 + melee_damage_lower = 8 + melee_damage_upper = 12 + combat_mode = TRUE + faction = list(FACTION_SPIDER) + pass_flags = PASSTABLE + attack_verb_continuous = "bites" + attack_verb_simple = "bite" + attack_sound = 'sound/weapons/bite.ogg' + attack_vis_effect = ATTACK_EFFECT_BITE + unique_name = TRUE + // VERY red, to fit the eyes + lighting_cutoff_red = 22 + lighting_cutoff_green = 5 + lighting_cutoff_blue = 5 + ai_controller = /datum/ai_controller/basic_controller/young_spider + /// The mob we will grow into. + var/mob/living/basic/giant_spider/grow_as = null + /// Speed modifier to apply if controlled by a human player + var/player_speed_modifier = -1 + /// What reagent the mob injects targets with + var/poison_type = /datum/reagent/toxin/hunterspider + /// How much of a reagent the mob injects on attack + var/poison_per_bite = 0 + /// Multiplier to apply to web laying speed. Fractional numbers make it faster, because it's a multiplier. + var/web_speed = 1 + /// Type of webbing ability to learn. + var/web_type = /datum/action/cooldown/lay_web + /// The message that the mother spider left for this spider when the egg was layed. + var/directive = "" + /// Short description of what this mob is capable of, for radial menu uses + var/menu_description = "Tanky and strong for the defense of the nest and other spiders." + /// If true then you shouldn't be told that you're a spider antagonist as soon as you are placed into this mob + var/apply_spider_antag = TRUE + /// The time it takes for the spider to grow into the next stage + var/spider_growth_time = 1 MINUTES + +/mob/living/basic/young_spider/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_WEB_SURFER, INNATE_TRAIT) + AddElement(/datum/element/ai_retaliate) + AddElement(/datum/element/ai_flee_while_injured) + AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW) + AddElement(/datum/element/nerfed_pulling, GLOB.typecache_general_bad_things_to_easily_move) + AddElement(/datum/element/prevent_attacking_of_types, GLOB.typecache_general_bad_hostile_attack_targets, "this tastes awful!") + AddElement(/datum/element/web_walker, /datum/movespeed_modifier/young_web) + + if(poison_per_bite) + AddElement(/datum/element/venomous, poison_type, poison_per_bite) + + var/datum/action/cooldown/lay_web/webbing = new web_type(src) + webbing.webbing_time *= web_speed + webbing.Grant(src) + ai_controller.set_blackboard_key(BB_SPIDER_WEB_ACTION, webbing) + AddComponent(\ + /datum/component/growth_and_differentiation,\ + growth_time = spider_growth_time,\ + growth_path = grow_as,\ + growth_probability = 25,\ + lower_growth_value = 1,\ + upper_growth_value = 2,\ + optional_checks = CALLBACK(src, PROC_REF(ready_to_grow)),\ + optional_grow_behavior = CALLBACK(src, PROC_REF(grow_into_giant_spider))\ + ) + +/mob/living/basic/young_spider/Login() + . = ..() + if(!. || !client) + return FALSE + GLOB.spidermobs[src] = TRUE + add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/player_spider_modifier, multiplicative_slowdown = player_speed_modifier) + if (apply_spider_antag) + var/datum/antagonist/spider/spider_antag = new(directive) + mind.add_antag_datum(spider_antag) + +/mob/living/basic/young_spider/Logout() + . = ..() + remove_movespeed_modifier(/datum/movespeed_modifier/player_spider_modifier) + +/mob/living/basic/young_spider/Destroy() + GLOB.spidermobs -= src + return ..() + +/mob/living/basic/young_spider/mob_negates_gravity() + if(locate(/obj/structure/spider/stickyweb) in loc) + return TRUE + return ..() + +/mob/living/basic/young_spider/expose_reagents(list/reagents, datum/reagents/source, methods=TOUCH, volume_modifier=1, show_message=TRUE) + . = ..() + for(var/datum/reagent/toxin/pestkiller/current_reagent in reagents) + apply_damage(50 * volume_modifier, STAMINA, BODY_ZONE_CHEST) + +/// Checks to see if we're ready to grow, primarily if we are on solid ground and not in a vent or something. +/// The component will automagically grow us when we return TRUE and that threshold has been met. +/mob/living/basic/young_spider/proc/ready_to_grow() + if(isturf(loc)) + return TRUE + + return FALSE + +/// Actually grows the young spider into a giant spider. We have to do a bunch of unique behavior that really can't be genericized, so we have to override the component in this manner. +/mob/living/basic/young_spider/proc/grow_into_giant_spider() + if(isnull(grow_as)) + if(prob(3)) + grow_as = pick(/mob/living/basic/giant_spider/tarantula, /mob/living/basic/giant_spider/viper, /mob/living/basic/giant_spider/midwife) + else + grow_as = pick(/mob/living/basic/giant_spider/guard, /mob/living/basic/giant_spider/ambush, /mob/living/basic/giant_spider/hunter, /mob/living/basic/giant_spider/scout, /mob/living/basic/giant_spider/nurse, /mob/living/basic/giant_spider/tangle) + + var/mob/living/basic/giant_spider/grown = change_mob_type(grow_as, get_turf(src), initial(grow_as.name)) + ADD_TRAIT(grown, TRAIT_WAS_EVOLVED, REF(src)) + grown.faction = faction.Copy() + grown.directive = directive + grown.set_name() + if(getBruteLoss() - 5 > 0) + grown.setBruteLoss(getBruteLoss() - 5) + if(getFireLoss() - 5 > 0) + grown.setFireLoss(getFireLoss() - 5) + + qdel(src) + +/// Used by all young spiders if they ever appear. +/datum/ai_controller/basic_controller/young_spider + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(), + ) + + ai_traits = STOP_MOVING_WHEN_PULLED + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + + planning_subtrees = list( + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, + /datum/ai_planning_subtree/flee_target, + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/attack_obstacle_in_path, + /datum/ai_planning_subtree/random_speech/insect, + /datum/ai_planning_subtree/find_unwebbed_turf, + /datum/ai_planning_subtree/spin_web, + ) + +/datum/ai_behavior/run_away_from_target/young_spider + run_distance = 6 diff --git a/code/modules/mob/living/basic/space_fauna/spider/young_spider/young_spider_subtypes.dm b/code/modules/mob/living/basic/space_fauna/spider/young_spider/young_spider_subtypes.dm new file mode 100644 index 00000000000..697ee5d0808 --- /dev/null +++ b/code/modules/mob/living/basic/space_fauna/spider/young_spider/young_spider_subtypes.dm @@ -0,0 +1,222 @@ +// This whole file is just a container for the young spider subtypes that actually differentiate into different giant spiders. None of them are particularly special as of now. + +/// Will differentiate into the base giant spider (known colloquially as the "guard" spider). +/mob/living/basic/young_spider/guard + grow_as = /mob/living/basic/giant_spider/guard + name = "young guard spider" + desc = "Furry and brown, it looks defenseless. This one has sparkling red eyes." + maxHealth = 70 + health = 70 + melee_damage_lower = 10 + melee_damage_upper = 15 + speed = 0.7 + +/// Will differentiate into the "ambush" giant spider. +/mob/living/basic/young_spider/ambush + grow_as = /mob/living/basic/giant_spider/ambush + name = "young ambush spider" + desc = "Furry and white, it looks defenseless. This one has sparkling pink eyes." + icon = 'icons/mob/simple/arachnoid.dmi' + icon_state = "young_ambush" + icon_dead = "young_ambush_dead" + maxHealth = 55 + health = 55 + melee_damage_lower = 12 + melee_damage_upper = 18 + speed = 1 + +/mob/living/basic/young_spider/ambush/Initialize(mapload) + . = ..() + var/datum/action/cooldown/sneak/spider/sneak_web = new(src) + sneak_web.Grant(src) + +/// Will differentiate into the "scout" giant spider. +/mob/living/basic/young_spider/scout + grow_as = /mob/living/basic/giant_spider/scout + name = "young scout spider" + desc = "Furry and black, it looks defenseless. This one has sparkling blue eyes." + icon = 'icons/mob/simple/arachnoid.dmi' + icon_state = "young_scout" + icon_dead = "young_scout_dead" + maxHealth = 35 + health = 35 + melee_damage_lower = 2 + melee_damage_upper = 4 + speed = 0.5 + poison_per_bite = 4 + poison_type = /datum/reagent/peaceborg/confuse + sight = SEE_SELF|SEE_MOBS + +/mob/living/basic/young_spider/scout/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) + +/// Will differentiate into the "hunter" giant spider. +/mob/living/basic/young_spider/hunter + grow_as = /mob/living/basic/giant_spider/hunter + name = "young hunter spider" + desc = "Furry and black, it looks defenseless. This one has sparkling purple eyes." + icon = 'icons/mob/simple/arachnoid.dmi' + icon_state = "young_hunter" + icon_dead = "young_hunter_dead" + maxHealth = 45 + health = 45 + melee_damage_lower = 8 + melee_damage_upper = 12 + speed = 0.5 + poison_per_bite = 2 + +/// Will differentiate into the "nurse" giant spider. +/mob/living/basic/young_spider/nurse + grow_as = /mob/living/basic/giant_spider/nurse + name = "young nurse spider" + desc = "Furry and black, it looks defenseless. This one has sparkling green eyes." + icon = 'icons/mob/simple/arachnoid.dmi' + icon_state = "young_nurse" + icon_dead = "young_nurse_dead" + maxHealth = 25 + health = 25 + melee_damage_lower = 2 + melee_damage_upper = 4 + speed = 0.7 + web_speed = 0.5 + web_type = /datum/action/cooldown/lay_web/sealer + ///The health HUD applied to the mob. + var/health_hud = DATA_HUD_MEDICAL_ADVANCED + +/mob/living/basic/young_spider/nurse/Initialize(mapload) + . = ..() + var/datum/atom_hud/datahud = GLOB.huds[health_hud] + datahud.show_to(src) + + AddComponent(/datum/component/healing_touch,\ + heal_brute = 15,\ + heal_burn = 15,\ + interaction_key = DOAFTER_SOURCE_SPIDER,\ + valid_targets_typecache = typecacheof(list(/mob/living/basic/giant_spider)),\ + action_text = "%SOURCE% begins wrapping the wounds of %TARGET%.",\ + complete_text = "%SOURCE% wraps the wounds of %TARGET%.",\ + ) + +/// Will differentiate into the "tangle" giant spider. +/mob/living/basic/young_spider/tangle + grow_as = /mob/living/basic/giant_spider/tangle + name = "young tangle spider" + desc = "Furry and brown, it looks defenseless. This one has dim brown eyes." + icon = 'icons/mob/simple/arachnoid.dmi' + icon_state = "young_tangle" + icon_dead = "young_tangle_dead" + maxHealth = 30 + health = 30 + melee_damage_lower = 1 + melee_damage_upper = 1 + speed = 0.7 + web_speed = 0.25 + web_type = /datum/action/cooldown/lay_web/sealer + poison_per_bite = 2 + poison_type = /datum/reagent/toxin/acid + +/mob/living/basic/young_spider/tangle/Initialize(mapload) + . = ..() + AddComponent(/datum/component/healing_touch,\ + heal_brute = 10,\ + heal_burn = 10,\ + heal_time = 3 SECONDS,\ + self_targetting = HEALING_TOUCH_SELF_ONLY,\ + interaction_key = DOAFTER_SOURCE_SPIDER,\ + valid_targets_typecache = typecacheof(list(/mob/living/basic/giant_spider/tangle)),\ + extra_checks = CALLBACK(src, PROC_REF(can_mend)),\ + action_text = "%SOURCE% begins mending themselves...",\ + complete_text = "%SOURCE%'s wounds mend together.",\ + ) + +/// Prevent you from healing other tangle spiders, or healing when on fire +/mob/living/basic/young_spider/tangle/proc/can_mend(mob/living/source, mob/living/target) + if (on_fire) + balloon_alert(src, "on fire!") + return FALSE + return TRUE + +/// Will differentiate into the "midwife" giant spider. +/mob/living/basic/young_spider/midwife + grow_as = /mob/living/basic/giant_spider/midwife + name = "young broodmother spider" + desc = "Furry and black, it looks defenseless. This one has scintillating green eyes. Might also be hiding a real knife somewhere." + icon = 'icons/mob/simple/arachnoid.dmi' + icon_state = "young_midwife" + icon_dead = "young_midwife_dead" + maxHealth = 100 + health = 100 + melee_damage_lower = 5 + melee_damage_upper = 10 + speed = 0.7 + web_speed = 0.5 + web_type = /datum/action/cooldown/lay_web/sealer + +/// Will differentiate into the "viper" giant spider. +/mob/living/basic/young_spider/viper + grow_as = /mob/living/basic/giant_spider/viper + name = "young viper spider" + desc = "Furry and black, it looks defenseless. This one has sparkling magenta eyes." + icon = 'icons/mob/simple/arachnoid.dmi' + icon_state = "young_viper" + icon_dead = "young_viper_dead" + maxHealth = 30 + health = 30 + melee_damage_lower = 5 + melee_damage_upper = 5 + speed = 0.2 + poison_type = /datum/reagent/toxin/viperspider + poison_per_bite = 2 + +/// Will differentiate into the "tarantula" giant spider. +/mob/living/basic/young_spider/tarantula + grow_as = /mob/living/basic/giant_spider/tarantula + name = "young tarantula spider" + desc = "Furry and black, it looks defenseless. This one has abyssal red eyes." + icon = 'icons/mob/simple/arachnoid.dmi' + icon_state = "young_tarantula" + icon_dead = "young_tarantula_dead" + maxHealth = 150 + health = 150 + melee_damage_lower = 20 + melee_damage_upper = 25 + speed = 1 + obj_damage = 40 + +/// Will differentiate into the "flesh" giant spider. +/mob/living/basic/young_spider/hunter/flesh + grow_as = /mob/living/basic/giant_spider/hunter/flesh + name = "young flesh spider" + desc = "Furry and red, it looks defenseless. This one has sparkling grey eyes." + icon = 'icons/mob/simple/arachnoid.dmi' + icon_state = "young_flesh" + icon_dead = "young_flesh_dead" + maxHealth = 55 + health = 55 + web_speed = 0.7 + spider_growth_time = 30 SECONDS + +/mob/living/basic/young_spider/hunter/flesh/Initialize(mapload) + . = ..() + AddComponent(/datum/component/blood_walk, \ + blood_type = /obj/effect/decal/cleanable/blood/bubblegum, \ + blood_spawn_chance = 3) + // It might be easier and more fitting to just replace this with Regenerator + AddComponent(/datum/component/healing_touch,\ + heal_brute = 25,\ + heal_burn = 25,\ + self_targetting = HEALING_TOUCH_SELF_ONLY,\ + interaction_key = DOAFTER_SOURCE_SPIDER,\ + valid_targets_typecache = typecacheof(list(/mob/living/basic/giant_spider/hunter/flesh)),\ + extra_checks = CALLBACK(src, PROC_REF(can_mend)),\ + action_text = "%SOURCE% begins mending themselves...",\ + complete_text = "%SOURCE%'s wounds mend together.",\ + ) + +/// Prevent you from healing other flesh spiders, or healing when on fire +/mob/living/basic/young_spider/hunter/flesh/proc/can_mend(mob/living/source, mob/living/target) + if (on_fire) + balloon_alert(src, "on fire!") + return FALSE + return TRUE diff --git a/code/modules/mob_spawn/ghost_roles/spider_roles.dm b/code/modules/mob_spawn/ghost_roles/spider_roles.dm index 1737f5bbfc9..24bef0abfa3 100644 --- a/code/modules/mob_spawn/ghost_roles/spider_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/spider_roles.dm @@ -177,7 +177,8 @@ var/list/display_spiders = list() for(var/choice in potentialspawns) var/mob/living/basic/spiderling/chosen_spiderling = choice - var/mob/living/basic/giant_spider/spider = initial(chosen_spiderling.grow_as) + var/mob/living/basic/young_spider/young_spider = initial(chosen_spiderling.grow_as) + var/mob/living/basic/giant_spider/spider = initial(young_spider.grow_as) spider_list[initial(spider.name)] = chosen_spiderling var/datum/radial_menu_choice/option = new diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm index c4a7ada4655..52c79945021 100644 --- a/code/modules/movespeed/modifiers/mobs.dm +++ b/code/modules/movespeed/modifiers/mobs.dm @@ -103,6 +103,9 @@ /datum/movespeed_modifier/fast_web multiplicative_slowdown = 0.2 +/datum/movespeed_modifier/young_web + multiplicative_slowdown = 0.5 + /datum/movespeed_modifier/spiderling_web multiplicative_slowdown = 0.7 @@ -112,6 +115,9 @@ /datum/movespeed_modifier/slow_web multiplicative_slowdown = 5 +/datum/movespeed_modifier/viper_defensive + multiplicative_slowdown = 1.5 + /datum/movespeed_modifier/gravity blacklisted_movetypes = FLOATING variable = TRUE diff --git a/icons/mob/actions/actions_animal.dmi b/icons/mob/actions/actions_animal.dmi index 1fcda97922c..9caf5cdf2f7 100644 Binary files a/icons/mob/actions/actions_animal.dmi and b/icons/mob/actions/actions_animal.dmi differ diff --git a/icons/mob/simple/arachnoid.dmi b/icons/mob/simple/arachnoid.dmi index 8ad8880fcd7..976005f6b5e 100644 Binary files a/icons/mob/simple/arachnoid.dmi and b/icons/mob/simple/arachnoid.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 002a22a3db6..f468d146ee5 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -763,6 +763,7 @@ #include "code\datums\actions\mobs\charge_apc.dm" #include "code\datums\actions\mobs\conjure_foamwall.dm" #include "code\datums\actions\mobs\dash.dm" +#include "code\datums\actions\mobs\defensive_mode.dm" #include "code\datums\actions\mobs\fire_breath.dm" #include "code\datums\actions\mobs\lava_swoop.dm" #include "code\datums\actions\mobs\meteors.dm" @@ -1221,6 +1222,7 @@ #include "code\datums\elements\bed_tucking.dm" #include "code\datums\elements\befriend_petting.dm" #include "code\datums\elements\blocks_explosives.dm" +#include "code\datums\elements\bonus_damage.dm" #include "code\datums\elements\bsa_blocker.dm" #include "code\datums\elements\bugkiller_reagent.dm" #include "code\datums\elements\bump_click.dm" @@ -1318,6 +1320,7 @@ #include "code\datums\elements\sticker.dm" #include "code\datums\elements\strippable.dm" #include "code\datums\elements\swabbable.dm" +#include "code\datums\elements\tear_wall.dm" #include "code\datums\elements\temporary_atom.dm" #include "code\datums\elements\tenacious.dm" #include "code\datums\elements\tiny_mob_hunter.dm" @@ -4172,6 +4175,8 @@ #include "code\modules\mob\living\basic\space_fauna\spider\spider_abilities\wrap.dm" #include "code\modules\mob\living\basic\space_fauna\spider\spiderlings\spiderling.dm" #include "code\modules\mob\living\basic\space_fauna\spider\spiderlings\spiderling_subtypes.dm" +#include "code\modules\mob\living\basic\space_fauna\spider\young_spider\young_spider.dm" +#include "code\modules\mob\living\basic\space_fauna\spider\young_spider\young_spider_subtypes.dm" #include "code\modules\mob\living\basic\space_fauna\statue\statue.dm" #include "code\modules\mob\living\basic\space_fauna\wumborian_fugu\fugu_gland.dm" #include "code\modules\mob\living\basic\space_fauna\wumborian_fugu\inflation.dm"