diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index ba43900425b..deb9188d76e 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -287,6 +287,8 @@ /// From /datum/element/basic_eating/finish_eating() #define COMSIG_MOB_ATE "mob_ate" + ///cancel post eating + #define COMSIG_MOB_TERMINATE_EAT (1<<0) ///From mob/living/carbon/proc/throw_mode_on and throw_mode_off #define COMSIG_LIVING_THROW_MODE_TOGGLE "living_throw_mode_toggle" diff --git a/code/datums/components/tameable.dm b/code/datums/components/tameable.dm index 0d77688a22e..747d729ee1d 100644 --- a/code/datums/components/tameable.dm +++ b/code/datums/components/tameable.dm @@ -2,8 +2,6 @@ /datum/component/tameable ///If true, this atom can only be domesticated by one person var/unique - ///What the mob eats, typically used for taming or animal husbandry. - var/list/food_types ///Starting success chance for taming. var/tame_chance ///Added success chance after every failed tame attempt. @@ -15,8 +13,6 @@ if(!isatom(parent)) //yes, you could make a tameable toolbox. return COMPONENT_INCOMPATIBLE - if(food_types) - src.food_types = food_types if(tame_chance) src.tame_chance = tame_chance src.current_tame_chance = tame_chance @@ -24,35 +20,30 @@ src.bonus_tame_chance = bonus_tame_chance src.unique = unique - RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(try_tame)) + if(food_types && !HAS_TRAIT(parent, TRAIT_MOB_EATER)) + parent.AddElement(/datum/element/basic_eating, food_types = food_types) + + RegisterSignal(parent, COMSIG_MOB_ATE, PROC_REF(try_tame)) RegisterSignal(parent, COMSIG_SIMPLEMOB_SENTIENCEPOTION, PROC_REF(on_tame)) //Instantly succeeds RegisterSignal(parent, COMSIG_SIMPLEMOB_TRANSFERPOTION, PROC_REF(on_tame)) //Instantly succeeds -/datum/component/tameable/proc/try_tame(datum/source, obj/item/food, mob/living/attacker, params) +/datum/component/tameable/proc/try_tame(atom/source, obj/item/food, mob/living/attacker) SIGNAL_HANDLER - if(!is_type_in_list(food, food_types)) - return - if(isliving(source)) - var/mob/living/potentially_dead_horse = source - if(potentially_dead_horse.stat == DEAD) - to_chat(attacker, span_warning("[parent] is dead!")) - return COMPONENT_CANCEL_ATTACK_CHAIN - var/atom/atom_parent = source + if(isnull(attacker) || already_friends(attacker)) + return + var/inform_tamer = FALSE - atom_parent.balloon_alert(attacker, "fed") var/modified_tame_chance = current_tame_chance if(HAS_TRAIT(attacker, TRAIT_BEAST_EMPATHY)) modified_tame_chance += 50 inform_tamer = TRUE - if(unique || !already_friends(attacker)) - if(prob(modified_tame_chance)) //note: lack of feedback message is deliberate, keep them guessing unless they're an expert! - on_tame(source, attacker, food, inform_tamer) - else - current_tame_chance += bonus_tame_chance - qdel(food) - return COMPONENT_CANCEL_ATTACK_CHAIN + source.balloon_alert(attacker, "eats from your hand") + if(prob(modified_tame_chance)) //note: lack of feedback message is deliberate, keep them guessing unless they're an expert! + on_tame(source, attacker, food, inform_tamer) + else + current_tame_chance += bonus_tame_chance /// Check if the passed mob is already considered one of our friends /datum/component/tameable/proc/already_friends(mob/living/potential_friend) diff --git a/code/datums/elements/basic_eating.dm b/code/datums/elements/basic_eating.dm index 4f4f493e0ef..75caa272ef9 100644 --- a/code/datums/elements/basic_eating.dm +++ b/code/datums/elements/basic_eating.dm @@ -30,16 +30,25 @@ src.drinking = drinking src.food_types = food_types - //this lets players eat + RegisterSignal(target, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(try_feed)) RegisterSignal(target, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_unarm_attack)) - //this lets ai eat. yes, i'm serious - RegisterSignal(target, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(on_pre_attackingtarget)) /datum/element/basic_eating/Detach(datum/target) REMOVE_TRAIT(target, TRAIT_MOB_EATER, REF(src)) - UnregisterSignal(target, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)) + + UnregisterSignal(target, list( + COMSIG_LIVING_UNARMED_ATTACK, + COMSIG_ATOM_ITEM_INTERACTION, + )) return ..() +/datum/element/basic_eating/proc/try_feed(atom/source, mob/living/user, atom/possible_food) + SIGNAL_HANDLER + if(user.combat_mode || !is_type_in_list(possible_food, food_types)) + return NONE + + try_eating(source, possible_food, user) + /datum/element/basic_eating/proc/on_unarm_attack(mob/living/eater, atom/target, proximity, modifiers) SIGNAL_HANDLER if(!proximity) @@ -49,14 +58,10 @@ return COMPONENT_CANCEL_ATTACK_CHAIN return NONE -/datum/element/basic_eating/proc/on_pre_attackingtarget(mob/living/eater, atom/target) - SIGNAL_HANDLER - try_eating(eater, target) - -/datum/element/basic_eating/proc/try_eating(mob/living/eater, atom/target) +/datum/element/basic_eating/proc/try_eating(mob/living/eater, atom/target, mob/living/feeder) if(!is_type_in_list(target, food_types)) return FALSE - if(SEND_SIGNAL(eater, COMSIG_MOB_PRE_EAT, target) & COMSIG_MOB_CANCEL_EAT) + if(SEND_SIGNAL(eater, COMSIG_MOB_PRE_EAT, target, feeder) & COMSIG_MOB_CANCEL_EAT) return FALSE var/eat_verb if(drinking) @@ -75,21 +80,22 @@ if (damage_amount > 0 && damage_type) eater.apply_damage(damage_amount, damage_type) eater.visible_message(span_notice("[eater] [eat_verb]s [target], and seems to hurt itself."), span_notice("You [eat_verb] [target], hurting yourself in the process.")) - finish_eating(eater, target) + finish_eating(eater, target, feeder) return TRUE eater.visible_message(span_notice("[eater] [eat_verb]s [target]."), span_notice("You [eat_verb] [target].")) - finish_eating(eater, target) + finish_eating(eater, target, feeder) return TRUE -/datum/element/basic_eating/proc/finish_eating(mob/living/eater, atom/target) +/datum/element/basic_eating/proc/finish_eating(mob/living/eater, atom/target, mob/living/feeder) set waitfor = FALSE - SEND_SIGNAL(eater, COMSIG_MOB_ATE) if(drinking) playsound(eater.loc,'sound/items/drink.ogg', rand(10,50), TRUE) else playsound(eater.loc,'sound/items/eatfood.ogg', rand(10,50), TRUE) var/atom/final_target = target + if(SEND_SIGNAL(eater, COMSIG_MOB_ATE, final_target, feeder) & COMSIG_MOB_TERMINATE_EAT) + return if(isstack(target)) //if stack, only consume 1 var/obj/item/stack/food_stack = target final_target = food_stack.split_stack(eater, 1) diff --git a/code/modules/mob/living/basic/clown/clown.dm b/code/modules/mob/living/basic/clown/clown.dm index ebc15182c2f..a8fb645af73 100644 --- a/code/modules/mob/living/basic/clown/clown.dm +++ b/code/modules/mob/living/basic/clown/clown.dm @@ -403,7 +403,11 @@ GRANT_ACTION(/datum/action/cooldown/regurgitate) AddElement(/datum/element/swabable, CELL_LINE_TABLE_GLUTTON, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) - AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/cheesiehonkers, /obj/item/food/cornchips), tame_chance = 30, bonus_tame_chance = 0) + var/static/list/food_types = list( + /obj/item/food/cheesiehonkers, + /obj/item/food/cornchips, + ) + AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 30, bonus_tame_chance = 0) AddElement(/datum/element/damage_threshold, 10) //lots of fat to cushion blows. /mob/living/basic/clown/mutant/glutton/attacked_by(obj/item/item, mob/living/user) diff --git a/code/modules/mob/living/basic/farm_animals/cow/_cow.dm b/code/modules/mob/living/basic/farm_animals/cow/_cow.dm index c26530b5f32..a07a70d0172 100644 --- a/code/modules/mob/living/basic/farm_animals/cow/_cow.dm +++ b/code/modules/mob/living/basic/farm_animals/cow/_cow.dm @@ -76,7 +76,6 @@ if(!food_types) food_types = src.food_types.Copy() AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 25, bonus_tame_chance = 15) - AddElement(/datum/element/basic_eating, food_types = food_types) /mob/living/basic/cow/tamed(mob/living/tamer, atom/food) visible_message("[src] [tame_message] as it seems to bond with [tamer].", "You [self_tame_message], recognizing [tamer] as your new pal.") diff --git a/code/modules/mob/living/basic/farm_animals/cow/cow_moonicorn.dm b/code/modules/mob/living/basic/farm_animals/cow/cow_moonicorn.dm index 47f11a02839..d11968128aa 100644 --- a/code/modules/mob/living/basic/farm_animals/cow/cow_moonicorn.dm +++ b/code/modules/mob/living/basic/farm_animals/cow/cow_moonicorn.dm @@ -32,7 +32,6 @@ var/static/list/food_types if(!food_types) food_types = src.food_types.Copy() - AddElement(/datum/element/basic_eating, food_types = food_types) AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 25, bonus_tame_chance = 15) /mob/living/basic/cow/moonicorn/tamed(mob/living/tamer, atom/food) diff --git a/code/modules/mob/living/basic/farm_animals/pig.dm b/code/modules/mob/living/basic/farm_animals/pig.dm index 412104617a5..270b9b4e859 100644 --- a/code/modules/mob/living/basic/farm_animals/pig.dm +++ b/code/modules/mob/living/basic/farm_animals/pig.dm @@ -48,7 +48,8 @@ ///wrapper for the tameable component addition so you can have non tamable cow subtypes /mob/living/basic/pig/proc/make_tameable() - AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/grown/carrot), tame_chance = 25, bonus_tame_chance = 15) + var/list/food_types = string_list(list(/obj/item/food/grown/carrot)) + AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 25, bonus_tame_chance = 15) /mob/living/basic/pig/tamed(mob/living/tamer, atom/food) AddElement(/datum/element/ridable, /datum/component/riding/creature/pig) diff --git a/code/modules/mob/living/basic/farm_animals/pony.dm b/code/modules/mob/living/basic/farm_animals/pony.dm index b73dac39451..d2f897fc823 100644 --- a/code/modules/mob/living/basic/farm_animals/pony.dm +++ b/code/modules/mob/living/basic/farm_animals/pony.dm @@ -53,7 +53,10 @@ AddElement(/datum/element/ai_retaliate) AddElement(/datum/element/ai_flee_while_injured) AddElementTrait(TRAIT_WADDLING, INNATE_TRAIT, /datum/element/waddling) - AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/grown/apple), tame_chance = 25, bonus_tame_chance = 15, unique = unique_tamer) + var/static/list/food_types = list( + /obj/item/food/grown/apple, + ) + AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 25, bonus_tame_chance = 15, unique = unique_tamer) /mob/living/basic/pony/tamed(mob/living/tamer, atom/food) playsound(src, 'sound/mobs/non-humanoids/pony/snort.ogg', 50) @@ -161,4 +164,5 @@ ponycolors = list("#5d566f", pick_weight(mane_colors)) name = pick("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday") // Only one person can tame these fellas, and they only need one apple - AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/grown/apple), tame_chance = 100, bonus_tame_chance = 15, unique = unique_tamer) + var/static/list/food_types = list(/obj/item/food/grown/apple) + AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 100, bonus_tame_chance = 15, unique = unique_tamer) diff --git a/code/modules/mob/living/basic/icemoon/wolf/wolf.dm b/code/modules/mob/living/basic/icemoon/wolf/wolf.dm index 3708d754ab4..b82092147f6 100644 --- a/code/modules/mob/living/basic/icemoon/wolf/wolf.dm +++ b/code/modules/mob/living/basic/icemoon/wolf/wolf.dm @@ -66,7 +66,8 @@ make_tameable() /mob/living/basic/mining/wolf/proc/make_tameable() - AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/meat/slab), tame_chance = 15, bonus_tame_chance = 5) + var/static/list/food_types = list(/obj/item/food/meat/slab) + AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 15, bonus_tame_chance = 5) /mob/living/basic/mining/wolf/tamed(mob/living/tamer, atom/food) new /obj/effect/temp_visual/heart(src.loc) diff --git a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm index 26c0d79540a..5a1166962be 100644 --- a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm +++ b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm @@ -67,6 +67,7 @@ ADD_TRAIT(src, TRAIT_BOULDER_BREAKER, INNATE_TRAIT) ADD_TRAIT(src, TRAIT_INSTANTLY_PROCESSES_BOULDERS, INNATE_TRAIT) RegisterSignal(src, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(block_bullets)) + RegisterSignal(src, COMSIG_MOB_ATE, PROC_REF(on_eat)) /mob/living/basic/mining/goldgrub/proc/block_bullets(datum/source, obj/projectile/hitting_projectile) SIGNAL_HANDLER @@ -105,7 +106,8 @@ return ..() /mob/living/basic/mining/goldgrub/proc/make_tameable() - AddComponent(/datum/component/tameable, food_types = list(/obj/item/stack/ore), tame_chance = 25, bonus_tame_chance = 5) + var/list/food_types = string_list(list(/obj/item/stack/ore)) + AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 25, bonus_tame_chance = 5) /mob/living/basic/mining/goldgrub/tamed(mob/living/tamer, atom/food) new /obj/effect/temp_visual/heart(src.loc) @@ -127,13 +129,18 @@ . = ..() if(!istype(arrived, /obj/item/stack/ore)) return - playsound(src,'sound/items/eatfood.ogg', rand(10,50), TRUE) if(!can_lay_eggs) return if(!istype(arrived, /obj/item/stack/ore/bluespace_crystal) || prob(60)) return new /obj/item/food/egg/green/grub_egg(get_turf(src)) +/mob/living/basic/mining/goldgrub/proc/on_eat(atom/source, atom/movable/food, mob/feeder) + SIGNAL_HANDLER + + food.forceMove(src) + return COMSIG_MOB_TERMINATE_EAT + /mob/living/basic/mining/goldgrub/baby icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi' name = "goldgrub baby" diff --git a/code/modules/mob/living/basic/lavaland/goliath/goliath.dm b/code/modules/mob/living/basic/lavaland/goliath/goliath.dm index 76feb1f4bd4..f8a7ee46bc3 100644 --- a/code/modules/mob/living/basic/lavaland/goliath/goliath.dm +++ b/code/modules/mob/living/basic/lavaland/goliath/goliath.dm @@ -68,7 +68,8 @@ AddComponent(/datum/component/basic_mob_attack_telegraph) AddComponentFrom(INNATE_TRAIT, /datum/component/shovel_hands) if (tameable) - AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/grown/ash_flora), tame_chance = 10, bonus_tame_chance = 5) + var/static/list/food_types = list(/obj/item/food/grown/ash_flora) + AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 10, bonus_tame_chance = 5) tentacles = new (src) tentacles.Grant(src) diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm index ebca48f2fa2..0b8babf82ec 100644 --- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm +++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm @@ -184,7 +184,7 @@ optional_checks = CALLBACK(src, PROC_REF(ready_to_grow)),\ optional_grow_behavior = CALLBACK(src, PROC_REF(grow_up))\ ) - AddComponent(/datum/component/tameable, target_foods, tame_chance = 35, bonus_tame_chance = 20) + AddComponent(/datum/component/tameable, tame_chance = 35, bonus_tame_chance = 20) AddComponent(/datum/component/swarming, 16, 11) ADD_TRAIT(src, TRAIT_MOB_HIDE_HAPPINESS, INNATE_TRAIT) //Do not let strangers know it gets happy when poked if stray. diff --git a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm index 5166211b138..8bf54b7165b 100644 --- a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm +++ b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm @@ -97,7 +97,7 @@ GLOBAL_LIST_EMPTY(raptor_population) ai_controller.set_blackboard_key(BB_BASIC_MOB_SPEAK_LINES, display_emote) inherited_stats = new inherit_properties() - var/static/list/my_food = list(/obj/item/stack/ore) + var/list/my_food = string_list(list(/obj/item/stack/ore)) AddElement(/datum/element/basic_eating, food_types = my_food) AddElement(/datum/element/ai_retaliate) AddElement(/datum/element/ai_flee_while_injured, stop_fleeing_at = 0.5, start_fleeing_below = 0.2) diff --git a/code/modules/mob/living/basic/pets/dog/_dog.dm b/code/modules/mob/living/basic/pets/dog/_dog.dm index b5259d275b5..fd8920d2ca0 100644 --- a/code/modules/mob/living/basic/pets/dog/_dog.dm +++ b/code/modules/mob/living/basic/pets/dog/_dog.dm @@ -68,7 +68,11 @@ AddElement(/datum/element/pet_bonus, "woof") AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW) AddElement(/datum/element/unfriend_attacker, untamed_reaction = "%SOURCE% fixes %TARGET% with a look of betrayal.") - AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/meat/slab/human/mutant/skeleton, /obj/item/stack/sheet/bone), tame_chance = 30, bonus_tame_chance = 15, unique = FALSE) + var/static/list/food_types = list( + /obj/item/food/meat/slab/human/mutant/skeleton, + /obj/item/stack/sheet/bone, + ) + AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 30, bonus_tame_chance = 15, unique = FALSE) AddComponent(/datum/component/obeys_commands, pet_commands) var/dog_area = get_area(src) for(var/obj/structure/bed/dogbed/dog_bed in dog_area) diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp.dm b/code/modules/mob/living/basic/space_fauna/carp/carp.dm index acd72af2b38..6f843857578 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp.dm @@ -111,7 +111,8 @@ tamed(tamer, feedback = FALSE) befriend(tamer) else - AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/meat), tame_chance = 10, bonus_tame_chance = 5) + var/static/list/food_types = list(/obj/item/food/meat) + AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 10, bonus_tame_chance = 5) teleport = new(src) teleport.Grant(src) diff --git a/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm b/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm index 9c56ec044c7..66e73b2bbfa 100644 --- a/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm +++ b/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm @@ -58,7 +58,8 @@ grant_actions_by_list(innate_actions) AddElement(/datum/element/simple_flying) - AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/grown/carrot), tame_chance = 100) + var/list/food_types = string_list(list(/obj/item/food/grown/carrot)) + AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 100) ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) on_hit_overlay = mutable_appearance(icon, "[icon_state]_crying") diff --git a/code/modules/mob/living/basic/vermin/mouse.dm b/code/modules/mob/living/basic/vermin/mouse.dm index a0c1faf971d..0ded016d1a0 100644 --- a/code/modules/mob/living/basic/vermin/mouse.dm +++ b/code/modules/mob/living/basic/vermin/mouse.dm @@ -83,7 +83,8 @@ if (tame) faction |= FACTION_NEUTRAL else - AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/cheese), tame_chance = 100) + var/static/list/food_types = list(/obj/item/food/cheese) + AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 100) /mob/living/basic/mouse/Destroy() SSmobs.cheeserats -= src diff --git a/code/modules/mob/living/simple_animal/hostile/vatbeast.dm b/code/modules/mob/living/simple_animal/hostile/vatbeast.dm index 8eab28a52e6..56dcbcaf7e1 100644 --- a/code/modules/mob/living/simple_animal/hostile/vatbeast.dm +++ b/code/modules/mob/living/simple_animal/hostile/vatbeast.dm @@ -31,7 +31,13 @@ GRANT_ACTION(/datum/action/cooldown/tentacle_slap) add_cell_sample() - AddComponent(/datum/component/tameable, list(/obj/item/food/fries, /obj/item/food/cheesyfries, /obj/item/food/cornchips, /obj/item/food/carrotfries), tame_chance = 30, bonus_tame_chance = 0) + var/static/list/food_types = list( + /obj/item/food/fries, + /obj/item/food/cheesyfries, + /obj/item/food/cornchips, + /obj/item/food/carrotfries, + ) + AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 30, bonus_tame_chance = 0) /mob/living/simple_animal/hostile/vatbeast/tamed(mob/living/tamer, obj/item/food) buckle_lying = 0