From b52f6cc6c038ef0130ac314e53d73c5c8862a4ce Mon Sep 17 00:00:00 2001 From: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com> Date: Fri, 19 Sep 2025 11:26:43 -0400 Subject: [PATCH] Converts farm animals to basic mobs (#30244) * Converts farm animals to basic mobs * Update paths, removes excess file * CI --------- Signed-off-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com> --- .../SpaceRuins/syndie_space_base.dmm | 2 +- _maps/map_files/shuttles/emergency_jungle.dmm | 4 +- _maps/map_files/stations/boxstation.dmm | 4 +- _maps/map_files/stations/cerestation.dmm | 4 +- _maps/map_files/stations/deltastation.dmm | 6 +- _maps/map_files/stations/emeraldstation.dmm | 4 +- _maps/map_files/stations/metastation.dmm | 4 +- .../spell_targeting/matter_eater_targeting.dm | 4 +- .../structures/crates_lockers/crittercrate.dm | 12 +- .../structures/crates_lockers/largecrate.dm | 4 +- code/modules/events/clogged_disposals.dm | 2 +- .../mob/living/basic/farm_animals/chicken.dm | 257 ++++++++++ .../mob/living/basic/farm_animals/goat.dm | 131 +++++ .../mob/living/basic/farm_animals/goose.dm | 51 ++ .../mob/living/basic/farm_animals/seal.dm | 56 +++ .../mob/living/basic/farm_animals/turkey.dm | 52 ++ .../mob/living/basic/farm_animals/udders.dm | 27 ++ .../living/carbon/human/species/tajaran.dm | 2 +- .../mob/living/carbon/human/species/unathi.dm | 2 +- .../living/carbon/human/species/vulpkanin.dm | 2 +- .../simple_animal/friendly/farm_animals.dm | 448 ------------------ .../projectile/magic_projectiles.dm | 10 +- paradise.dme | 7 +- sound/creatures/bagawk.ogg | Bin 0 -> 7285 bytes sound/creatures/chick_peep.ogg | Bin 0 -> 2845 bytes sound/creatures/clucks.ogg | Bin 0 -> 10497 bytes .../Scripts/30244_basic_farm_animals.txt | 7 + tools/ci/check_simplemob_additions.py | 11 - 28 files changed, 620 insertions(+), 493 deletions(-) create mode 100644 code/modules/mob/living/basic/farm_animals/chicken.dm create mode 100644 code/modules/mob/living/basic/farm_animals/goat.dm create mode 100644 code/modules/mob/living/basic/farm_animals/goose.dm create mode 100644 code/modules/mob/living/basic/farm_animals/seal.dm create mode 100644 code/modules/mob/living/basic/farm_animals/turkey.dm create mode 100644 code/modules/mob/living/basic/farm_animals/udders.dm delete mode 100644 code/modules/mob/living/simple_animal/friendly/farm_animals.dm create mode 100644 sound/creatures/bagawk.ogg create mode 100644 sound/creatures/chick_peep.ogg create mode 100644 sound/creatures/clucks.ogg create mode 100644 tools/UpdatePaths/Scripts/30244_basic_farm_animals.txt diff --git a/_maps/map_files/RandomRuins/SpaceRuins/syndie_space_base.dmm b/_maps/map_files/RandomRuins/SpaceRuins/syndie_space_base.dmm index 5604f99d938..0c2b0495a91 100644 --- a/_maps/map_files/RandomRuins/SpaceRuins/syndie_space_base.dmm +++ b/_maps/map_files/RandomRuins/SpaceRuins/syndie_space_base.dmm @@ -5173,7 +5173,7 @@ name = "Animal Storage"; req_access = list(150) }, -/mob/living/simple_animal/chicken{ +/mob/living/basic/chicken{ faction = list("neutral","syndicate") }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ diff --git a/_maps/map_files/shuttles/emergency_jungle.dmm b/_maps/map_files/shuttles/emergency_jungle.dmm index fb69b98dc65..270b77e6165 100644 --- a/_maps/map_files/shuttles/emergency_jungle.dmm +++ b/_maps/map_files/shuttles/emergency_jungle.dmm @@ -316,7 +316,7 @@ dir = 1 }, /obj/structure/flora/junglebush, -/mob/living/simple_animal/hostile/retaliate/goat, +/mob/living/basic/goat, /turf/simulated/floor/grass, /area/shuttle/escape) "bA" = ( @@ -709,7 +709,7 @@ /obj/machinery/light/small{ dir = 4 }, -/mob/living/simple_animal/hostile/retaliate/goat, +/mob/living/basic/goat, /turf/simulated/floor/grass, /area/shuttle/escape) "qH" = ( diff --git a/_maps/map_files/stations/boxstation.dmm b/_maps/map_files/stations/boxstation.dmm index e3de69b4279..94e18d4fe36 100644 --- a/_maps/map_files/stations/boxstation.dmm +++ b/_maps/map_files/stations/boxstation.dmm @@ -16557,7 +16557,7 @@ }, /area/station/service/hydroponics) "bfE" = ( -/mob/living/simple_animal/hostile/retaliate/goat/chef, +/mob/living/basic/goat/chef, /turf/simulated/floor/plasteel{ icon_state = "showroomfloor" }, @@ -45752,7 +45752,7 @@ /area/station/service/hydroponics) "dnE" = ( /obj/machinery/hydroponics/soil, -/mob/living/simple_animal/chicken/clucky, +/mob/living/basic/chicken/clucky, /turf/simulated/floor/grass, /area/station/service/hydroponics) "dnF" = ( diff --git a/_maps/map_files/stations/cerestation.dmm b/_maps/map_files/stations/cerestation.dmm index 60b26a4ac64..955aa079e59 100644 --- a/_maps/map_files/stations/cerestation.dmm +++ b/_maps/map_files/stations/cerestation.dmm @@ -93581,7 +93581,7 @@ }, /area/station/service/clown/secret) "srW" = ( -/mob/living/simple_animal/hostile/retaliate/goat{ +/mob/living/basic/goat{ name = "Pete" }, /obj/machinery/hologram/holopad, @@ -97517,7 +97517,7 @@ /area/station/public/dorms) "thf" = ( /obj/structure/flora/ausbushes/sunnybush, -/mob/living/simple_animal/chicken/clucky, +/mob/living/basic/chicken/clucky, /turf/simulated/floor/grass, /area/station/service/hydroponics) "thi" = ( diff --git a/_maps/map_files/stations/deltastation.dmm b/_maps/map_files/stations/deltastation.dmm index fae3e814839..de725309142 100644 --- a/_maps/map_files/stations/deltastation.dmm +++ b/_maps/map_files/stations/deltastation.dmm @@ -13749,7 +13749,7 @@ /turf/simulated/floor/plasteel/dark, /area/station/engineering/atmos) "bdz" = ( -/mob/living/simple_animal/chicken/clucky, +/mob/living/basic/chicken/clucky, /turf/simulated/floor/grass, /area/station/service/kitchen) "bdA" = ( @@ -46459,7 +46459,7 @@ /area/station/science/research) "dxA" = ( /obj/structure/flora/ausbushes/fullgrass, -/mob/living/simple_animal/chick{ +/mob/living/basic/chick{ name = "Sins" }, /turf/simulated/floor/grass, @@ -86492,7 +86492,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, -/mob/living/simple_animal/hostile/retaliate/goat/chef, +/mob/living/basic/goat/chef, /obj/item/radio/intercom{ name = "north bump"; pixel_y = 28 diff --git a/_maps/map_files/stations/emeraldstation.dmm b/_maps/map_files/stations/emeraldstation.dmm index f413f808d90..b35279a717d 100644 --- a/_maps/map_files/stations/emeraldstation.dmm +++ b/_maps/map_files/stations/emeraldstation.dmm @@ -72539,7 +72539,7 @@ }, /area/station/security/armory/secure) "osA" = ( -/mob/living/simple_animal/hostile/retaliate/goat/chef, +/mob/living/basic/goat/chef, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, @@ -106745,7 +106745,7 @@ }, /area/station/security/interrogation) "vgz" = ( -/mob/living/simple_animal/chicken/clucky, +/mob/living/basic/chicken/clucky, /turf/simulated/floor/grass, /area/station/service/kitchen) "vgB" = ( diff --git a/_maps/map_files/stations/metastation.dmm b/_maps/map_files/stations/metastation.dmm index a8e6ae51372..b229ee37c1c 100644 --- a/_maps/map_files/stations/metastation.dmm +++ b/_maps/map_files/stations/metastation.dmm @@ -64935,7 +64935,7 @@ }, /area/station/science/rnd) "oHv" = ( -/mob/living/simple_animal/hostile/retaliate/goat/chef, +/mob/living/basic/goat/chef, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, @@ -71259,7 +71259,7 @@ /turf/simulated/floor/plating, /area/station/hallway/primary/fore/east) "qUq" = ( -/mob/living/simple_animal/chicken/clucky, +/mob/living/basic/chicken/clucky, /turf/simulated/floor/grass, /area/station/service/hydroponics) "qUX" = ( diff --git a/code/datums/spell_targeting/matter_eater_targeting.dm b/code/datums/spell_targeting/matter_eater_targeting.dm index a44d3b152b6..bb7efb91d0c 100644 --- a/code/datums/spell_targeting/matter_eater_targeting.dm +++ b/code/datums/spell_targeting/matter_eater_targeting.dm @@ -14,8 +14,8 @@ /mob/living/simple_animal/slime, /mob/living/carbon/alien/larva, /mob/living/simple_animal/slime, - /mob/living/simple_animal/chick, - /mob/living/simple_animal/chicken, + /mob/living/basic/chick, + /mob/living/basic/chicken, /mob/living/basic/lizard, /mob/living/basic/cow, /mob/living/simple_animal/spiderbot diff --git a/code/game/objects/structures/crates_lockers/crittercrate.dm b/code/game/objects/structures/crates_lockers/crittercrate.dm index 04bfe0d1a14..b1a8e7d9e08 100644 --- a/code/game/objects/structures/crates_lockers/crittercrate.dm +++ b/code/game/objects/structures/crates_lockers/crittercrate.dm @@ -51,9 +51,9 @@ /mob/living/simple_animal/pet/dog/corgi, /mob/living/simple_animal/pet/dog/corgi/lisa, - /mob/living/simple_animal/hostile/retaliate/goat, - /mob/living/simple_animal/turkey, - /mob/living/simple_animal/chick, + /mob/living/basic/goat, + /mob/living/basic/turkey, + /mob/living/basic/chick, /mob/living/simple_animal/pet/cat, /mob/living/simple_animal/pet/dog/pug, /mob/living/simple_animal/pet/dog/fox, @@ -77,15 +77,15 @@ /obj/structure/closet/critter/goat name = "goat crate" - content_mob = /mob/living/simple_animal/hostile/retaliate/goat + content_mob = /mob/living/basic/goat /obj/structure/closet/critter/turkey name = "turkey crate" - content_mob = /mob/living/simple_animal/turkey + content_mob = /mob/living/basic/turkey /obj/structure/closet/critter/chick name = "chicken crate" - content_mob = /mob/living/simple_animal/chick + content_mob = /mob/living/basic/chick /obj/structure/closet/critter/chick/populate_contents() amount = rand(1, 3) diff --git a/code/game/objects/structures/crates_lockers/largecrate.dm b/code/game/objects/structures/crates_lockers/largecrate.dm index 7633872defb..e0189655921 100644 --- a/code/game/objects/structures/crates_lockers/largecrate.dm +++ b/code/game/objects/structures/crates_lockers/largecrate.dm @@ -82,7 +82,7 @@ icon_state = "lisacrate" /obj/structure/largecrate/goat/break_open() - new /mob/living/simple_animal/hostile/retaliate/goat(loc) + new /mob/living/basic/goat(loc) /obj/structure/largecrate/chick name = "chicken crate" @@ -91,7 +91,7 @@ /obj/structure/largecrate/chick/break_open() var/num = rand(4, 6) for(var/i in 1 to num) - new /mob/living/simple_animal/chick(loc) + new /mob/living/basic/chick(loc) /obj/structure/largecrate/cat name = "cat crate" diff --git a/code/modules/events/clogged_disposals.dm b/code/modules/events/clogged_disposals.dm index b75fcc10f6b..21812e8c5f8 100644 --- a/code/modules/events/clogged_disposals.dm +++ b/code/modules/events/clogged_disposals.dm @@ -46,7 +46,7 @@ // Retaliate mobs /mob/living/basic/clown = 5, /mob/living/basic/clown/goblin = 5, - /mob/living/simple_animal/hostile/retaliate/goat = 5, + /mob/living/basic/goat = 5, // Friendly /mob/living/simple_animal/mouse = 5, /mob/living/simple_animal/diona = 5, diff --git a/code/modules/mob/living/basic/farm_animals/chicken.dm b/code/modules/mob/living/basic/farm_animals/chicken.dm new file mode 100644 index 00000000000..005bfd5f5f8 --- /dev/null +++ b/code/modules/mob/living/basic/farm_animals/chicken.dm @@ -0,0 +1,257 @@ +/mob/living/basic/chick + name = "chick" + desc = "Adorable! They make such a racket though." + icon_state = "chick" + icon_living = "chick" + icon_dead = "chick_dead" + icon_gib = "chick_gib" + gender = FEMALE + mob_biotypes = MOB_ORGANIC | MOB_BEAST + speak_emote = list("cheeps") + density = FALSE + butcher_results = list(/obj/item/food/meat/chicken = 1) + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" + attack_verb_continuous = "pecks" + attack_verb_simple = "peck" + health = 3 + maxHealth = 3 + ventcrawler = VENTCRAWLER_ALWAYS + pass_flags = PASSTABLE | PASSGRILLE | PASSMOB + mob_size = MOB_SIZE_TINY + holder_type = /obj/item/holder/chicken + can_hide = TRUE + gold_core_spawnable = FRIENDLY_SPAWN + step_type = FOOTSTEP_MOB_CLAW + ai_controller = /datum/ai_controller/basic_controller/chicken/chick + /// How grown up are we? + var/amount_grown = 0 + +/mob/living/basic/chick/Initialize(mapload) + . = ..() + AddElement(/datum/element/wears_collar) + scatter_atom() + /// Basic mobs need a language otherwise their speech is garbled + add_language("Galactic Common") + set_default_language(GLOB.all_languages["Galactic Common"]) + +/mob/living/basic/chick/scatter_atom(x_offset, y_offset) + pixel_x = rand(-6, 6) + x_offset + pixel_y = rand(0, 10) + y_offset + +/mob/living/basic/chick/Life(seconds, times_fired) + . = ..() + if(.) + amount_grown += rand(1,2) + if(amount_grown >= 100) + var/mob/living/basic/chicken/C = new /mob/living/basic/chicken(loc) + if(name != initial(name)) + C.name = name + if(mind) + mind.transfer_to(C) + + for(var/atom/movable/AM in contents) + AM.forceMove(C) + + qdel(src) + +/mob/living/basic/chick/valid_respawn_target_for(mob/user) + return TRUE + +/mob/living/basic/chick/attack_hand(mob/living/carbon/human/M) + if(M.a_intent == INTENT_HELP) + get_scooped(M, TRUE) + ..() + +#define MAX_CHICKENS 50 +GLOBAL_VAR_INIT(chicken_count, 0) + +/mob/living/basic/chicken + name = "chicken" + desc = "Hopefully the eggs are good this season." + gender = FEMALE + mob_biotypes = MOB_ORGANIC | MOB_BEAST + icon_state = "chicken_brown" + icon_living = "chicken_brown" + icon_dead = "chicken_brown_dead" + speak_emote = list("clucks", "croons") + density = FALSE + butcher_results = list(/obj/item/food/meat/chicken = 2) + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" + attack_verb_continuous = "pecks" + attack_verb_simple = "peck" + friendly_verb_continuous = "headbutts" + friendly_verb_simple = "headbutt" + health = 15 + maxHealth = 15 + ventcrawler = VENTCRAWLER_ALWAYS + + pass_flags = PASSTABLE | PASSMOB + mob_size = MOB_SIZE_SMALL + holder_type = /obj/item/holder/chicken + can_hide = TRUE + + gold_core_spawnable = FRIENDLY_SPAWN + step_type = FOOTSTEP_MOB_CLAW + ai_controller = /datum/ai_controller/basic_controller/chicken + + /// What type of egg do we lay? + var/egg_type = /obj/item/food/egg + /// How many eggs do we have left to lay? + var/eggsleft = 0 + /// Are the eggs fertile? + var/eggsFertile = TRUE + /// What can the chicken eat? + var/static/list/edibles = list( + /obj/item/food/grown/wheat, + ) + /// What color chicken are we? + var/body_color + /// Prefix for icon determining colors + var/icon_prefix = "chicken" + /// What colors can chickens be? + var/list/validColors = list("brown", "black", "white") + /// What message to play when laying an egg? + var/list/layMessage = EGG_LAYING_MESSAGES + +/mob/living/basic/chicken/Initialize(mapload) + . = ..() + if(!body_color) + body_color = pick(validColors) + icon_state = "[icon_prefix]_[body_color]" + icon_living = "[icon_prefix]_[body_color]" + icon_dead = "[icon_prefix]_[body_color]_dead" + AddElement(/datum/element/wears_collar) + AddElement(/datum/element/ai_retaliate) + AddElement(/datum/element/pet_bonus, "cluck") + // Have all eating components share the same exact list per mob subtype + var/static/list/static_food_types + if(!static_food_types) + static_food_types = edibles.Copy() + AddElement(/datum/element/basic_eating, food_types_ = static_food_types) + RegisterSignal(src, COMSIG_MOB_PRE_EAT, PROC_REF(on_eat)) + ai_controller.set_blackboard_key(BB_BASIC_FOODS, typecacheof(edibles)) + scatter_atom() + update_appearance(UPDATE_ICON_STATE) + GLOB.chicken_count++ + /// Basic mobs need a language otherwise their speech is garbled + add_language("Galactic Common") + set_default_language(GLOB.all_languages["Galactic Common"]) + +/mob/living/basic/chicken/scatter_atom(x_offset, y_offset) + pixel_x = rand(-6, 6) + x_offset + pixel_y = rand(0, 10) + y_offset + +/mob/living/basic/chicken/death(gibbed) + // Only execute the below if we successfully died + . = ..(gibbed) + if(!.) + return + GLOB.chicken_count-- + +/mob/living/basic/chicken/proc/on_eat(atom/target, mob/feeder) + SIGNAL_HANDLER // COMSIG_MOB_PRE_EAT + if(stat == CONSCIOUS && eggsleft < 8) + eggsleft += rand(1, 4) + else + to_chat(feeder, "[src] doesn't seem hungry!") + return COMSIG_MOB_CANCEL_EAT + +/mob/living/basic/chicken/attack_hand(mob/living/carbon/human/M) + if(M.a_intent == INTENT_HELP) + get_scooped(M, TRUE) + ..() + +/mob/living/basic/chicken/Life(seconds, times_fired) + . = ..() + if((. && prob(3) && eggsleft > 0) && egg_type) + visible_message("[src] [pick(layMessage)]") + eggsleft-- + var/obj/item/E = new egg_type(get_turf(src)) + E.scatter_atom() + if(eggsFertile) + if(GLOB.chicken_count < MAX_CHICKENS && prob(25)) + START_PROCESSING(SSobj, E) + +/obj/item/food/egg/process() + if(isturf(loc)) + amount_grown += rand(1,2) + if(amount_grown >= 100) + visible_message("[src] hatches with a quiet cracking sound.") + new /mob/living/basic/chick(get_turf(src)) + STOP_PROCESSING(SSobj, src) + qdel(src) + else + STOP_PROCESSING(SSobj, src) + +/mob/living/basic/chicken/valid_respawn_target_for(mob/user) + return TRUE + +/mob/living/basic/chicken/clucky + name = "Commander Clucky" + real_name = "Commander Clucky" + +/mob/living/basic/chicken/clucky/valid_respawn_target_for(mob/user) // depriving the chef of his animals is not cool + return FALSE + +/mob/living/basic/chicken/kentucky + name = "Kentucky" + real_name = "Kentucky" + +/mob/living/basic/chicken/kentucky/valid_respawn_target_for(mob/user) + return FALSE + +/mob/living/basic/chicken/featherbottom + name = "Featherbottom" + real_name = "Featherbottom" + +/mob/living/basic/chicken/featherbottom/valid_respawn_target_for(mob/user) + return FALSE + +/datum/ai_controller/basic_controller/chicken + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + ) + + ai_traits = AI_FLAG_STOP_MOVING_WHEN_PULLED + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + + planning_subtrees = list( + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, + /datum/ai_planning_subtree/flee_target, + /datum/ai_planning_subtree/find_food, + /datum/ai_planning_subtree/random_speech/chicken, + ) + +/datum/ai_planning_subtree/random_speech/chicken + speech_chance = 15 // really talkative ladies + speak = list("Cluck!", "BWAAAAARK BWAK BWAK BWAK!", "Bwaak bwak.") + sound = list('sound/creatures/clucks.ogg', 'sound/creatures/bagawk.ogg') + emote_hear = list("clucks.", "croons.") + emote_see = list("pecks at the ground.", "flaps her wings viciously.") + +/datum/ai_controller/basic_controller/chicken/chick + planning_subtrees = list( + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, + /datum/ai_planning_subtree/flee_target, + /datum/ai_planning_subtree/random_speech/chick, + ) + +/datum/ai_planning_subtree/random_speech/chick + speech_chance = 15 + speak = list("Cherp.", "Cherp?", "Chirrup.", "Cheep!") + sound = list('sound/creatures/chick_peep.ogg') + emote_hear = list("cheeps.") + emote_see = list("pecks at the ground", "flaps its tiny wings") + +#undef MAX_CHICKENS diff --git a/code/modules/mob/living/basic/farm_animals/goat.dm b/code/modules/mob/living/basic/farm_animals/goat.dm new file mode 100644 index 00000000000..39664321e2a --- /dev/null +++ b/code/modules/mob/living/basic/farm_animals/goat.dm @@ -0,0 +1,131 @@ +// goat +/mob/living/basic/goat + name = "goat" + desc = "Not known for their pleasant disposition." + icon_state = "goat" + icon_living = "goat" + icon_dead = "goat_dead" + see_in_dark = 6 + butcher_results = list(/obj/item/food/meat = 4) + + speak_emote = list("brays") + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" + attack_verb_continuous = "kicks" + attack_verb_simple = "kick" + + faction = list("neutral", "jungle") + mob_biotypes = MOB_ORGANIC | MOB_BEAST + health = 40 + maxHealth = 40 + melee_damage_lower = 1 + melee_damage_upper = 2 + blood_volume = BLOOD_VOLUME_NORMAL + gender = FEMALE + step_type = FOOTSTEP_MOB_SHOE + ai_controller = /datum/ai_controller/basic_controller/goat + /// What can the goat eat? + var/static/list/edibles = list( + /obj/structure/glowshroom, + /obj/structure/spacevine, + ) + /// The goat's udder + var/obj/item/udder/cow/udder + +/mob/living/basic/goat/Initialize(mapload) + . = ..() + udder = new() + AddElement(/datum/element/wears_collar) + AddElement(/datum/element/ai_retaliate) + ai_controller.set_blackboard_key(BB_BASIC_FOODS, typecacheof(edibles)) + + RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(on_pre_attack)) + RegisterSignal(src, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_move)) + +/mob/living/basic/goat/Destroy() + QDEL_NULL(udder) + return ..() + +/mob/living/basic/goat/melee_attack(atom/target, list/modifiers, ignore_cooldown) + . = ..() + if(. && isdiona(target)) + var/mob/living/carbon/human/H = target + var/obj/item/organ/external/NB = pick(H.bodyparts) + H.visible_message("[src] takes a big chomp out of [H]!", "[src] takes a big chomp out of your [NB.name]!") + NB.droplimb() + +/mob/living/basic/goat/proc/on_pre_attack(datum/source, atom/target) + SIGNAL_HANDLER // COMSIG_HOSTILE_PRE_ATTACKINGTARGET + if(is_type_in_list(target, edibles)) + eat_plant(list(target)) + return COMPONENT_HOSTILE_NO_ATTACK + +/mob/living/basic/goat/proc/on_move(datum/source, atom/entering_loc) + SIGNAL_HANDLER // COMSIG_MOVABLE_PRE_MOVE + if(!isturf(entering_loc) || stat == DEAD) + return + + var/list/edible_plants = list() + for(var/obj/target in entering_loc) + if(is_type_in_list(target, edibles)) + edible_plants += target + + INVOKE_ASYNC(src, PROC_REF(eat_plant), edible_plants) + +/mob/living/basic/goat/Life(seconds, times_fired) + . = ..() + if(stat == CONSCIOUS) + udder.generateMilk() + +/mob/living/basic/goat/item_interaction(mob/living/user, obj/item/O, list/modifiers) + if(stat == CONSCIOUS && istype(O, /obj/item/reagent_containers/glass)) + udder.milkAnimal(O, user) + return ITEM_INTERACT_COMPLETE + +/mob/living/basic/goat/proc/eat_plant(list/plants) + var/eaten = FALSE + + for(var/atom/target as anything in plants) + if(istype(target, /obj/structure/spacevine)) + var/obj/structure/spacevine/vine = target + vine.eat(src) + eaten = TRUE + + if(istype(target, /obj/structure/glowshroom)) + qdel(target) + eaten = TRUE + + if(eaten && prob(10)) + say("Nom") // bon appetit + playsound(src, 'sound/items/eatfood.ogg', rand(30, 50), TRUE) + +/mob/living/basic/goat/chef + name = "Pete" + desc = "Pete, the Chef's pet goat from the Caribbean. Not known for their pleasant disposition." + +/// Goats are normally content to sorta hang around and crunch any plant in sight, but they will go ape on someone who attacks them. +/datum/ai_controller/basic_controller/goat + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + ) + ai_traits = AI_FLAG_STOP_MOVING_WHEN_PULLED + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + + planning_subtrees = list( + /datum/ai_planning_subtree/capricious_retaliate, // Capricious like Capra, get it? + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/find_food, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/random_speech/goat, + ) + +/datum/ai_planning_subtree/random_speech/goat + speech_chance = 3 + emote_hear = list("brays.") + emote_see = list("shakes their head.", "stamps a foot.", "glares around.") + speak = list("EHEHEHEHEH", "eh?") diff --git a/code/modules/mob/living/basic/farm_animals/goose.dm b/code/modules/mob/living/basic/farm_animals/goose.dm new file mode 100644 index 00000000000..e51acaa4a31 --- /dev/null +++ b/code/modules/mob/living/basic/farm_animals/goose.dm @@ -0,0 +1,51 @@ +/mob/living/basic/goose + name = "goose" + desc = "A pretty goose. Would make a nice comforter." + icon_state = "goose" + icon_living = "goose" + icon_dead = "goose_dead" + speak_emote = list("quacks") + see_in_dark = 6 + butcher_results = list(/obj/item/food/meat = 6) + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" + attack_verb_continuous = "pecks" + attack_verb_simple = "peck" + health = 50 + maxHealth = 50 + mob_biotypes = MOB_ORGANIC | MOB_BEAST + gold_core_spawnable = FRIENDLY_SPAWN + step_type = FOOTSTEP_MOB_CLAW + ai_controller = /datum/ai_controller/basic_controller/goose + +/mob/living/basic/goose/Initialize(mapload) + . = ..() + AddElement(/datum/element/wears_collar) + AddElement(/datum/element/ai_retaliate) + /// Basic mobs need a language otherwise their speech is garbled + add_language("Galactic Common") + set_default_language(GLOB.all_languages["Galactic Common"]) + +/datum/ai_controller/basic_controller/goose + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + ) + + ai_traits = AI_FLAG_STOP_MOVING_WHEN_PULLED + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + + planning_subtrees = list( + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, + /datum/ai_planning_subtree/flee_target, + /datum/ai_planning_subtree/random_speech/goose, + ) + +/datum/ai_planning_subtree/random_speech/goose + speech_chance = 2 + speak = list("quack?", "quack", "QUACK") + emote_see = list("flaps it's wings.") diff --git a/code/modules/mob/living/basic/farm_animals/seal.dm b/code/modules/mob/living/basic/farm_animals/seal.dm new file mode 100644 index 00000000000..29d6138fd30 --- /dev/null +++ b/code/modules/mob/living/basic/farm_animals/seal.dm @@ -0,0 +1,56 @@ +/mob/living/basic/seal + name = "seal" + desc = "A beautiful white seal." + icon_state = "seal" + icon_living = "seal" + icon_dead = "seal_dead" + speak_emote = list("urks") + see_in_dark = 6 + butcher_results = list(/obj/item/food/meat = 6) + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" + health = 50 + maxHealth = 50 + mob_biotypes = MOB_ORGANIC | MOB_BEAST + gold_core_spawnable = FRIENDLY_SPAWN + blood_volume = BLOOD_VOLUME_NORMAL + ai_controller = /datum/ai_controller/basic_controller/seal + +/mob/living/basic/seal/walrus + name = "walrus" + desc = "A big brown walrus." + icon_state = "walrus" + icon_living = "walrus" + icon_dead = "walrus_dead" + +/mob/living/basic/seal/Initialize(mapload) + . = ..() + AddElement(/datum/element/wears_collar) + AddElement(/datum/element/ai_retaliate) + /// Basic mobs need a language otherwise their speech is garbled + add_language("Galactic Common") + set_default_language(GLOB.all_languages["Galactic Common"]) + +/datum/ai_controller/basic_controller/seal + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + ) + + ai_traits = AI_FLAG_STOP_MOVING_WHEN_PULLED + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + + planning_subtrees = list( + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, + /datum/ai_planning_subtree/flee_target, + /datum/ai_planning_subtree/random_speech/seal, + ) + +/datum/ai_planning_subtree/random_speech/seal + speech_chance = 2 + speak = list("Urk?", "urk.", "URK!") + emote_see = list("flops around.") diff --git a/code/modules/mob/living/basic/farm_animals/turkey.dm b/code/modules/mob/living/basic/farm_animals/turkey.dm new file mode 100644 index 00000000000..9286d3f4429 --- /dev/null +++ b/code/modules/mob/living/basic/farm_animals/turkey.dm @@ -0,0 +1,52 @@ +/mob/living/basic/turkey + name = "turkey" + desc = "Benjamin Franklin would be proud." + icon_state = "turkey" + icon_living = "turkey" + icon_dead = "turkey_dead" + icon_resting = "turkey_rest" + speak_emote = list("gobble") + see_in_dark = 6 + butcher_results = list(/obj/item/food/meat = 4) + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" + attack_verb_continuous = "pecks" + attack_verb_simple = "peck" + health = 50 + maxHealth = 50 + mob_biotypes = MOB_ORGANIC | MOB_BEAST + gold_core_spawnable = FRIENDLY_SPAWN + step_type = FOOTSTEP_MOB_CLAW + ai_controller = /datum/ai_controller/basic_controller/turkey + +/mob/living/basic/turkey/Initialize(mapload) + . = ..() + AddElement(/datum/element/wears_collar) + AddElement(/datum/element/ai_retaliate) + /// Basic mobs need a language otherwise their speech is garbled + add_language("Galactic Common") + set_default_language(GLOB.all_languages["Galactic Common"]) + +/datum/ai_controller/basic_controller/turkey + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + ) + + ai_traits = AI_FLAG_STOP_MOVING_WHEN_PULLED + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + + planning_subtrees = list( + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, + /datum/ai_planning_subtree/flee_target, + /datum/ai_planning_subtree/random_speech/turkey, + ) + +/datum/ai_planning_subtree/random_speech/turkey + speech_chance = 2 + speak = list("gobble?", "gobble", "GOBBLE") + emote_see = list("struts around.") diff --git a/code/modules/mob/living/basic/farm_animals/udders.dm b/code/modules/mob/living/basic/farm_animals/udders.dm new file mode 100644 index 00000000000..83e472b2597 --- /dev/null +++ b/code/modules/mob/living/basic/farm_animals/udders.dm @@ -0,0 +1,27 @@ +/obj/item/udder + name = "udder" + +/obj/item/udder/Initialize(mapload) + . = ..() + create_reagents(50) + +/obj/item/udder/proc/generateMilk() + if(prob(5)) + reagents.add_reagent("milk", rand(5, 10)) + +/obj/item/udder/proc/milkAnimal(obj/O, mob/user) + var/obj/item/reagent_containers/glass/G = O + if(G.reagents.total_volume >= G.volume) + to_chat(user, "[O] is full.") + return + var/transfered = reagents.trans_to(O, rand(5,10)) + if(transfered) + user.visible_message("[user] milks [src] using \the [O].", "You milk [src] using \the [O].") + else + to_chat(user, "The udder is dry. Wait a bit longer...") + +/obj/item/udder/cow + +/obj/item/udder/cow/Initialize(mapload) + . = ..() + reagents.add_reagent("milk", 20) diff --git a/code/modules/mob/living/carbon/human/species/tajaran.dm b/code/modules/mob/living/carbon/human/species/tajaran.dm index 003d4f2131e..7d7f4b980ac 100644 --- a/code/modules/mob/living/carbon/human/species/tajaran.dm +++ b/code/modules/mob/living/carbon/human/species/tajaran.dm @@ -44,7 +44,7 @@ unless they choose otherwise by selecting the colourblind disability in character creation (darksight = 8 but colourblind).*/ ) - allowed_consumed_mobs = list(/mob/living/simple_animal/mouse, /mob/living/simple_animal/chick, /mob/living/basic/butterfly, /mob/living/simple_animal/parrot, /mob/living/simple_animal/hostile/poison/bees) + allowed_consumed_mobs = list(/mob/living/simple_animal/mouse, /mob/living/basic/chick, /mob/living/basic/butterfly, /mob/living/simple_animal/parrot, /mob/living/simple_animal/hostile/poison/bees) suicide_messages = list( "is attempting to bite their tongue off!", diff --git a/code/modules/mob/living/carbon/human/species/unathi.dm b/code/modules/mob/living/carbon/human/species/unathi.dm index 04e20ea2042..f96a9b805bc 100644 --- a/code/modules/mob/living/carbon/human/species/unathi.dm +++ b/code/modules/mob/living/carbon/human/species/unathi.dm @@ -48,7 +48,7 @@ "eyes" = /obj/item/organ/internal/eyes/unathi //3 darksight. ) - allowed_consumed_mobs = list(/mob/living/simple_animal/mouse, /mob/living/basic/lizard, /mob/living/simple_animal/chick, /mob/living/simple_animal/chicken, + allowed_consumed_mobs = list(/mob/living/simple_animal/mouse, /mob/living/basic/lizard, /mob/living/basic/chick, /mob/living/basic/chicken, /mob/living/simple_animal/crab, /mob/living/basic/butterfly, /mob/living/simple_animal/parrot, /mob/living/simple_animal/hostile/poison/bees) suicide_messages = list( diff --git a/code/modules/mob/living/carbon/human/species/vulpkanin.dm b/code/modules/mob/living/carbon/human/species/vulpkanin.dm index 5238db6d9e7..55286796834 100644 --- a/code/modules/mob/living/carbon/human/species/vulpkanin.dm +++ b/code/modules/mob/living/carbon/human/species/vulpkanin.dm @@ -38,7 +38,7 @@ unless they choose otherwise by selecting the colourblind disability in character creation (darksight = 8 but colourblind).*/ ) - allowed_consumed_mobs = list(/mob/living/simple_animal/mouse, /mob/living/basic/lizard, /mob/living/simple_animal/chick, /mob/living/simple_animal/chicken, + allowed_consumed_mobs = list(/mob/living/simple_animal/mouse, /mob/living/basic/lizard, /mob/living/basic/chick, /mob/living/basic/chicken, /mob/living/simple_animal/crab, /mob/living/basic/butterfly, /mob/living/simple_animal/parrot, /mob/living/simple_animal/hostile/poison/bees) suicide_messages = list( diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm deleted file mode 100644 index dfc483deced..00000000000 --- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm +++ /dev/null @@ -1,448 +0,0 @@ -//goat -/mob/living/simple_animal/hostile/retaliate/goat - name = "goat" - desc = "Not known for their pleasant disposition." - icon_state = "goat" - icon_living = "goat" - icon_dead = "goat_dead" - speak = list("EHEHEHEHEH","eh?") - speak_emote = list("brays") - emote_hear = list("brays") - emote_see = list("shakes its head", "stamps a foot", "glares around") - speak_chance = 1 - turns_per_move = 5 - see_in_dark = 6 - butcher_results = list(/obj/item/food/meat = 4) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - faction = list("neutral", "jungle") - mob_biotypes = MOB_ORGANIC | MOB_BEAST - attack_same = TRUE - attacktext = "kicks" - attack_sound = 'sound/weapons/punch1.ogg' - health = 40 - maxHealth = 40 - melee_damage_lower = 1 - melee_damage_upper = 2 - stop_automated_movement_when_pulled = TRUE - blood_volume = BLOOD_VOLUME_NORMAL - var/obj/item/udder/cow/udder = null - gender = FEMALE - footstep_type = FOOTSTEP_MOB_SHOE - -/mob/living/simple_animal/hostile/retaliate/goat/Initialize(mapload) - . = ..() - udder = new() - AddElement(/datum/element/wears_collar) - -/mob/living/simple_animal/hostile/retaliate/goat/Destroy() - QDEL_NULL(udder) - return ..() - -/mob/living/simple_animal/hostile/retaliate/goat/handle_automated_movement() - . = ..() - //chance to go crazy and start wacking stuff - if(!length(enemies) && prob(1)) - Retaliate() - - if(length(enemies) && prob(10)) - enemies = list() - LoseTarget() - visible_message("[src] calms down.") - - eat_plants() - if(!pulledby) - for(var/direction in shuffle(GLOB.alldirs)) - var/step = get_step(src, direction) - if(step) - if(locate(/obj/structure/spacevine) in step || locate(/obj/structure/glowshroom) in step) - Move(step, get_dir(src, step)) - -/mob/living/simple_animal/hostile/retaliate/goat/Life(seconds, times_fired) - . = ..() - if(stat == CONSCIOUS) - udder.generateMilk() - -/mob/living/simple_animal/hostile/retaliate/goat/Retaliate() - ..() - visible_message("[src] gets an evil-looking gleam in their eye.") - -/mob/living/simple_animal/hostile/retaliate/goat/Move() - . = ..() - if(stat == CONSCIOUS) - eat_plants() - -/mob/living/simple_animal/hostile/retaliate/goat/item_interaction(mob/living/user, obj/item/O, list/modifiers) - if(stat == CONSCIOUS && istype(O, /obj/item/reagent_containers/glass)) - udder.milkAnimal(O, user) - return ITEM_INTERACT_COMPLETE - -/mob/living/simple_animal/hostile/retaliate/goat/proc/eat_plants() - var/eaten = FALSE - var/obj/structure/spacevine/SV = locate(/obj/structure/spacevine) in loc - if(SV) - SV.eat(src) - eaten = TRUE - - var/obj/structure/glowshroom/GS = locate(/obj/structure/glowshroom) in loc - if(GS) - qdel(GS) - eaten = TRUE - - if(eaten && prob(10)) - say("Nom") - -/mob/living/simple_animal/hostile/retaliate/goat/AttackingTarget() - . = ..() - if(. && isdiona(target)) - var/mob/living/carbon/human/H = target - var/obj/item/organ/external/NB = pick(H.bodyparts) - H.visible_message("[src] takes a big chomp out of [H]!", "[src] takes a big chomp out of your [NB.name]!") - NB.droplimb() - -/mob/living/simple_animal/hostile/retaliate/goat/chef - name = "Pete" - desc = "Pete, the Chef's pet goat from the Caribbean. Not known for their pleasant disposition." - unique_pet = TRUE - -/mob/living/simple_animal/chick - name = "chick" - desc = "Adorable! They make such a racket though." - icon_state = "chick" - icon_living = "chick" - icon_dead = "chick_dead" - icon_gib = "chick_gib" - gender = FEMALE - mob_biotypes = MOB_ORGANIC | MOB_BEAST - speak = list("Cherp.","Cherp?","Chirrup.","Cheep!") - speak_emote = list("cheeps") - emote_hear = list("cheeps") - emote_see = list("pecks at the ground","flaps its tiny wings") - density = FALSE - speak_chance = 2 - turns_per_move = 2 - butcher_results = list(/obj/item/food/meat/chicken = 1) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - attacktext = "kicks" - health = 3 - maxHealth = 3 - ventcrawler = VENTCRAWLER_ALWAYS - var/amount_grown = 0 - pass_flags = PASSTABLE | PASSGRILLE | PASSMOB - mob_size = MOB_SIZE_TINY - holder_type = /obj/item/holder/chicken - can_hide = TRUE - gold_core_spawnable = FRIENDLY_SPAWN - footstep_type = FOOTSTEP_MOB_CLAW - -/mob/living/simple_animal/chick/Initialize(mapload) - . = ..() - AddElement(/datum/element/wears_collar) - scatter_atom() - -/mob/living/simple_animal/chick/scatter_atom(x_offset, y_offset) - pixel_x = rand(-6, 6) + x_offset - pixel_y = rand(0, 10) + y_offset - -/mob/living/simple_animal/chick/Life(seconds, times_fired) - . =..() - if(.) - amount_grown += rand(1,2) - if(amount_grown >= 100) - var/mob/living/simple_animal/chicken/C = new /mob/living/simple_animal/chicken(loc) - if(name != initial(name)) - C.name = name - if(mind) - mind.transfer_to(C) - - for(var/atom/movable/AM in contents) - AM.forceMove(C) - - qdel(src) - - -/mob/living/simple_animal/chick/npc_safe(mob/user) - return TRUE - -/mob/living/simple_animal/chick/attack_hand(mob/living/carbon/human/M) - if(M.a_intent == INTENT_HELP) - get_scooped(M, TRUE) - ..() - -#define MAX_CHICKENS 50 -GLOBAL_VAR_INIT(chicken_count, 0) - -/mob/living/simple_animal/chicken - name = "chicken" - desc = "Hopefully the eggs are good this season." - gender = FEMALE - mob_biotypes = MOB_ORGANIC | MOB_BEAST - icon_state = "chicken_brown" - icon_living = "chicken_brown" - icon_dead = "chicken_brown_dead" - speak = list("Cluck!","BWAAAAARK BWAK BWAK BWAK!","Bwaak bwak.") - speak_emote = list("clucks","croons") - emote_hear = list("clucks") - emote_see = list("pecks at the ground","flaps its wings viciously") - density = FALSE - speak_chance = 2 - turns_per_move = 3 - butcher_results = list(/obj/item/food/meat/chicken = 2) - var/egg_type = /obj/item/food/egg - var/food_type = /obj/item/food/grown/wheat - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - attacktext = "kicks" - health = 15 - maxHealth = 15 - ventcrawler = VENTCRAWLER_ALWAYS - var/eggsleft = 0 - var/eggsFertile = TRUE - var/body_color - var/icon_prefix = "chicken" - pass_flags = PASSTABLE | PASSMOB - mob_size = MOB_SIZE_SMALL - holder_type = /obj/item/holder/chicken - can_hide = TRUE - var/list/feedMessages = list("It clucks happily.","It clucks happily.") - var/list/layMessage = EGG_LAYING_MESSAGES - var/list/validColors = list("brown","black","white") - gold_core_spawnable = FRIENDLY_SPAWN - footstep_type = FOOTSTEP_MOB_CLAW - -/mob/living/simple_animal/chicken/Initialize(mapload) - . = ..() - if(!body_color) - body_color = pick(validColors) - icon_state = "[icon_prefix]_[body_color]" - icon_living = "[icon_prefix]_[body_color]" - icon_dead = "[icon_prefix]_[body_color]_dead" - AddElement(/datum/element/wears_collar) - scatter_atom() - update_appearance(UPDATE_ICON_STATE) - GLOB.chicken_count += 1 - -/mob/living/simple_animal/chicken/scatter_atom(x_offset, y_offset) - pixel_x = rand(-6, 6) + x_offset - pixel_y = rand(0, 10) + y_offset - -/mob/living/simple_animal/chicken/death(gibbed) - // Only execute the below if we successfully died - . = ..(gibbed) - if(!.) - return - GLOB.chicken_count -= 1 - -/mob/living/simple_animal/chicken/item_interaction(mob/living/user, obj/item/O, list/modifiers) - if(istype(O, food_type)) //feedin' dem chickens - if(stat == CONSCIOUS && eggsleft < 8) - var/feedmsg = "[user] feeds [O] to [name]! [pick(feedMessages)]" - user.visible_message(feedmsg) - user.drop_item() - qdel(O) - eggsleft += rand(1, 4) - //world << eggsleft - else - to_chat(user, "[name] doesn't seem hungry!") - - return ITEM_INTERACT_COMPLETE - -/mob/living/simple_animal/chicken/attack_hand(mob/living/carbon/human/M) - if(M.a_intent == INTENT_HELP) - get_scooped(M, TRUE) - ..() - -/mob/living/simple_animal/chicken/Life(seconds, times_fired) - . = ..() - if((. && prob(3) && eggsleft > 0) && egg_type) - visible_message("[src] [pick(layMessage)]") - eggsleft-- - var/obj/item/E = new egg_type(get_turf(src)) - E.scatter_atom() - if(eggsFertile) - if(GLOB.chicken_count < MAX_CHICKENS && prob(25)) - START_PROCESSING(SSobj, E) - -/obj/item/food/egg/process() - if(isturf(loc)) - amount_grown += rand(1,2) - if(amount_grown >= 100) - visible_message("[src] hatches with a quiet cracking sound.") - new /mob/living/simple_animal/chick(get_turf(src)) - STOP_PROCESSING(SSobj, src) - qdel(src) - else - STOP_PROCESSING(SSobj, src) - -/mob/living/simple_animal/chicken/npc_safe(mob/user) - return TRUE - -/mob/living/simple_animal/chicken/clucky - name = "Commander Clucky" - real_name = "Commander Clucky" - unique_pet = TRUE - -/mob/living/simple_animal/chicken/clucky/npc_safe(mob/user) // depriving the chef of his animals is not cool - return FALSE - -/mob/living/simple_animal/chicken/kentucky - name = "Kentucky" - real_name = "Kentucky" - unique_pet = TRUE - -/mob/living/simple_animal/chicken/kentucky/npc_safe(mob/user) - return FALSE - -/mob/living/simple_animal/chicken/featherbottom - name = "Featherbottom" - real_name = "Featherbottom" - unique_pet = TRUE - -/mob/living/simple_animal/chicken/featherbottom/npc_safe(mob/user) - return FALSE - -/mob/living/simple_animal/turkey - name = "turkey" - desc = "Benjamin Franklin would be proud." - icon_state = "turkey" - icon_living = "turkey" - icon_dead = "turkey_dead" - icon_resting = "turkey_rest" - speak = list("gobble?","gobble","GOBBLE") - speak_emote = list("gobble") - emote_see = list("struts around") - speak_chance = 1 - turns_per_move = 5 - see_in_dark = 6 - butcher_results = list(/obj/item/food/meat = 4) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - attacktext = "pecks" - health = 50 - maxHealth = 50 - mob_biotypes = MOB_ORGANIC | MOB_BEAST - gold_core_spawnable = FRIENDLY_SPAWN - footstep_type = FOOTSTEP_MOB_CLAW - -/mob/living/simple_animal/turkey/Initialize(mapload) - . = ..() - AddElement(/datum/element/wears_collar) - -/mob/living/simple_animal/goose - name = "goose" - desc = "A pretty goose. Would make a nice comforter." - icon_state = "goose" - icon_living = "goose" - icon_dead = "goose_dead" - speak = list("quack?","quack","QUACK") - speak_emote = list("quacks") -// emote_hear = list("brays") - emote_see = list("flaps it's wings") - speak_chance = 1 - turns_per_move = 5 - see_in_dark = 6 - butcher_results = list(/obj/item/food/meat = 6) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - attacktext = "kicks" - health = 50 - maxHealth = 50 - mob_biotypes = MOB_ORGANIC | MOB_BEAST - gold_core_spawnable = FRIENDLY_SPAWN - footstep_type = FOOTSTEP_MOB_CLAW - -/mob/living/simple_animal/goose/Initialize(mapload) - . = ..() - AddElement(/datum/element/wears_collar) - -/mob/living/simple_animal/seal - name = "seal" - desc = "A beautiful white seal." - icon_state = "seal" - icon_living = "seal" - icon_dead = "seal_dead" - speak = list("Urk?","urk","URK") - speak_emote = list("urks") -// emote_hear = list("brays") - emote_see = list("flops around") - speak_chance = 1 - turns_per_move = 5 - see_in_dark = 6 - butcher_results = list(/obj/item/food/meat = 6) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - attacktext = "kicks" - health = 50 - maxHealth = 50 - mob_biotypes = MOB_ORGANIC | MOB_BEAST - gold_core_spawnable = FRIENDLY_SPAWN - blood_volume = BLOOD_VOLUME_NORMAL - -/mob/living/simple_animal/seal/Initialize(mapload) - . = ..() - AddElement(/datum/element/wears_collar) - -/mob/living/simple_animal/walrus - name = "walrus" - desc = "A big brown walrus." - icon_state = "walrus" - icon_living = "walrus" - icon_dead = "walrus_dead" - speak = list("Urk?","urk","URK") - speak_emote = list("urks") -// emote_hear = list("brays") - emote_see = list("flops around") - speak_chance = 1 - turns_per_move = 5 - see_in_dark = 6 - butcher_results = list(/obj/item/food/meat = 6) - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - attacktext = "kicks" - health = 50 - maxHealth = 50 - mob_biotypes = MOB_ORGANIC | MOB_BEAST - gold_core_spawnable = FRIENDLY_SPAWN - blood_volume = BLOOD_VOLUME_NORMAL - -/mob/living/simple_animal/walrus/Initialize(mapload) - . = ..() - AddElement(/datum/element/wears_collar) - -/obj/item/udder - name = "udder" - -/obj/item/udder/Initialize(mapload) - . = ..() - create_reagents(50) - -/obj/item/udder/proc/generateMilk() - if(prob(5)) - reagents.add_reagent("milk", rand(5, 10)) - -/obj/item/udder/proc/milkAnimal(obj/O, mob/user) - var/obj/item/reagent_containers/glass/G = O - if(G.reagents.total_volume >= G.volume) - to_chat(user, "[O] is full.") - return - var/transfered = reagents.trans_to(O, rand(5,10)) - if(transfered) - user.visible_message("[user] milks [src] using \the [O].", "You milk [src] using \the [O].") - else - to_chat(user, "The udder is dry. Wait a bit longer...") - -/obj/item/udder/cow - -/obj/item/udder/cow/Initialize(mapload) - . = ..() - reagents.add_reagent("milk", 20) - -#undef MAX_CHICKENS diff --git a/code/modules/projectiles/projectile/magic_projectiles.dm b/code/modules/projectiles/projectile/magic_projectiles.dm index d79d92f1f48..c1c97b46cc4 100644 --- a/code/modules/projectiles/projectile/magic_projectiles.dm +++ b/code/modules/projectiles/projectile/magic_projectiles.dm @@ -197,7 +197,7 @@ GLOBAL_LIST_INIT(wabbajack_hostile_animals, list( "mushroom" = /mob/living/simple_animal/hostile/mushroom, "statue" = /mob/living/simple_animal/hostile/statue, "bat" = /mob/living/basic/scarybat, - "goat" = /mob/living/simple_animal/hostile/retaliate/goat, + "goat" = /mob/living/basic/goat, "kangaroo" = /mob/living/basic/kangaroo, "tomato" = /mob/living/basic/killertomato, "gorilla" = /mob/living/basic/gorilla, @@ -209,14 +209,14 @@ GLOBAL_LIST_INIT(wabbajack_docile_animals, list( "crab" = /mob/living/simple_animal/crab, "cat" = /mob/living/simple_animal/pet/cat, "mouse" = /mob/living/simple_animal/mouse, - "chicken" = /mob/living/simple_animal/chicken, + "chicken" = /mob/living/basic/chicken, "cow" = /mob/living/basic/cow, "lizard" = /mob/living/basic/lizard, "fox" = /mob/living/simple_animal/pet/dog/fox, - "chick" = /mob/living/simple_animal/chick, + "chick" = /mob/living/basic/chick, "pug" = /mob/living/simple_animal/pet/dog/pug, - "turkey" = /mob/living/simple_animal/turkey, - "seal" = /mob/living/simple_animal/seal, + "turkey" = /mob/living/basic/turkey, + "seal" = /mob/living/basic/seal, "bunny" = /mob/living/basic/bunny, "penguin" = /mob/living/basic/pet/penguin/emperor, )) diff --git a/paradise.dme b/paradise.dme index 013d2aa35dc..9e95ef103e7 100644 --- a/paradise.dme +++ b/paradise.dme @@ -2446,6 +2446,12 @@ #include "code\modules\mob\living\basic\basic_emotes.dm" #include "code\modules\mob\living\basic\basic_mob.dm" #include "code\modules\mob\living\basic\posessed_object.dm" +#include "code\modules\mob\living\basic\farm_animals\chicken.dm" +#include "code\modules\mob\living\basic\farm_animals\goat.dm" +#include "code\modules\mob\living\basic\farm_animals\goose.dm" +#include "code\modules\mob\living\basic\farm_animals\seal.dm" +#include "code\modules\mob\living\basic\farm_animals\turkey.dm" +#include "code\modules\mob\living\basic\farm_animals\udders.dm" #include "code\modules\mob\living\basic\farm_animals\cow.dm" #include "code\modules\mob\living\basic\farm_animals\deer.dm" #include "code\modules\mob\living\basic\farm_animals\deer_ai.dm" @@ -2687,7 +2693,6 @@ #include "code\modules\mob\living\simple_animal\friendly\crab.dm" #include "code\modules\mob\living\simple_animal\friendly\diona_nymph.dm" #include "code\modules\mob\living\simple_animal\friendly\dog.dm" -#include "code\modules\mob\living\simple_animal\friendly\farm_animals.dm" #include "code\modules\mob\living\simple_animal\friendly\fox.dm" #include "code\modules\mob\living\simple_animal\friendly\friendly_emote.dm" #include "code\modules\mob\living\simple_animal\friendly\mouse.dm" diff --git a/sound/creatures/bagawk.ogg b/sound/creatures/bagawk.ogg new file mode 100644 index 0000000000000000000000000000000000000000..c275c4cbbc9c966059e3bed5db252592255a1265 GIT binary patch literal 7285 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 literal 0 HcmV?d00001 diff --git a/sound/creatures/chick_peep.ogg b/sound/creatures/chick_peep.ogg new file mode 100644 index 0000000000000000000000000000000000000000..791246171a6886b431187ea960ffe6b661a2f715 GIT binary patch literal 2845 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 ANdN!< literal 0 HcmV?d00001 diff --git a/sound/creatures/clucks.ogg b/sound/creatures/clucks.ogg new file mode 100644 index 0000000000000000000000000000000000000000..e59afd424d814162785b5178bbacdbd2d4968db9 GIT binary patch literal 10497 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