From e43a88de5bd7ca5b66e7eca5ecb1517c690a1bef Mon Sep 17 00:00:00 2001 From: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com> Date: Tue, 19 Aug 2025 09:40:31 -0400 Subject: [PATCH] Converts Nian Caterpillars to Basic Mob AI (#29938) * Nian Caterpillar Basic Mob * Merge conflict resolution --------- Signed-off-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com> --- code/__DEFINES/mob_defines.dm | 2 +- .../structures/crates_lockers/crittercrate.dm | 2 +- code/modules/food_and_drinks/food_base.dm | 2 +- .../friendly/nian_caterpillar.dm | 103 +++++++++++++----- paradise.dme | 2 +- 5 files changed, 79 insertions(+), 32 deletions(-) rename code/modules/mob/living/{simple_animal => basic}/friendly/nian_caterpillar.dm (56%) diff --git a/code/__DEFINES/mob_defines.dm b/code/__DEFINES/mob_defines.dm index bca02adda14..3f6ef0995df 100644 --- a/code/__DEFINES/mob_defines.dm +++ b/code/__DEFINES/mob_defines.dm @@ -252,7 +252,7 @@ #define isbot(A) (istype((A), /mob/living/simple_animal/bot)) #define isguardian(A) (istype((A), /mob/living/simple_animal/hostile/guardian)) #define isnymph(A) (istype((A), /mob/living/simple_animal/diona)) -#define iscaterpillar(A) (istype((A), /mob/living/simple_animal/nian_caterpillar)) +#define iscaterpillar(A) (istype((A), /mob/living/basic/nian_caterpillar)) #define ishostile(A) (istype((A), /mob/living/simple_animal/hostile)) #define isretaliate(A) (istype((A), /mob/living/simple_animal/hostile/retaliate)) #define isterrorspider(A) (istype((A), /mob/living/simple_animal/hostile/poison/terror_spider)) diff --git a/code/game/objects/structures/crates_lockers/crittercrate.dm b/code/game/objects/structures/crates_lockers/crittercrate.dm index 8c330c5b57f..04bfe0d1a14 100644 --- a/code/game/objects/structures/crates_lockers/crittercrate.dm +++ b/code/game/objects/structures/crates_lockers/crittercrate.dm @@ -112,7 +112,7 @@ /obj/structure/closet/critter/nian_caterpillar name = "nian caterpillar crate" - content_mob = /mob/living/simple_animal/nian_caterpillar + content_mob = /mob/living/basic/nian_caterpillar /obj/structure/closet/critter/deer name = "deer crate" diff --git a/code/modules/food_and_drinks/food_base.dm b/code/modules/food_and_drinks/food_base.dm index 1d656a550b1..cd8301cbf20 100644 --- a/code/modules/food_and_drinks/food_base.dm +++ b/code/modules/food_and_drinks/food_base.dm @@ -275,7 +275,7 @@ N.adjustHealth(-2) N.taste(reagents) else if(iscaterpillar(M)) - var/mob/living/simple_animal/nian_caterpillar/W = M + var/mob/living/basic/nian_caterpillar/W = M W.taste(reagents) W.consume(src) diff --git a/code/modules/mob/living/simple_animal/friendly/nian_caterpillar.dm b/code/modules/mob/living/basic/friendly/nian_caterpillar.dm similarity index 56% rename from code/modules/mob/living/simple_animal/friendly/nian_caterpillar.dm rename to code/modules/mob/living/basic/friendly/nian_caterpillar.dm index 376ec0aabb0..b16847c5585 100644 --- a/code/modules/mob/living/simple_animal/friendly/nian_caterpillar.dm +++ b/code/modules/mob/living/basic/friendly/nian_caterpillar.dm @@ -1,4 +1,4 @@ -/mob/living/simple_animal/nian_caterpillar +/mob/living/basic/nian_caterpillar name = "nian caterpillar" icon = 'icons/mob/monkey.dmi' icon_state = "mothroach" @@ -11,49 +11,65 @@ ventcrawler = VENTCRAWLER_ALWAYS atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) butcher_results = list(/obj/item/food/meat = 1) - minbodytemp = 0 + minimum_survivable_temperature = 0 blood_color = "#b9ae9c" maxHealth = 50 health = 50 speed = 0.75 - turns_per_move = 4 // What they sound like voice_name = "nian caterpillar" speak_emote = list("flutters", "chitters", "chatters") - emote_hear = list("flutters", "chitters", "chatters") - emote_see = list("flutters", "chitters", "chatters") // Special verbs for when someone interacts with a caterpillar - response_help = "pets" - response_disarm = "shoos" - response_harm = "kicks" + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "shoos" + response_disarm_simple = "shoo" + response_harm_continuous = "kicks" + response_harm_simple = "kicks" // Xenobiology and cargo are the only ways to get the caterpillar. gold_core_spawnable = FRIENDLY_SPAWN + melee_attack_cooldown_min = 1.5 SECONDS + melee_attack_cooldown_max = 2.5 SECONDS melee_damage_lower = 5 melee_damage_upper = 8 - attacktext = "bites" + attack_verb_continuous = "bites" + attack_verb_simple = "bite" attack_sound = 'sound/weapons/bite.ogg' holder_type = /obj/item/holder/nian_caterpillar - /// Evolution action. - var/datum/action/innate/nian_caterpillar_emerge/evolve_action = new() + ai_controller = /datum/ai_controller/basic_controller/mothroach + + var/list/innate_actions = list( + /datum/action/innate/nian_caterpillar_emerge, + ) + + /// List of stuff that we want to eat + var/static/list/edibles = list( + /obj/item/food, + ) /// The amount of nutrition the nian caterpillar needs to evolve, default is 500. var/nutrition_need = 500 -/mob/living/simple_animal/nian_caterpillar/Initialize(mapload) +/mob/living/basic/nian_caterpillar/Initialize(mapload) . = ..() real_name = name AddElement(/datum/element/wears_collar) + AddElement(/datum/element/ai_retaliate) + AddElement(/datum/element/basic_eating, heal_amt_ = 2, food_types_ = edibles) + ai_controller.set_blackboard_key(BB_BASIC_FOODS, typecacheof(edibles)) add_language("Tkachi") - evolve_action.Grant(src) + grant_actions_by_list(innate_actions) + RegisterSignal(src, COMSIG_MOB_PRE_EAT, PROC_REF(check_full)) + RegisterSignal(src, COMSIG_MOB_ATE, PROC_REF(consume)) -/mob/living/simple_animal/nian_caterpillar/proc/evolve(obj/structure/moth_cocoon/C, datum/mind/M) +/mob/living/basic/nian_caterpillar/proc/evolve(obj/structure/moth_cocoon/C, datum/mind/M) if(stat != CONSCIOUS) return FALSE @@ -80,10 +96,11 @@ adult.name = name adult.real_name = name - // Mind transfer to new worme. - M.transfer_to(adult) - // [Caterpillar -> worme -> nian] is from xenobio (or cargo) and does not give vampires usuble blood and cannot be converted by cult. - ADD_TRAIT(adult.mind, TRAIT_XENOBIO_SPAWNED_HUMAN, ROUNDSTART_TRAIT) + if(M) + // Mind transfer to new worme. + M.transfer_to(adult) + // [Caterpillar -> worme -> nian] is from xenobio (or cargo) and does not give vampires usuble blood and cannot be converted by cult. + ADD_TRAIT(adult.mind, TRAIT_XENOBIO_SPAWNED_HUMAN, ROUNDSTART_TRAIT) // Worme is placed into cacoon. adult.forceMove(C) @@ -103,18 +120,21 @@ qdel(src) return TRUE -/mob/living/simple_animal/nian_caterpillar/proc/consume(obj/item/food/G) +/mob/living/basic/nian_caterpillar/proc/check_full(datum/source, obj/item/potential_food) + SIGNAL_HANDLER // COMSIG_MOB_PRE_EAT if(nutrition >= nutrition_need) // Prevents griefing by overeating food items without evolving. - return to_chat(src, "You're too full to consume this! Perhaps it's time to grow bigger...") - visible_message("[src] ravenously consumes [G].", "You ravenously devour [G].") - playsound(loc, 'sound/items/eatfood.ogg', 30, TRUE, frequency = 1.5) - if(G.reagents.get_reagent_amount("nutriment") + G.reagents.get_reagent_amount("plantmatter") < 1) + to_chat(src, "You're too full to consume this! Perhaps it's time to grow bigger...") + return COMSIG_MOB_TERMINATE_EAT + + +/mob/living/basic/nian_caterpillar/proc/consume(datum/source, obj/item/potential_food) + SIGNAL_HANDLER // COMSIG_MOB_ATE + if(potential_food.reagents.get_reagent_amount("nutriment") + potential_food.reagents.get_reagent_amount("plantmatter") < 1) adjust_nutrition(2) else - adjust_nutrition((G.reagents.get_reagent_amount("nutriment") + G.reagents.get_reagent_amount("plantmatter")) * 2) - qdel(G) + adjust_nutrition((potential_food.reagents.get_reagent_amount("nutriment") + potential_food.reagents.get_reagent_amount("plantmatter")) * 2) -/mob/living/simple_animal/nian_caterpillar/attack_hand(mob/living/carbon/human/M) +/mob/living/basic/nian_caterpillar/attack_hand(mob/living/carbon/human/M) // Let people pick the little buggers up. if(M.a_intent != INTENT_HELP) return ..() @@ -123,12 +143,16 @@ else get_scooped(M) -/mob/living/simple_animal/nian_caterpillar/attacked_by(obj/item/I, mob/living/user) +/mob/living/basic/nian_caterpillar/attacked_by(obj/item/I, mob/living/user) if(..()) return FINISH_ATTACK if(istype(I, /obj/item/melee/flyswatter) && I.force) gib() // Commit die. +/mob/living/basic/nian_caterpillar/melee_attack(atom/target, list/modifiers, ignore_cooldown) + . = ..() + + /datum/action/innate/nian_caterpillar_emerge name = "Evolve" desc = "Weave a cocoon around yourself to evolve into a greater form. The worme." @@ -143,7 +167,7 @@ qdel(C) /datum/action/innate/nian_caterpillar_emerge/Activate() - var/mob/living/simple_animal/nian_caterpillar/user = owner + var/mob/living/basic/nian_caterpillar/user = owner user.visible_message("[user] begins to hold still and concentrate on weaving a cocoon...", "You begin to focus on weaving a cocoon... (This will take [COCOON_WEAVE_DELAY / 10] seconds, and you must hold still.)") if(do_after(user, COCOON_WEAVE_DELAY, FALSE, user)) @@ -151,3 +175,26 @@ var/datum/mind/H = user.mind user.evolve(C, H) addtimer(CALLBACK(src, PROC_REF(emerge), C), COCOON_EMERGE_DELAY, TIMER_UNIQUE) + +/datum/ai_controller/basic_controller/mothroach + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_EAT_FOOD_COOLDOWN = 1 MINUTES, // Moth wants to eat, but not too fast. + BB_SEARCH_RANGE = 3, + ) + + ai_traits = AI_FLAG_STOP_MOVING_WHEN_PULLED | AI_FLAG_PAUSE_DURING_DO_AFTER + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/random_speech/moth_caterpillar, + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, + /datum/ai_planning_subtree/flee_target, + /datum/ai_planning_subtree/find_food, + ) + +/datum/ai_planning_subtree/random_speech/moth_caterpillar + speech_chance = 2 + emote_hear = list("flutters.", "chitters.", "chatters.") + emote_see = list("flutters.", "chitters.", "chatters.") + diff --git a/paradise.dme b/paradise.dme index d1b37be4498..772467d1930 100644 --- a/paradise.dme +++ b/paradise.dme @@ -2424,6 +2424,7 @@ #include "code\modules\mob\living\taste.dm" #include "code\modules\mob\living\basic\basic_emotes.dm" #include "code\modules\mob\living\basic\basic_mob.dm" +#include "code\modules\mob\living\basic\friendly\nian_caterpillar.dm" #include "code\modules\mob\living\basic\posessed_object.dm" #include "code\modules\mob\living\basic\farm_animals\cow.dm" #include "code\modules\mob\living\basic\farm_animals\deer.dm" @@ -2661,7 +2662,6 @@ #include "code\modules\mob\living\simple_animal\friendly\fox.dm" #include "code\modules\mob\living\simple_animal\friendly\friendly_emote.dm" #include "code\modules\mob\living\simple_animal\friendly\mouse.dm" -#include "code\modules\mob\living\simple_animal\friendly\nian_caterpillar.dm" #include "code\modules\mob\living\simple_animal\friendly\pet.dm" #include "code\modules\mob\living\simple_animal\friendly\spiderbot.dm" #include "code\modules\mob\living\simple_animal\hostile\angel_statue.dm"