Essential Pet Interactions (#7633)

tweak: "Pets have more discipline regarding food. They will no longer beg for food, seek it out, run towards it, steal it, or eat like there's an endless void in their stomachs. They'll still eat food on their tile if sufficiently hungry, and you can still feed pets by hand, if you'd like. Chefs, rejoice!"
    tweak: "Corgi stomach capacity adjusted to a way more sane level."
    rscdel: "Removed guilty messages about pets starving when you examine them; they won't go hungry in a single shift, don't worry."
    rscadd: "You can brush most friendly animals. Combs work for fuzzy and feathered animals, rags work on other ones."
    tweak: "There's a small chance that when you pet a guard dog (like Columbo) on help intent (and aren't his master), he won't immediately maul your face off; instead, he will growl at you to warn you not to do that. I still don't recommend it."
    tweak: "Like other pets, baby carp can eat now. But not a lot."
This commit is contained in:
Doxxmedearly
2019-12-13 00:25:43 -06:00
committed by Erki
parent d5e323516d
commit 455eab7a34
18 changed files with 121 additions and 76 deletions
@@ -43,7 +43,8 @@
friendly = "pinches"
attacktext = "pinched"
resistance = 9
canbrush = TRUE
brush = /obj/item/reagent_containers/glass/rag
/mob/living/simple_animal/familiar/pike
name = "space pike"
@@ -64,7 +65,8 @@
maxHealth = 100
melee_damage_lower = 15
melee_damage_upper = 15
canbrush = TRUE
brush = /obj/item/reagent_containers/glass/rag
meat_type = /obj/item/reagent_containers/food/snacks/carpmeat
min_oxy = 0
@@ -134,6 +136,7 @@
mob_size = 4.5 //weight based on Chanthangi goats
density = 0
wizardy_spells = list(/spell/aoe_turf/smoke)
canbrush = TRUE
meat_type = /obj/item/reagent_containers/food/snacks/meat
meat_amount = 6
@@ -178,6 +181,7 @@
density = 0
wizardy_spells = list(/spell/targeted/subjugation)
canbrush = TRUE
meat_type = /obj/item/reagent_containers/food/snacks/meat
butchering_products = list(/obj/item/stack/material/animalhide/cat = 2)
@@ -12,6 +12,7 @@
meat_type = /obj/item/reagent_containers/food/snacks/meat/adhomai
meat_amount = 2
hunger_enabled = FALSE
canbrush = TRUE
var/eggsleft = 0
/mob/living/simple_animal/ice_tunneler/attackby(var/obj/item/O as obj, var/mob/user as mob)
@@ -62,11 +63,9 @@
attacktext = "kicked"
health = 200
maxHealth = 200
autoseek_food = 0
beg_for_food = 0
mob_size = 15
canbrush = TRUE
has_udder = TRUE
milk_type = "fatshouter_milk"
@@ -34,10 +34,16 @@
minbodytemp = 0
mob_size = 4
metabolic_factor = 0 // NEVER EAT HA HA HA - geeves
max_nutrition = 40
metabolic_factor = 0.2
bite_factor = 0.6 //Carp got big bites
stomach_size_mult = 3 //They're just baby
density = TRUE
pass_flags = PASSTABLE
canbrush = TRUE
brush = /obj/item/reagent_containers/glass/rag
possession_candidate = TRUE
@@ -33,6 +33,7 @@
var/mob/living/simple_animal/rat/rattarget = null
seek_speed = 5
pass_flags = PASSTABLE
canbrush = TRUE
possession_candidate = 1
emote_sounds = list('sound/effects/creatures/cat_meow.ogg', 'sound/effects/creatures/cat_meow2.ogg')
butchering_products = list(/obj/item/stack/material/animalhide/cat = 2)
@@ -45,7 +46,6 @@
if(snack.stat != DEAD && prob(65))//The probability allows her to not get stuck target the first rat, reducing exploits
rattarget = snack
movement_target = snack
foodtarget = 0 //chasing mice takes precedence over eating food
if(prob(15))
audible_emote(pick("hisses and spits!","mrowls fiercely!","eyes [snack] hungrily."))
@@ -104,9 +104,6 @@
if (prob(75))
break//usually only kill one rat per proc
/mob/living/simple_animal/cat/beg(var/atom/thing, var/atom/holder)
visible_emote("licks [get_pronoun(POSESSIVE_ADJECTIVE)] lips and hungrily glares at [holder]'s [thing.name]",0)
/mob/living/simple_animal/cat/Released()
//A thrown cat will immediately attack mice near where it lands
handle_movement_target()
@@ -20,11 +20,11 @@
response_harm = "kicks"
see_in_dark = 5
mob_size = 3.5
max_nutrition = 80 //Dogs are insatiable eating monsters. This scales with their mob size too
stomach_size_mult = 30
max_nutrition = 70 //Dogs are insatiable eating monsters. This scales with their mob size too
stomach_size_mult = 8
seek_speed = 6
possession_candidate = 1
canbrush = TRUE
holder_type = /obj/item/holder/corgi
butchering_products = list(/obj/item/stack/material/animalhide/corgi = 3)
@@ -35,7 +35,7 @@
/mob/living/simple_animal/corgi/Initialize()
. = ..()
nutrition = max_nutrition * 0.3 //Ian doesn't start with a full belly so will be hungry at roundstart
nutrition = max_nutrition * 0.8 //They can start a little hungry, but let's no go crazy
//IAN! SQUEEEEEEEEE~
/mob/living/simple_animal/corgi/Ian
@@ -61,9 +61,6 @@
set_dir(i)
sleep(1)
/mob/living/simple_animal/corgi/beg(var/atom/thing, var/atom/holder)
visible_emote("stares at the [thing] that [holder] has with sad puppy eyes.",0)
/obj/item/reagent_containers/food/snacks/meat/corgi
name = "Corgi meat"
desc = "Tastes like... well you know..."
@@ -77,7 +74,6 @@
)
scan_interval = max_scan_interval
movement_target = null
foodtarget = 0
stop_automated_movement = 0
turns_since_scan = 0
@@ -25,14 +25,12 @@
melee_damage_lower = 1
melee_damage_upper = 5
udder = null
canbrush = TRUE
emote_sounds = list('sound/effects/creatures/goat.ogg')
has_udder = TRUE
butchering_products = list(/obj/item/stack/material/animalhide = 3)
/mob/living/simple_animal/hostile/retaliate/goat/beg(var/atom/thing, var/atom/holder)
visible_emote("butts insistently at [holder]'s legs and reaches towards their [thing].",0)
/mob/living/simple_animal/hostile/retaliate/goat/Life()
. = ..()
if(.)
@@ -82,7 +80,7 @@
icon_dead = "cow_dead"
icon_gib = "cow_gib"
speak = list("moo?","moo","MOOOOOO")
speak_emote = list("moos","moos hauntingly")
speak_emote = list("moos")
emote_hear = list("brays")
emote_see = list("shakes its head")
speak_chance = 1
@@ -95,10 +93,9 @@
response_harm = "kicks"
attacktext = "kicked"
health = 250
autoseek_food = 0
beg_for_food = 0
mob_size = 20//based on mass of holstein fresian dairy cattle, what the sprite is based on
emote_sounds = list('sound/effects/creatures/cow.ogg')
canbrush = TRUE
has_udder = TRUE
butchering_products = list(/obj/item/stack/material/animalhide = 8)
@@ -142,10 +139,9 @@
var/amount_grown = 0
pass_flags = PASSTABLE | PASSGRILLE
holder_type = /obj/item/holder/chick
autoseek_food = 0
beg_for_food = 0
density = 0
mob_size = 0.75//just a rough estimate, the real value should be way lower
canbrush = TRUE
hunger_enabled = FALSE
emote_sounds = list('sound/effects/creatures/chick.ogg')
@@ -195,6 +191,7 @@
density = 0
mob_size = 2
hunger_enabled = FALSE
canbrush = TRUE
var/static/chicken_count = 0
emote_sounds = list('sound/effects/creatures/chicken.ogg', 'sound/effects/creatures/chicken_bwak.ogg')
@@ -20,7 +20,7 @@
response_disarm = "gently pushes aside"
response_harm = "kicks"
mob_size = 4
max_nutrition = 90
max_nutrition = 80
holder_type = /obj/item/holder/fox
emote_sounds = list()
butchering_products = list(/obj/item/stack/material/animalhide = 3)
@@ -18,9 +18,9 @@
attacktext = "kicked"
health = 250
maxHealth = 250
canbrush = TRUE
brush = /obj/item/reagent_containers/glass/rag
autoseek_food = FALSE
beg_for_food = FALSE
mob_size = 15
has_udder = TRUE
@@ -18,6 +18,8 @@
holder_type = /obj/item/holder/lizard
density = 0
seek_speed = 0.75
canbrush = TRUE
brush = /obj/item/reagent_containers/glass/rag
butchering_products = list(/obj/item/stack/material/animalhide/lizard = 2)
@@ -22,6 +22,8 @@
density = 0
holder_type = /obj/item/holder/mushroom
mob_size = 2
canbrush = TRUE
brush = /obj/item/reagent_containers/glass/rag
/mob/living/simple_animal/mushroom/Initialize()
. = ..()
@@ -49,7 +49,7 @@
max_scan_interval = 20
seek_speed = 1
max_nutrition = 17
canbrush = TRUE
can_pull_size = 1
can_pull_mobs = MOB_PULL_NONE
@@ -135,9 +135,6 @@
/mob/living/simple_animal/rat/speak_audio()
squeak_soft(0)
/mob/living/simple_animal/rat/beg(var/atom/thing, var/atom/holder)
squeak_soft(0)
visible_emote("squeaks timidly, sniffs the air and gazes longingly up at \the [thing.name].",0)
/mob/living/simple_animal/rat/attack_hand(mob/living/carbon/human/M as mob)
if (src.stat == DEAD)//If the mouse is dead, we don't pet it, we just pickup the corpse on click
@@ -173,6 +173,8 @@
pass_flags = PASSTABLE
density = 0
mob_size = 2
canbrush = TRUE
brush = /obj/item/reagent_containers/glass/rag
/mob/living/simple_animal/tindalos
name = "tindalos"
@@ -184,3 +186,5 @@
pass_flags = PASSTABLE
density = 0
mob_size = 1.5
canbrush = TRUE
brush = /obj/item/reagent_containers/glass/rag
@@ -209,7 +209,13 @@
target_mob = null
if(M.a_intent == I_HURT)
audible_emote("[pick(sad_emote)].",0)
return
return
if(M.a_intent == I_HELP && prob(40)) //chance that they won't immediately kill anyone who pets them. But only a chance.
stance = HOSTILE_STANCE_IDLE
target_mob = null
audible_emote("growls at [M].")
to_chat(M, span("warning", "Maybe you should keep your hands to yourself..."))
return
if(M.a_intent == I_HURT && retribution) //assume he wants to hurt us.
@@ -244,7 +250,8 @@
if(user == master)
target_mob = null
stance = HOSTILE_STANCE_IDLE
audible_emote("[pick(sad_emote)].",0)
if(!istype(O, brush)) //we don't get sad if we're brushed!
audible_emote("[pick(sad_emote)].",0)
/mob/living/simple_animal/hostile/commanded/hitby(atom/movable/AM as mob|obj,var/speed = THROWFORCE_SPEED_DIVISOR)//Standardization and logging -Sieve
..()
@@ -37,9 +37,8 @@
response_disarm = "pushes"
hunger_enabled = 1 //so you can feed your dog or something
autoseek_food = 0
beg_for_food = 0
max_nutrition = 120
canbrush = TRUE
known_commands = list("stay", "stop", "attack", "follow")
@@ -49,6 +49,7 @@
response_harm = "swats"
stop_automated_movement = 1
universal_speak = 1
canbrush = TRUE
flying = TRUE
@@ -80,24 +80,22 @@
var/digest_factor = 0.2 //A multiplier on how quickly reagents are digested
var/stomach_size_mult = 5
//Food behaviour vars
var/autoseek_food = 1//If 0. this animal will not automatically eat
var/beg_for_food = 1//If 0, this animal will not show interest in food held by a person
var/min_scan_interval = 1//Minimum and maximum number of procs between a foodscan. Animals will slow down if there's no food around for a while
//Seeking/Moving behaviour vars
var/min_scan_interval = 1//Minimum and maximum number of procs between a scan
var/max_scan_interval = 15
var/scan_interval = 5//current scan interval, clamped between min and max
//It gradually increases up to max when its left alone, to save performance
//It will drop back to 1 if it spies any food.
//This short time makes animals more responsive to interactions and more fun to play with
var/seek_speed = 2//How many tiles per second the animal will move towards food
var/seek_speed = 2//How many tiles per second the animal will move towards something
var/seek_move_delay
var/scan_range = 6//How far around the animal will look for food
var/foodtarget = 0
//Used to control how often ian scans for nearby food
var/scan_range = 6//How far around the animal will look for something
var/kitchen_tag = "animal" //Used for cooking with animals
//brushing
var/canbrush = FALSE //can we brush this beautiful creature?
var/brush = /obj/item/haircomb //What can we brush it with? Use a rag for things with scales/carapaces/etc
//Napping
var/can_nap = 0
var/icon_rest = null
@@ -112,20 +110,6 @@
var/list/butchering_products //if anything else is created when butchering this creature, like bones and leather
/mob/living/simple_animal/proc/beg(var/atom/thing, var/atom/holder)
visible_emote("gazes longingly at [holder]'s [thing]",0)
/mob/living/simple_animal/proc/steal_food(var/obj/item/reagent_containers/food/snacks/F, var/mob/living/carbon/human/H)
if(!F || !H)
return
H.visible_message(
span("warning", "\the [src] grabs \the [F] with its teeth and steals it from \the [H] hands. Taking a bite and dropping it on the floor."),
span("warning", "\the [src] grabs \the [F] with its teeth and steals it from your hands. Taking a bite and dropping it on the floor.")
)
H.drop_from_inventory(F)
UnarmedAttack(F)
if (get_turf(F) == loc)
set_dir(pick(NORTH, SOUTH, EAST, WEST, NORTH, NORTH))//Face a random direction when eating, but mostly upwards
/mob/living/simple_animal/proc/update_nutrition_stats()
nutrition_step = mob_size * 0.03 * metabolic_factor
@@ -173,13 +157,6 @@
/mob/living/simple_animal/examine(mob/user)
..()
if (hunger_enabled)
if (!nutrition)
to_chat(user, "<span class='danger'>It looks starving!</span>")
else if (nutrition < max_nutrition *0.5)
to_chat(user, "<span class='notice'>It looks hungry.</span>")
else if ((reagents.total_volume > 0 && nutrition > max_nutrition *0.75) || nutrition > max_nutrition *0.9)
to_chat(user, "It looks full and contented.")
if (stat == DEAD)
to_chat(user, "<span class='danger'>It looks dead.</span>")
if (health < maxHealth * 0.5)
@@ -204,7 +181,6 @@
handle_paralysed()
update_canmove()
handle_supernatural()
autoseek_food = nutrition / max_nutrition <= 0.05 ? TRUE : initial(autoseek_food)
process_food()
//Movement
@@ -261,7 +237,6 @@
/mob/living/simple_animal/think()
..()
handle_foodscanning()
if(!stop_automated_movement && wander && !anchored)
if(isturf(loc) && !resting && !buckled && canmove) //This is so it only moves if it's not inside a closet, gentics machine, etc.
if(turns_since_move >= turns_per_move && !(stop_automated_movement_when_pulled && pulledby)) //Some animals don't move when pulled
@@ -313,6 +288,13 @@
if (!stat || prob(0.5))
wake_up()
//Eating in tile
for(var/obj/item/reagent_containers/food/snacks/S in src.loc)
if(can_eat() && (nutrition < max_nutrition * 0.3)) //Only when sufficiently hungry
UnarmedAttack(S)
else
break
/mob/living/simple_animal/proc/handle_supernatural()
if(purge)
purge -= 1
@@ -428,7 +410,10 @@ mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj)
return
/mob/living/simple_animal/attackby(var/obj/item/O, var/mob/user)
/mob/living/simple_animal/attackby(obj/item/O, mob/user)
if(istype(O, /obj/item/reagent_containers/glass/rag)) //You can't milk an udder with a rag.
attacked_with_item(O, user)
return
if(has_udder)
var/obj/item/reagent_containers/glass/G = O
if(stat == CONSCIOUS && istype(G) && G.is_open_container())
@@ -453,11 +438,16 @@ mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj)
attacked_with_item(O, user)
//TODO: refactor mob attackby(), attacked_by(), and friends.
/mob/living/simple_animal/proc/attacked_with_item(var/obj/item/O, var/mob/user)
/mob/living/simple_animal/proc/attacked_with_item(obj/item/O, mob/user)
if(istype(O, /obj/item/trap/animal))
O.attack(src, user)
return
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(istype(O, brush) && canbrush) //Brushing animals
visible_message(span("notice", "[user] gently brushes [src] with \the [O]."))
if(prob(15) && !istype(src, /mob/living/simple_animal/hostile)) //Aggressive animals don't purr before biting your face off.
visible_message(span("notice", "[src] [speak_emote.len ? pick(speak_emote) : "rumbles"] happily.")) //purring
return
if(!O.force)
visible_message("<span class='notice'>[user] gently taps [src] with \the [O].</span>")
poke()
@@ -613,7 +603,7 @@ mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj)
user.visible_message("<span class='danger'>[user] butchers \the [src] messily!</span>")
gib()
/*
//Code to handle finding and nomming nearby food items
/mob/living/simple_animal/proc/handle_foodscanning()
if (client || !hunger_enabled || !autoseek_food)
@@ -679,7 +669,7 @@ mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj)
beg(movement_target, movement_target.loc)
else
scan_interval = max(min_scan_interval, min(scan_interval+1, max_scan_interval))//If nothing is happening, ian's scanning frequency slows down to save processing
*/
//For picking up small animals
/mob/living/simple_animal/MouseDrop(atom/over_object)
@@ -710,7 +700,6 @@ mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj)
wander = 0
walk_to(src,0)
movement_target = null
foodtarget = 0
update_icons()
//Wakes the mob up from sleeping
@@ -80,7 +80,6 @@
var/m_bitesize = bitesize * SA.bite_factor//Modified bitesize based on creature size
var/amount_eaten = m_bitesize
SA.scan_interval = SA.min_scan_interval//Feeding an animal will make it suddenly care about food
m_bitesize = min(m_bitesize, reagents.total_volume)
if (!SA.can_eat() || ((user.reagents.maximum_volume - user.reagents.total_volume) < m_bitesize * 0.5))