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 00000000000..c275c4cbbc9
Binary files /dev/null and b/sound/creatures/bagawk.ogg differ
diff --git a/sound/creatures/chick_peep.ogg b/sound/creatures/chick_peep.ogg
new file mode 100644
index 00000000000..791246171a6
Binary files /dev/null and b/sound/creatures/chick_peep.ogg differ
diff --git a/sound/creatures/clucks.ogg b/sound/creatures/clucks.ogg
new file mode 100644
index 00000000000..e59afd424d8
Binary files /dev/null and b/sound/creatures/clucks.ogg differ
diff --git a/tools/UpdatePaths/Scripts/30244_basic_farm_animals.txt b/tools/UpdatePaths/Scripts/30244_basic_farm_animals.txt
new file mode 100644
index 00000000000..8917c70b76f
--- /dev/null
+++ b/tools/UpdatePaths/Scripts/30244_basic_farm_animals.txt
@@ -0,0 +1,7 @@
+/mob/living/simple_animal/hostile/retaliate/goat/@SUBTYPES : /mob/living/basic/goat/@SUBTYPES{@OLD}
+/mob/living/simple_animal/chick/@SUBTYPES : /mob/living/basic/chick/@SUBTYPES{@OLD}
+/mob/living/simple_animal/chicken/@SUBTYPES : /mob/living/basic/chicken/@SUBTYPES{@OLD}
+/mob/living/simple_animal/turkey/@SUBTYPES : /mob/living/basic/turkey/@SUBTYPES{@OLD}
+/mob/living/simple_animal/goose/@SUBTYPES : /mob/living/basic/goose/@SUBTYPES{@OLD}
+/mob/living/simple_animal/seal/@SUBTYPES : /mob/living/basic/seal/@SUBTYPES{@OLD}
+/mob/living/simple_animal/walrus/@SUBTYPES : /mob/living/basic/seal/walrus/@SUBTYPES{@OLD}
diff --git a/tools/ci/check_simplemob_additions.py b/tools/ci/check_simplemob_additions.py
index 582f3d8e15d..df6dd933ac5 100644
--- a/tools/ci/check_simplemob_additions.py
+++ b/tools/ci/check_simplemob_additions.py
@@ -45,11 +45,6 @@ BURNDOWN_LIST = {
"/mob/living/simple_animal/bot/secbot/griefsky/toy",
"/mob/living/simple_animal/bot/secbot/ofitser",
"/mob/living/simple_animal/bot/secbot/pingsky",
- "/mob/living/simple_animal/chick",
- "/mob/living/simple_animal/chicken",
- "/mob/living/simple_animal/chicken/clucky",
- "/mob/living/simple_animal/chicken/featherbottom",
- "/mob/living/simple_animal/chicken/kentucky",
"/mob/living/simple_animal/crab",
"/mob/living/simple_animal/crab/coffee",
"/mob/living/simple_animal/crab/evil",
@@ -63,7 +58,6 @@ BURNDOWN_LIST = {
"/mob/living/simple_animal/demon/slaughter/lesser",
"/mob/living/simple_animal/diona",
"/mob/living/simple_animal/drone",
- "/mob/living/simple_animal/goose",
"/mob/living/simple_animal/hostile",
"/mob/living/simple_animal/hostile/ancient_robot_leg",
"/mob/living/simple_animal/hostile/asteroid",
@@ -170,8 +164,6 @@ BURNDOWN_LIST = {
"/mob/living/simple_animal/hostile/retaliate/carp",
"/mob/living/simple_animal/hostile/retaliate/carp/koi",
"/mob/living/simple_animal/hostile/retaliate/carp/koi/honk",
- "/mob/living/simple_animal/hostile/retaliate/goat",
- "/mob/living/simple_animal/hostile/retaliate/goat/chef",
"/mob/living/simple_animal/hostile/spaceinfected",
"/mob/living/simple_animal/hostile/spaceinfected/default",
"/mob/living/simple_animal/hostile/spaceinfected/default/ranged",
@@ -231,7 +223,6 @@ BURNDOWN_LIST = {
"/mob/living/simple_animal/pet/dog/fox/syndifox",
"/mob/living/simple_animal/pet/dog/pug",
"/mob/living/simple_animal/revenant",
- "/mob/living/simple_animal/seal",
"/mob/living/simple_animal/shade",
"/mob/living/simple_animal/shade/cult",
"/mob/living/simple_animal/shade/holy",
@@ -242,8 +233,6 @@ BURNDOWN_LIST = {
"/mob/living/simple_animal/slime/random",
"/mob/living/simple_animal/slime/unit_test_dummy",
"/mob/living/simple_animal/spiderbot",
- "/mob/living/simple_animal/turkey",
- "/mob/living/simple_animal/walrus",
}
}