diff --git a/code/game/objects/structures/flora/flora.dm b/code/game/objects/structures/flora/flora.dm index aafdc194a7..78e85b802b 100644 --- a/code/game/objects/structures/flora/flora.dm +++ b/code/game/objects/structures/flora/flora.dm @@ -91,21 +91,29 @@ var/mob/living/simple_mob/animal/critter = user if(!critter.forager) return ..() + + if(!critter.has_appetite()) + to_chat(critter, SPAN_WARNING("You don't have much of an appetite at the moment.")) + return TRUE + if(!can_forage(critter)) to_chat(critter, SPAN_WARNING("You cannot see any edible fruit on \the [src].")) return TRUE + critter.set_AI_busy(TRUE) show_animal_foraging_message(critter) critter.setClickCooldown(5 SECONDS) + if(!do_after(critter, 5 SECONDS, src) || QDELETED(src) || !can_forage(user)) critter.set_AI_busy(FALSE) return TRUE + critter.set_AI_busy(FALSE) show_animal_eating_message(critter) - playsound(critter, 'sound/items/eatfood.ogg', rand(10,50), 1) harvest_count++ critter.eat_food_item(spawn_harvest(pickweight(harvest_loot))) return TRUE + return ..() /obj/structure/flora/proc/can_forage(var/mob/critter) diff --git a/code/modules/food/food/snacks.dm b/code/modules/food/food/snacks.dm index ed338ec586..42c2e15f93 100644 --- a/code/modules/food/food/snacks.dm +++ b/code/modules/food/food/snacks.dm @@ -232,6 +232,9 @@ return if(isanimal(user)) var/mob/living/simple_mob/animal/critter = user + if(!critter.has_appetite()) + to_chat(critter, SPAN_WARNING("You don't have much of an appetite at the moment.")) + return TRUE critter.eat_food_item(src, bitesize) else user.visible_message("[user] nibbles away at \the [src].","You nibble away at \the [src].") diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/animal.dm b/code/modules/mob/living/simple_mob/subtypes/animal/animal.dm index e0d4b6addc..01d75be657 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/animal.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/animal.dm @@ -31,6 +31,9 @@ /decl/mob_organ_names/quadruped //Most subtypes have this basic body layout. hit_zones = list("head", "torso", "left foreleg", "right foreleg", "left hind leg", "right hind leg", "tail") +/mob/living/simple_mob/animal/proc/has_appetite() + return TRUE + /mob/living/simple_mob/animal/do_interaction(var/atom/A) // Can we do some critter interaction? @@ -50,6 +53,11 @@ if(scavenger && isliving(A) && a_intent == I_HURT) var/mob/living/M = A if(M.stat == DEAD && length(M.internal_organs)) + + if(!has_appetite()) + to_chat(src, SPAN_WARNING("You don't have much of an appetite at the moment.")) + return TRUE + to_chat(src, SPAN_NOTICE("You dig into the guts of \the [M], hunting for the sweetest meat.")) set_AI_busy(TRUE) if(do_after(src, 2 SECONDS, M) && !QDELETED(M) && length(M.internal_organs)) @@ -65,18 +73,21 @@ /mob/living/simple_mob/animal/proc/eat_food_item(var/obj/item/snack, var/override_bitesize, var/silent) - if(!silent) - visible_message("\The [src] nibbles away at \the [snack].") - playsound(src, 'sound/items/eatfood.ogg', rand(10,50), 1) - if(istype(snack, /obj/item/organ)) var/obj/item/organ/organ = snack if(organ.meat_type) snack = new organ.meat_type(src) qdel(organ) + else if(!istype(snack) || !snack.reagents?.total_volume) + to_chat(src, SPAN_WARNING("\The [snack] doesn't seem edible.")) + return + + if(!silent) + visible_message("\The [src] nibbles away at \the [snack].") + playsound(src, 'sound/items/eatfood.ogg', rand(10,50), 1) if(snack.reagents?.total_volume) - var/use_bitesize = (override_bitesize || bitesize) + var/use_bitesize = max(override_bitesize, bitesize) var/removing_reagents = clamp(use_bitesize, 0, min(max(0, reagents?.maximum_volume - reagents?.total_volume), snack.reagents.total_volume)) if(reagents && removing_reagents) snack.reagents.trans_to_holder(reagents, removing_reagents) diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka.dm index a253afca46..396ddedfc7 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka.dm @@ -7,9 +7,16 @@ on_expired_text = "The last of the sap in your wounds is absorbed by your body." /datum/modifier/sifsap_salve/tick() + if(holder.stat == DEAD) expire() + if(istype(holder, /mob/living/simple_mob/animal/sif)) + + var/mob/living/simple_mob/animal/sif/critter = holder + if(critter.health >= critter.sap_heal_threshold) + return + if(holder.resting) if(istype(holder.loc, /obj/structure/animal_den)) holder.adjustBruteLoss(-3) @@ -116,6 +123,11 @@ var/global/list/last_drake_howl = list() tt_desc = "S tesca pabulator" faction = "grafadreka" + mob_size = MOB_LARGE + mob_bump_flag = SIMPLE_ANIMAL + mob_swap_flags = SIMPLE_ANIMAL + mob_push_flags = SIMPLE_ANIMAL + maxHealth = 150 health = 150 movement_cooldown = 2 @@ -167,7 +179,6 @@ var/global/list/last_drake_howl = list() var/max_stored_sap = 100 var/attacked_by_human = FALSE - /mob/living/simple_mob/animal/sif/grafadreka/proc/can_tend_wounds(var/mob/living/friend) if(ishuman(friend)) var/mob/living/carbon/human/H = friend @@ -175,6 +186,9 @@ var/global/list/last_drake_howl = list() if(E.status & ORGAN_BLEEDING) return TRUE return FALSE + if(istype(friend, /mob/living/simple_mob/animal/sif)) + var/mob/living/simple_mob/animal/sif/critter = friend + return critter.health < critter.sap_heal_threshold return (friend.health < friend.maxHealth) /mob/living/simple_mob/animal/sif/grafadreka/Initialize() @@ -219,7 +233,7 @@ var/global/list/last_drake_howl = list() // Process food and sap chems. if(stat == CONSCIOUS) // Hibernating drakes don't get hungy. // by default we lose nutrition. Hungry hungry drakes. - var/food_val = resting ? -0.2 : -0.5 + var/food_val = resting ? 0 : -0.3 // Very basic metabolism. if(reagents?.total_volume) @@ -227,7 +241,7 @@ var/global/list/last_drake_howl = list() var/removing = min(REM, chem.volume) if(istype(chem, /datum/reagent/nutriment)) var/datum/reagent/nutriment/food = chem - food_val += (food.nutriment_factor * removing) * ((food.allergen_type & ALLERGEN_MEAT) ? 0.5 : 0.1) + food_val += (food.nutriment_factor * removing) * ((food.allergen_type & ALLERGEN_MEAT) ? 0.3 : 0.1) else if(istype(chem, /datum/reagent/toxin/sifslurry)) add_sap(removing * 3) reagents.remove_reagent(chem.id, removing) @@ -341,9 +355,14 @@ var/global/list/last_drake_howl = list() if(!can_tend_wounds(friend)) if(friend == src) - to_chat(src, SPAN_WARNING("You are unwounded.")) + if(health == maxHealth) + to_chat(src, SPAN_WARNING("You are unwounded.")) + else + to_chat(src, SPAN_WARNING("You cannot tend any of your wounds.")) else - return ..() + if(friend.health == friend.maxHealth) + return ..() + to_chat(src, SPAN_WARNING("You cannot tend any of \the [friend]'s wounds.")) return TRUE if(friend.has_modifier_of_type(/datum/modifier/sifsap_salve)) @@ -460,7 +479,7 @@ var/global/list/last_drake_howl = list() to_chat(src, SPAN_WARNING("You aren't the pack leader! Sit down!")) return - for(var/mob/living/simple_mob/animal/sif/grafadreka/drake in hearers(7, src)) + for(var/mob/living/simple_mob/animal/sif/grafadreka/drake in hearers(world.view * 3, src)) if(drake == src || drake.faction != faction) continue if(drake.client) @@ -470,6 +489,9 @@ var/global/list/last_drake_howl = list() audible_message("\The [src] barks loudly and rattles its neck spines.") +/mob/living/simple_mob/animal/sif/grafadreka/has_appetite() + return reagents && abs(reagents.total_volume - reagents.maximum_volume) >= 10 + /datum/say_list/grafadreka speak = list("Chff!","Skhh.", "Rrrss...") emote_see = list("scratches its ears","grooms its spines", "sways its tail", "claws at the ground") diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka_ai.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka_ai.dm index 9fdcc7b1a0..fd7c18ff2f 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka_ai.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka_ai.dm @@ -24,14 +24,15 @@ drake_brain.hostile = TRUE /datum/ai_holder/simple_mob/intentional/grafadreka - hostile = TRUE - retaliate = TRUE - cooperative = TRUE - can_flee = TRUE - flee_when_dying = TRUE - var/next_food_check - var/next_sap_check - var/next_heal_check + hostile = TRUE + retaliate = TRUE + cooperative = TRUE + can_flee = TRUE + flee_when_dying = TRUE + home_low_priority = TRUE + var/next_food_check = 0 + var/next_sap_check = 0 + var/next_heal_check = 0 /datum/ai_holder/simple_mob/intentional/grafadreka/should_flee(force) . = ..() @@ -105,7 +106,7 @@ return // These actions need space in our stomach to be worth considering at all. - if(drake.reagents && abs(drake.reagents.total_volume - drake.reagents.maximum_volume) >= 10) + if(drake.has_appetite() && !(locate(/datum/reagent/nutriment) in drake.reagents.reagent_list)) // Find some sap if we're low and aren't already digesting some. if(!drake.has_sap(20) && !drake.reagents.has_reagent("sifsap")) diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/sif.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/sif.dm index e3573025ae..8856abca11 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/sif.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/sif.dm @@ -5,6 +5,23 @@ heat_resist = -0.5 tame_items = list( - /obj/item/reagent_containers/food/snacks/meat/crab = 20, - /obj/item/reagent_containers/food/snacks/meat = 10 + /obj/item/reagent_containers/food/snacks/meat/crab = 20, + /obj/item/reagent_containers/food/snacks/meat = 10 ) + + // Healing threshold for grafadreka healing spit effect. + var/sap_heal_threshold + var/sap_heal_gradient = 0.25 // 25% of health each regen threshold + +/mob/living/simple_mob/animal/sif/Initialize() + . = ..() + sap_heal_threshold = round(maxHealth * 0.15) + +/mob/living/simple_mob/animal/sif/updatehealth() + . = ..() + var/sap_threshold = round(maxHealth * sap_heal_gradient) + sap_heal_threshold = min(maxHealth, min(sap_heal_threshold, n_ceil(health % sap_threshold)*sap_threshold)) + +/mob/living/simple_mob/animal/sif/rejuvenate() + sap_heal_threshold = maxHealth + . = ..() diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index eb7f169c47..ae12db9e21 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -562,6 +562,9 @@ var/global/list/organ_cache = list() /obj/item/organ/attack_generic(mob/user) if(isanimal(user)) var/mob/living/simple_mob/animal/critter = user - critter.eat_food_item(src) + if(!critter.has_appetite()) + to_chat(critter, SPAN_WARNING("You don't have much of an appetite at the moment.")) + else + critter.eat_food_item(src) return TRUE return ..()