From ecf8425a1937977f41d884b81bb7bc7cd49e9c09 Mon Sep 17 00:00:00 2001 From: NanakoAC Date: Tue, 2 Aug 2016 19:43:03 +0100 Subject: [PATCH] Animal Feeding and Hunger (#634) changes: rscadd: "Added hunger and feeding system for simple animals, this includes cats, dogs, mice, lizards, chickens, cows, etc" rscadd: "Animals can now actually consume food instead of nibbling them eternally." rscadd: "Animals can now be hand-fed by using food on them." rscadd: "Animals will move more slowly when starving. Examining an animal will show if its hungry." Basically added a very simple metabolising system for animals, and fixed up various eating/feeding functions. They only metabolise food, any other reagents are just removed and ignored for now, since most chemicals were designed for carbon mobs and often aren't valid --- .../living/simple_animal/friendly/mouse.dm | 3 + .../mob/living/simple_animal/simple_animal.dm | 73 ++++++++++++++++++- code/modules/reagents/Chemistry-Holder.dm | 10 ++- .../reagent_containers/food/snacks.dm | 56 +++++++++++++- html/changelogs/Nanako-AnimalFeeding.yml | 40 ++++++++++ 5 files changed, 174 insertions(+), 8 deletions(-) create mode 100644 html/changelogs/Nanako-AnimalFeeding.yml diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm index 97dfe678bc1..c8cf8373e36 100644 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -30,6 +30,7 @@ universal_understand = 1 mob_size = 1 holder_type = /obj/item/weapon/holder/mouse + digest_factor = 0.05 /mob/living/simple_animal/mouse/Life() ..() @@ -75,6 +76,8 @@ holder_type = /obj/item/weapon/holder/mouse/white + + /mob/living/simple_animal/mouse/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 get_scooped(M) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 59e2e256910..f2b76e665cf 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -66,9 +66,29 @@ var/supernatural = 0 var/purge = 0 + var/max_nutrition = 75 + var/nutrition_step = 0.2 //nutrition lost per tick and per step, calculated from mob_size, 0.4 is a fallback + var/bite_factor = 0.4 + var/digest_factor = 0.2 //A multiplier on how quickly reagents are digested + /mob/living/simple_animal/New() ..() verbs -= /mob/verb/observe + if (mob_size) + nutrition_step = mob_size * 0.05 + bite_factor = mob_size * 0.3 + max_nutrition *= 1 + (nutrition_step*3)//Max nutrition scales faster than costs, so bigger creatures eat less often + reagents = new/datum/reagents(5*mob_size, src) + else + reagents = new/datum/reagents(20, src) + nutrition = max_nutrition + +/mob/living/simple_animal/Move(NewLoc, direct) + . = ..() + if(.) + if(src.nutrition && src.stat != DEAD) + src.nutrition -= nutrition_step + /mob/living/simple_animal/Login() if(src && src.client) @@ -78,6 +98,15 @@ /mob/living/simple_animal/updatehealth() return +/mob/living/simple_animal/examine(mob/user) + ..() + if (!nutrition) + user << "It looks starving!" + else if (nutrition < max_nutrition *0.5) + user << "It looks hungry." + else if ((reagents.total_volume > 0 && nutrition > max_nutrition *0.75) || nutrition > max_nutrition *0.9) + user << "It looks full and contented." + /mob/living/simple_animal/Life() ..() @@ -104,7 +133,7 @@ handle_paralysed() update_canmove() handle_supernatural() - + process_food() //Movement if(!client && !stop_automated_movement && wander && !anchored) if(isturf(src.loc) && !resting && !buckled && canmove) //This is so it only moves if it's not inside a closet, gentics machine, etc. @@ -210,6 +239,40 @@ if(purge) purge -= 1 + + +//Simple reagent processing for simple animals +//This allows animals to digest food, and only food +//Most drugs, poisons etc, are designed to work on carbons and affect many values a simple animal doesnt have +/mob/living/simple_animal/proc/process_food() + + if (nutrition) + nutrition -= nutrition_step//Bigger animals get hungry faster + nutrition = max(0,min(nutrition, max_nutrition))//clamp the value + else + if (prob(3)) + src << "You feel hungry..." + + + if (!reagents || !reagents.total_volume) + return + + for(var/datum/reagent/current in reagents.reagent_list) + var/removed = min(current.metabolism*digest_factor, current.volume) + if (istype(current, /datum/reagent/nutriment))//If its food, it feeds us + var/datum/reagent/nutriment/N = current + nutrition += removed*N.nutriment_factor + current.remove_self(removed)//If its not food, it just does nothing. no fancy effects + +/mob/living/simple_animal/proc/can_eat() + if (nutrition > max_nutrition * 0.9) + return 0//full + + else if (nutrition > max_nutrition * 0.8) + return 1//content + + else return 2//hungry + /mob/living/simple_animal/gib() ..(icon_gib,1) @@ -284,7 +347,10 @@ M.show_message("[user] applies the [MED] on [src].") else user << "\The [src] is dead, medical items won't bring \him back to life." - if(meat_type && (stat == DEAD)) //if the animal has a meat, and if it is dead. + else if(istype(O, /obj/item/weapon/reagent_containers)) + ..() + + else if(meat_type && (stat == DEAD)) //if the animal has a meat, and if it is dead. if(istype(O, /obj/item/weapon/material/knife) || istype(O, /obj/item/weapon/material/knife/butch)) harvest(user) else @@ -320,6 +386,9 @@ tally = 1 tally *= purge + if (!nutrition) + tally += 4 + return tally+config.animal_delay /mob/living/simple_animal/Stat() diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm index 85d7191048b..f8aa92964f4 100644 --- a/code/modules/reagents/Chemistry-Holder.dm +++ b/code/modules/reagents/Chemistry-Holder.dm @@ -391,9 +391,13 @@ var/datum/reagents/R = C.touching return trans_to_holder(R, amount, multiplier, copy) else - var/datum/reagents/R = new /datum/reagents(amount) - . = trans_to_holder(R, amount, multiplier, copy) - R.touch_mob(target) + //If the target has a reagent holder, we'll try to put it there instead. This allows feeding simple animals + if(target.reagents && type == CHEM_BLOOD || type == CHEM_INGEST) + return trans_to_holder(target.reagents, amount, multiplier, copy) + else + var/datum/reagents/R = new /datum/reagents(amount) + . = trans_to_holder(R, amount, multiplier, copy) + R.touch_mob(target) /datum/reagents/proc/trans_to_turf(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Turfs don't have any reagents (at least, for now). Just touch it. if(!target || !target.simulated) diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index 950b17a13ee..c4c7bd93d53 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -108,6 +108,32 @@ On_Consume(M) return 1 + else if (isanimal(M)) + var/mob/living/simple_animal/SA = M + var/m_bitesize = bitesize * SA.bite_factor//Modified bitesize based on creature size + var/amount_eaten = m_bitesize + + if(reagents && SA.reagents) + m_bitesize = min(m_bitesize, reagents.total_volume) + //If the creature can't even stomach half a bite, then it eats nothing + if (!SA.can_eat() || ((user.reagents.maximum_volume - user.reagents.total_volume) < m_bitesize * 0.5)) + amount_eaten = 0 + else + amount_eaten = reagents.trans_to_mob(SA, m_bitesize, CHEM_INGEST) + else + return 0//The target creature can't eat + + if (amount_eaten) + bitecount++ + if (amount_eaten >= m_bitesize) + user.visible_message("[user] feeds [M] [src].") + else + user.visible_message("[user] feeds [M] a tiny bit of [src]. It looks full.") + On_Consume(M) + return 1 + else + user << "[M.name] can't stomach anymore food!" + return 0 /obj/item/weapon/reagent_containers/food/snacks/examine(mob/user) @@ -206,10 +232,34 @@ /obj/item/weapon/reagent_containers/food/snacks/attack_generic(var/mob/living/user) if(!isanimal(user) && !isalien(user)) return - user.visible_message("[user] nibbles away at \the [src].","You nibble away at \the [src].") - bitecount++ + + var/amount_eaten = bitesize + var/m_bitesize = bitesize + + if (isanimal(user)) + var/mob/living/simple_animal/SA = user + m_bitesize = bitesize * SA.bite_factor//Modified bitesize based on creature size + amount_eaten = m_bitesize + if (!SA.can_eat()) + user << "You're too full to eat anymore!" + return + if(reagents && user.reagents) - reagents.trans_to_mob(user, bitesize, CHEM_INGEST) + m_bitesize = min(m_bitesize, reagents.total_volume) + //If the creature can't even stomach half a bite, then it eats nothing + if (((user.reagents.maximum_volume - user.reagents.total_volume) < m_bitesize * 0.5)) + amount_eaten = 0 + else + amount_eaten = reagents.trans_to_mob(user, m_bitesize, CHEM_INGEST) + if (amount_eaten) + bitecount++ + if (amount_eaten < m_bitesize) + user.visible_message("[user] reluctantly nibbles a tiny part of \the [src].","You reluctantly nibble a tiny part of \the [src]. You can't stomach much more!.") + else + user.visible_message("[user] nibbles away at \the [src].","You nibble away at \the [src].") + else + user << "You're too full to eat anymore!" + spawn(5) if(!src && !user.client) user.custom_emote(1,"[pick("burps", "cries for more", "burps twice", "looks at the area where the food was")]") diff --git a/html/changelogs/Nanako-AnimalFeeding.yml b/html/changelogs/Nanako-AnimalFeeding.yml new file mode 100644 index 00000000000..4c444d2b653 --- /dev/null +++ b/html/changelogs/Nanako-AnimalFeeding.yml @@ -0,0 +1,40 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: Nanako + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Added hunger and feeding system for simple animals, this includes cats, dogs, mice, lizards, chickens, cows, etc" + - rscadd: "Animals can now actually consume food instead of nibbling them eternally." + - rscadd: "Animals can now be hand-fed by using food on them." + - rscadd: "Animals will move more slowly when starving. Examining an animal will show if its hungry." + \ No newline at end of file