From b86cde05213d4d3db1158c8636e4fbe418ce87df Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Thu, 6 Jun 2024 14:51:50 +0200 Subject: [PATCH] [MIRROR] Sentient mobs can slowly subtract slime stacks by shaking (#28006) * Sentient mobs can slowly subtract slime stacks by shaking (#83471) ## About The Pull Request Closes #82746 PR #77569 replaced the clone damage inflicted by slimes with a lingering damage over time effect which can be removed with water. This is all well and good for humans who can spray themselves with fire extinguishers, showers, or sinks... but most other mobs are not actually capable of opearating any form of equipment which can make them wet. This PR allows you to click on the debuff icon to shake the slime off slowly over time (15 seconds to fully remove the debuff). This is slower than the recovery time when wet. Dogs, Cats, and by extension, Felinids are better at removing slime because of their self-cleaning prowess (they're always licking weird stuff off themselves). This is rarely helpful if you're not a Felinid, because almost all cats and dogs have so little health that they will hit the minimum health threshold and lose the debuff anyway by the time they would be done. In the very niche circumstance that a sentient wolf is attacked by a slime they will appreciate this bonus. ## Why It's Good For The Game This was a replacement for slimes inflicting clone damage (I am not sure this even did anything for most simple mobs?) but essentially turned slimes into an automatic death sentence for most forms of mob without hands. Technically the slime debuff cannot kill you and stops if you are under 10 HP, but this is small consolation for most of these mobs which cannot heal themselves either. You are still probably going to take between 30-60 damage during the 15 seconds of removing slime from your body. ## Changelog :cl: balance: Corrosive slime left behind after a slime fails to eat you can be scraped off with your hands, or shaken off in some other way, by clicking on the debuff. This is slower and less effective than washing it off using water. /:cl: * Sentient mobs can slowly subtract slime stacks by shaking --------- Co-authored-by: Jacquerel --- code/__DEFINES/traits/declarations.dm | 2 + code/_globalvars/traits/_traits.dm | 1 + .../status_effects/debuffs/slime/slimed.dm | 56 +++++++++++++++---- code/datums/wounds/slash.dm | 2 +- .../mob/living/basic/icemoon/wolf/wolf.dm | 1 + code/modules/mob/living/basic/pets/cat/cat.dm | 2 +- .../modules/mob/living/basic/pets/dog/_dog.dm | 1 + .../surgery/organs/internal/tongue/_tongue.dm | 1 + 8 files changed, 53 insertions(+), 13 deletions(-) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 8f122c5be7c..254dee79055 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -228,6 +228,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_PROFOUND_FISHER "profound_fisher" /// This trait lets you evaluate someone's fitness level against your own #define TRAIT_EXAMINE_FITNESS "reveal_power_level" +/// These mobs have particularly hygienic tongues +#define TRAIT_WOUND_LICKER "wound_licker" /// Added to a mob, allows that mob to experience flavour-based moodlets when examining food #define TRAIT_REMOTE_TASTING "remote_tasting" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 779b56ce01d..28100977dc0 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -498,6 +498,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_WINE_TASTER" = TRAIT_WINE_TASTER, "TRAIT_WING_BUFFET" = TRAIT_WING_BUFFET, "TRAIT_WING_BUFFET_TIRED" = TRAIT_WING_BUFFET_TIRED, + "TRAIT_WOUND_LICKER" = TRAIT_WOUND_LICKER, "TRAIT_XENO_HOST" = TRAIT_XENO_HOST, "TRAIT_XENO_IMMUNE" = TRAIT_XENO_IMMUNE, "TRAIT_XRAY_HEARING" = TRAIT_XRAY_HEARING, diff --git a/code/datums/status_effects/debuffs/slime/slimed.dm b/code/datums/status_effects/debuffs/slime/slimed.dm index 15632277f3d..6c2c0fb5be3 100644 --- a/code/datums/status_effects/debuffs/slime/slimed.dm +++ b/code/datums/status_effects/debuffs/slime/slimed.dm @@ -5,9 +5,42 @@ /atom/movable/screen/alert/status_effect/slimed name = "Covered in Slime" - desc = "You are covered in slime and it's eating away at you! Find a way to wash it off!" + desc = "You are covered in slime and it's eating away at you! Click to start cleaning it off, or find a faster way to wash it away!" icon_state = "slimed" +/atom/movable/screen/alert/status_effect/slimed/Click() + . = ..() + if (!.) + return FALSE + if (!can_wash()) + return FALSE + INVOKE_ASYNC(src, PROC_REF(remove_slime)) + return TRUE + +/// Confirm that we are capable of washing off slime +/atom/movable/screen/alert/status_effect/slimed/proc/can_wash() + var/mob/living/living_owner = owner + if (!living_owner.can_resist()) + return FALSE + if (DOING_INTERACTION_WITH_TARGET(owner, owner)) + return FALSE + if (locate(/datum/status_effect/fire_handler/wet_stacks) in living_owner.status_effects) + return FALSE // Don't double dip with washing + return TRUE + +/// Try to get rid of it +/atom/movable/screen/alert/status_effect/slimed/proc/remove_slime() + owner.balloon_alert(owner, "cleaning off slime...") + var/datum/status_effect/slimed/slime_effect = owner.has_status_effect(/datum/status_effect/slimed) + while (!QDELETED(src) && !isnull(slime_effect)) + if (!can_wash()) + return + var/clean_interval = HAS_TRAIT(owner, TRAIT_WOUND_LICKER) ? 1.2 SECONDS : 1.5 SECONDS + owner.Shake(2, 0, duration = clean_interval * 0.8, shake_interval = 0.05 SECONDS) + if (!do_after(owner, clean_interval, owner)) + return + slime_effect.remove_stacks() + /datum/status_effect/slimed id = "slimed" tick_interval = 3 SECONDS @@ -32,6 +65,16 @@ to_chat(owner, span_userdanger("You have been covered in a thick layer of slime! Find a way to wash it off!")) return ..() +/datum/status_effect/slimed/proc/remove_stacks(stacks_to_remove = 1) + slime_stacks -= stacks_to_remove // lose 1 stack per second + if(slime_stacks <= 0) + to_chat(owner, span_notice("You manage to wash off the layer of slime completely.")) + qdel(src) + return + + if(prob(10)) + to_chat(owner,span_warning("The layer of slime is slowly getting thinner.")) + /datum/status_effect/slimed/tick(seconds_between_ticks) // remove from the mob once we have dealt enough damage if(owner.get_organic_health() <= MIN_HEALTH) @@ -42,20 +85,11 @@ // handle washing slime off var/datum/status_effect/fire_handler/wet_stacks/wetness = locate() in owner.status_effects if(istype(wetness) && wetness.stacks > (MIN_WATER_STACKS * seconds_between_ticks)) - slime_stacks -= seconds_between_ticks // lose 1 stack per second wetness.adjust_stacks(-5 * seconds_between_ticks) - - // got rid of it + remove_stacks(seconds_between_ticks) // 1 per second if(slime_stacks <= 0) - to_chat(owner, span_notice("You manage to wash off the layer of slime completely.")) - qdel(src) return - if(SPT_PROB(10, seconds_between_ticks)) - to_chat(owner,span_warning("The layer of slime is slowly getting thinner as it's washing off your skin.")) - - return - // otherwise deal brute damage owner.apply_damage(rand(2,4) * seconds_between_ticks, damagetype = BRUTE) diff --git a/code/datums/wounds/slash.dm b/code/datums/wounds/slash.dm index 980cb712484..0e370c2ffca 100644 --- a/code/datums/wounds/slash.dm +++ b/code/datums/wounds/slash.dm @@ -189,7 +189,7 @@ return suture(I, user) /datum/wound/slash/flesh/try_handling(mob/living/carbon/human/user) - if(user.pulling != victim || user.zone_selected != limb.body_zone || !isfelinid(user) || !victim.try_inject(user, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE)) + if(user.pulling != victim || user.zone_selected != limb.body_zone || !HAS_TRAIT(user, TRAIT_WOUND_LICKER) || !victim.try_inject(user, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE)) return FALSE if(DOING_INTERACTION_WITH_TARGET(user, victim)) to_chat(user, span_warning("You're already interacting with [victim]!")) diff --git a/code/modules/mob/living/basic/icemoon/wolf/wolf.dm b/code/modules/mob/living/basic/icemoon/wolf/wolf.dm index e452c156474..b7a947f00e3 100644 --- a/code/modules/mob/living/basic/icemoon/wolf/wolf.dm +++ b/code/modules/mob/living/basic/icemoon/wolf/wolf.dm @@ -55,6 +55,7 @@ /mob/living/basic/mining/wolf/Initialize(mapload) . = ..() + ADD_TRAIT(src, TRAIT_WOUND_LICKER, INNATE_TRAIT) AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW) AddElement(/datum/element/ai_flee_while_injured) AddElement(/datum/element/ai_retaliate) diff --git a/code/modules/mob/living/basic/pets/cat/cat.dm b/code/modules/mob/living/basic/pets/cat/cat.dm index 3c2612d9a62..400bd9ac9f1 100644 --- a/code/modules/mob/living/basic/pets/cat/cat.dm +++ b/code/modules/mob/living/basic/pets/cat/cat.dm @@ -58,7 +58,7 @@ AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_CLAW) add_cell_sample() add_verb(src, /mob/living/proc/toggle_resting) - add_traits(list(TRAIT_CATLIKE_GRACE, TRAIT_VENTCRAWLER_ALWAYS), INNATE_TRAIT) + add_traits(list(TRAIT_CATLIKE_GRACE, TRAIT_VENTCRAWLER_ALWAYS, TRAIT_WOUND_LICKER), INNATE_TRAIT) ai_controller.set_blackboard_key(BB_HUNTABLE_PREY, typecacheof(huntable_items)) if(can_breed) add_breeding_component() diff --git a/code/modules/mob/living/basic/pets/dog/_dog.dm b/code/modules/mob/living/basic/pets/dog/_dog.dm index f513795e7f6..5cd970575ec 100644 --- a/code/modules/mob/living/basic/pets/dog/_dog.dm +++ b/code/modules/mob/living/basic/pets/dog/_dog.dm @@ -47,6 +47,7 @@ /mob/living/basic/pet/dog/Initialize(mapload) . = ..() + ADD_TRAIT(src, TRAIT_WOUND_LICKER, INNATE_TRAIT) AddElement(/datum/element/pet_bonus, "woofs happily!") AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW) AddElement(/datum/element/unfriend_attacker, untamed_reaction = "%SOURCE% fixes %TARGET% with a look of betrayal.") diff --git a/code/modules/surgery/organs/internal/tongue/_tongue.dm b/code/modules/surgery/organs/internal/tongue/_tongue.dm index c01b5938124..a47639fe0e6 100644 --- a/code/modules/surgery/organs/internal/tongue/_tongue.dm +++ b/code/modules/surgery/organs/internal/tongue/_tongue.dm @@ -617,6 +617,7 @@ GLOBAL_LIST_INIT(english_to_zombie, list()) say_mod = "meows" liked_foodtypes = SEAFOOD | ORANGES | BUGS | GORE disliked_foodtypes = GROSS | CLOTH | RAW + organ_traits = list(TRAIT_WOUND_LICKER) /obj/item/organ/internal/tongue/jelly name = "jelly tongue"