mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-26 14:39:58 +01:00
u can now hand-feed animals. like cats and raptors (#88173)
## About The Pull Request this PR does 2 things, firstly it allows u to directly feed animals from ur hand instead of having to drop it on the floor and relying on their AI to go eat it. So you can now directly feed ore to raptors or wheat to cows by simply clicking on them with the item. secondly, it links the tameable component and the eating element together, as now the former relies on signals sent by the latter. ## Why It's Good For The Game Small QOL for pet owners when it comes to feeding their animals. ## Changelog 🆑 qol: u can now directly feed animals from ur hands, like raptors or cats, by clicking on them with their preferred food. balance: u can now heal ur raptors mid or post battles by hand feeding them ores /🆑
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user