From d4f25a089f0dbfe1b5f4ace63bc560ce0ce55378 Mon Sep 17 00:00:00 2001 From: mistakenot4892 Date: Wed, 1 Oct 2025 11:59:41 +1000 Subject: [PATCH 1/2] Adding trained bird module. --- .../mob/living/simple_animal/crow/crow.dm | 5 +- mods/content/birds/_birds.dm | 2 + mods/content/birds/_birds.dme | 11 +++ mods/content/birds/bird.dm | 31 +++++++ mods/content/birds/bird_crow.dm | 10 +++ mods/content/birds/bird_hawk.dm | 82 ++++++++++++++++++ mods/content/birds/bird_pigeon.dm | 67 ++++++++++++++ mods/content/birds/hutch.dm | 71 +++++++++++++++ mods/content/birds/icons/aviary.dmi | Bin 0 -> 718 bytes mods/content/birds/icons/crow.dmi | Bin 0 -> 3446 bytes mods/content/birds/icons/hawk.dmi | Bin 0 -> 10319 bytes mods/content/birds/icons/hutch.dmi | Bin 0 -> 641 bytes mods/content/birds/icons/pigeon.dmi | Bin 0 -> 3772 bytes mods/content/fantasy/datum/skills.dm | 7 +- mods/~compatibility/patches/fantasy.dm | 7 +- .../patches/fantasy/bird_fantasy.dm | 2 + 16 files changed, 290 insertions(+), 5 deletions(-) create mode 100644 mods/content/birds/_birds.dm create mode 100644 mods/content/birds/_birds.dme create mode 100644 mods/content/birds/bird.dm create mode 100644 mods/content/birds/bird_crow.dm create mode 100644 mods/content/birds/bird_hawk.dm create mode 100644 mods/content/birds/bird_pigeon.dm create mode 100644 mods/content/birds/hutch.dm create mode 100644 mods/content/birds/icons/aviary.dmi create mode 100644 mods/content/birds/icons/crow.dmi create mode 100644 mods/content/birds/icons/hawk.dmi create mode 100644 mods/content/birds/icons/hutch.dmi create mode 100644 mods/content/birds/icons/pigeon.dmi create mode 100644 mods/~compatibility/patches/fantasy/bird_fantasy.dm diff --git a/code/modules/mob/living/simple_animal/crow/crow.dm b/code/modules/mob/living/simple_animal/crow/crow.dm index 2ee46b3e0df2..8fd974b53c61 100644 --- a/code/modules/mob/living/simple_animal/crow/crow.dm +++ b/code/modules/mob/living/simple_animal/crow/crow.dm @@ -7,6 +7,7 @@ storage = /datum/storage/backpack/crow material = /decl/material/solid/organic/cloth +// TODO: Merge with /mob/living/simple_animal/passive/bird/crow /mob/living/simple_animal/crow name = "crow" desc = "A large crow. Caw caw." @@ -15,7 +16,7 @@ mob_size = MOB_SIZE_SMALL speak_emote = list("caws") ai = /datum/mob_controller/crow - natural_weapon = /obj/item/natural_weapon/crow_claws + natural_weapon = /obj/item/natural_weapon/bird_claws universal_speak = TRUE /datum/mob_controller/crow @@ -34,7 +35,7 @@ /mob/living/simple_animal/crow/get_bodytype() return GET_DECL(/decl/bodytype/animal/crow) -/obj/item/natural_weapon/crow_claws +/obj/item/natural_weapon/bird_claws name = "claws" gender = PLURAL attack_verb = "clawed" diff --git a/mods/content/birds/_birds.dm b/mods/content/birds/_birds.dm new file mode 100644 index 000000000000..f8a627b127f1 --- /dev/null +++ b/mods/content/birds/_birds.dm @@ -0,0 +1,2 @@ +/decl/modpack/birds + name = "Birds" diff --git a/mods/content/birds/_birds.dme b/mods/content/birds/_birds.dme new file mode 100644 index 000000000000..dac5a08b08a6 --- /dev/null +++ b/mods/content/birds/_birds.dme @@ -0,0 +1,11 @@ +#ifndef MODPACK_BIRDS +#define MODPACK_BIRDS +// BEGIN_INCLUDE +#include "_birds.dm" +#include "bird.dm" +#include "bird_crow.dm" +#include "bird_hawk.dm" +#include "bird_pigeon.dm" +#include "hutch.dm" +// END_INCLUDE +#endif diff --git a/mods/content/birds/bird.dm b/mods/content/birds/bird.dm new file mode 100644 index 000000000000..6be2df996f21 --- /dev/null +++ b/mods/content/birds/bird.dm @@ -0,0 +1,31 @@ +/mob/living/simple_animal/passive/bird + mob_size = MOB_SIZE_SMALL + pass_flags = PASS_FLAG_TABLE + abstract_type = /mob/living/simple_animal/passive/bird + natural_weapon = /obj/item/natural_weapon/bird_claws + holder_type = /obj/item/holder/bird + +/obj/item/holder/bird + w_class = MOB_SIZE_SMALL + +/obj/item/holder/bird/attack_self(mob/user) + var/mob/living/bird = locate() in contents + if(istype(bird?.ai) && bird.ai.process_holder_interaction(user)) + return TRUE + return ..() + +/obj/item/holder/bird/afterattack(atom/target, mob/user, proximity) + if(proximity) + return ..() + var/mob/living/bird = locate() in contents + . = ..() + if(!user || !bird || QDELETED(src) || bird.loc != src) + return + bird.dropInto(loc) + qdel(src) // This will happen shortly regardless, but might as well skip the 1ds delay. + if(isturf(target)) + bird.visible_message(SPAN_NOTICE("\The [user] releases \a [bird]!")) + else + bird.visible_message(SPAN_NOTICE("\The [user] indicates \the [target] and releases \a [bird]!")) + if(istype(bird.ai)) + bird.ai.process_handler_target(user, target, user.get_intent()?.intent_flags) diff --git a/mods/content/birds/bird_crow.dm b/mods/content/birds/bird_crow.dm new file mode 100644 index 000000000000..32a4836eac83 --- /dev/null +++ b/mods/content/birds/bird_crow.dm @@ -0,0 +1,10 @@ +/datum/mob_controller/passive/crow + emote_speech = list("Caw.","Caw!","Caw...") + emote_hear = list("croaks", "caws") + emote_see = list("preens its feathers", "hops around") + +/mob/living/simple_animal/passive/bird/crow + name = "crow" + icon = 'mods/content/birds/icons/crow.dmi' + ai = /datum/mob_controller/passive/crow + ability_handlers = list(/datum/ability_handler/predator) // should really be /scavenger diff --git a/mods/content/birds/bird_hawk.dm b/mods/content/birds/bird_hawk.dm new file mode 100644 index 000000000000..f391e1c63e0a --- /dev/null +++ b/mods/content/birds/bird_hawk.dm @@ -0,0 +1,82 @@ +/mob/living/simple_animal/passive/bird/hawk + name = "hawk" + icon = 'mods/content/birds/icons/hawk.dmi' + ai = /datum/mob_controller/passive/hunter/hawk + ability_handlers = list(/datum/ability_handler/predator) + +/datum/mob_controller/passive/hunter/hawk + emote_speech = list("Skree!","SKREE!","Skree!?") + emote_hear = list("screeches", "screams") + emote_see = list("preens its feathers", "flicks its wings", "looks sharply around") + var/handler_set_target = FALSE + var/handling_skill = SKILL_BOTANY + var/handling_difficulty = SKILL_ADEPT + +/datum/mob_controller/passive/hunter/hawk/consume_prey(mob/living/prey) + if(prey.stat == DEAD && last_handler && handler_set_target) + set_target(last_handler?.resolve()) + prey.try_make_grab(body, defer_hand = TRUE) + return + return ..() + +/datum/mob_controller/passive/hunter/hawk/set_target(atom/new_target) + . = ..() + handler_set_target = FALSE + +/datum/mob_controller/passive/hunter/hawk/process_handler_target(mob/handler, atom/target) + if((. = ..())) + set_target(target) + handler_set_target = TRUE + process_hunting(target) + +/datum/mob_controller/passive/hunter/hawk/can_hunt(mob/living/victim) + return handler_set_target || ..() + +/datum/mob_controller/passive/hunter/hawk/check_handler_can_order(mob/handler, atom/target, intent_flags) + if(!(. = ..()) && handler.skill_check(handling_skill, handling_difficulty)) + add_friend(handler) + return ..() + +/datum/mob_controller/passive/hunter/hawk/process_handler_failure(mob/handler, atom/target) + body?.visible_message(SPAN_DANGER("\The [body] ignores \the [target] in favour of attacking \the [handler]!")) + set_target(handler) + handler_set_target = TRUE + next_hunt = 0 + return ..() + +/datum/mob_controller/passive/hunter/hawk/handle_friend_hunting(mob/user) + ..() + set_target(null) + resume_wandering() + if(!body) + return + if(body.scoop_check(user) && body.get_scooped(user, body, silent = TRUE)) + body.visible_message(SPAN_NOTICE("\The [body] alights on \the [user].")) + else + body.visible_message(SPAN_NOTICE("\The [body] lands beside \the [user].")) + + for(var/obj/item/thing in body.get_equipped_items(include_carried = TRUE)) + body.drop_from_inventory(thing) + if(!QDELETED(thing)) + user.put_in_hands(thing) + var/equipped_to = user.get_equipped_slot_for_item(thing) + var/datum/inventory_slot/slot = equipped_to && user.get_inventory_slot_datum(equipped_to) + if(istype(slot)) + to_chat(user, SPAN_NOTICE("\The [body] drops \a [thing] into your [lowertext(slot.slot_name)].")) + else + to_chat(user, SPAN_NOTICE("\The [body] drops \a [thing].")) + + return TRUE + +/datum/mob_controller/passive/hunter/hawk/process_hunting(atom/target) + // Handles pathing to the target, and attacking the target if it's a mob. + if(!(. = ..())) + return + // Maybe consider handling structures at some point? + if(isitem(target) && body.Adjacent(target)) + body.put_in_hands(target) + if(target.loc != body) + body.visible_message(SPAN_WARNING("\The [body] fails to collect \the [target]!")) + // Return to handler. + set_target(last_handler?.resolve()) + return FALSE diff --git a/mods/content/birds/bird_pigeon.dm b/mods/content/birds/bird_pigeon.dm new file mode 100644 index 000000000000..40af24aeb746 --- /dev/null +++ b/mods/content/birds/bird_pigeon.dm @@ -0,0 +1,67 @@ +/mob/living/simple_animal/passive/bird/pigeon + name = "messenger pigeon" + icon = 'mods/content/birds/icons/pigeon.dmi' + ai = /datum/mob_controller/passive/pigeon + holder_type = /obj/item/holder/bird/pigeon + var/weakref/home_hutch + +/mob/living/simple_animal/passive/bird/pigeon/Initialize() + . = ..() + update_hutch() + +/mob/living/simple_animal/passive/bird/pigeon/proc/go_home(mob/releaser) + if(!is_outside()) + return + var/obj/structure/hutch/hutch = home_hutch?.resolve() + if(!istype(hutch) || QDELETED(hutch)) + return // todo: check if the hutch is accessible from the sky + if(releaser) + releaser.visible_message(SPAN_NOTICE("\The [releaser] releases \a [src], which flutters away into the sky.")) + else + visible_message(SPAN_NOTICE("\The [src] flutters away into the sky.")) + set_dir(SOUTH) + // this is done manually due to the actual flying state primarily being handled as a movement state. + icon_state = "world-flying" + new /obj/effect/dummy/fadeout(loc, NORTH, src) + new /obj/effect/dummy/fadein(get_turf(hutch), SOUTH, src) + update_icon() + + hutch.visible_message(SPAN_NOTICE("\A [src] alights on \the [hutch] in a flutter of wings.")) + var/obj/item/holder/bird_item = new holder_type + forceMove(bird_item) + bird_item.sync(src) + hutch.storage?.handle_item_insertion(null, bird_item) + if(bird_item.loc != hutch) + dropInto(hutch.loc) + qdel(bird_item) + +/obj/item/holder/bird/pigeon/attack_self(mob/user) + var/mob/living/simple_animal/passive/bird/pigeon/pigeon = locate() in contents + if(!istype(pigeon)) + return ..() + if(!is_outside()) + to_chat(user, SPAN_WARNING("You need to be outdoors to release \the [pigeon].")) + return TRUE + if(isnull(pigeon.home_hutch)) + var/decl/pronouns/pronouns = pigeon.get_pronouns() + to_chat(user, SPAN_WARNING("\The [pigeon] tilts [pronouns.his] head at you in confusion. [pronouns.He] must not have a hutch to return to.")) + else + user.drop_from_inventory(src) + pigeon.go_home(user) + qdel(src) + return TRUE + +/mob/living/simple_animal/passive/bird/pigeon/proc/update_hutch() + var/obj/structure/hutch/hutch = home_hutch?.resolve() + if(!istype(hutch) || QDELETED(hutch)) + hutch = get_recursive_loc_of_type(/obj/structure/hutch) + if(istype(hutch) && !QDELETED(hutch)) + home_hutch = weakref(hutch) + events_repository.unregister(/decl/observ/moved, src, src) + else + events_repository.register(/decl/observ/moved, src, src, TYPE_PROC_REF(/mob/living/simple_animal/passive/bird/pigeon, update_hutch)) + +/datum/mob_controller/passive/pigeon + emote_speech = list("Oo-ooo.","Oo-ooo?","Oo-ooo...") + emote_hear = list("coos") + emote_see = list("preens its feathers", "puffs out its neck", "ruffles its wings") diff --git a/mods/content/birds/hutch.dm b/mods/content/birds/hutch.dm new file mode 100644 index 000000000000..fae7915f735f --- /dev/null +++ b/mods/content/birds/hutch.dm @@ -0,0 +1,71 @@ +/datum/storage/hutch + can_hold = list(/obj/item/holder) + max_w_class = MOB_SIZE_SMALL + storage_slots = 10 + +/datum/storage/hutch/open(mob/user) + . = ..() + var/atom/hutch = holder + if(istype(hutch)) + hutch.queue_icon_update() + +/datum/storage/hutch/close(mob/user) + . = ..() + var/atom/hutch = holder + if(istype(hutch)) + hutch.queue_icon_update() + +/obj/structure/hutch + name = "hutch" + icon = 'mods/content/birds/icons/hutch.dmi' + desc = "A hutch for containing small animals like rabbits." + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_ALL + storage = /datum/storage/hutch + var/initial_animal_count = 5 + var/decl/material/door_material = /decl/material/solid/organic/plantmatter/grass/dry + var/initial_animal_type + +/obj/structure/hutch/Initialize(ml, _mat, _reinf_mat) + . = ..() + + if(ispath(door_material)) + door_material = GET_DECL(door_material) + + if(initial_animal_type && initial_animal_count) + for(var/i = 1 to initial_animal_count) + var/mob/bird_type = islist(initial_animal_type) ? pick(initial_animal_type) : initial_animal_type + var/bird_holder_type = bird_type::holder_type + var/obj/item/holder/bird/bird_item = new bird_holder_type(src) + bird_item.sync(new bird_type(bird_item)) + else + update_icon() + +/obj/structure/hutch/on_update_icon() + . = ..() + if(door_material) + add_overlay(overlay_image(icon, "[icon_state]-doors-[storage?.opened ? "open" : "closed"]", door_material.color, RESET_COLOR)) + +// Bird subtypes. +/obj/structure/hutch/aviary + name = "aviary" + desc = "A hutch for containing birds like hawks or crows." + icon = 'mods/content/birds/icons/aviary.dmi' + +/obj/structure/hutch/aviary/crow + initial_animal_type = /mob/living/simple_animal/passive/bird/crow + +/obj/structure/hutch/aviary/pigeon + initial_animal_type = /mob/living/simple_animal/passive/bird/pigeon + +/obj/structure/hutch/aviary/hawk + initial_animal_type = /mob/living/simple_animal/passive/bird/hawk + +// Rabbits are a kind of bird, right? +/obj/structure/hutch/rabbit + initial_animal_type = list( + /mob/living/simple_animal/passive/rabbit, + /mob/living/simple_animal/passive/rabbit/black, + /mob/living/simple_animal/passive/rabbit/brown + ) diff --git a/mods/content/birds/icons/aviary.dmi b/mods/content/birds/icons/aviary.dmi new file mode 100644 index 0000000000000000000000000000000000000000..8ba4c4443f9a168feb46f5251e69d23ee0fc278b GIT binary patch literal 718 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 literal 0 HcmV?d00001 diff --git a/mods/content/birds/icons/hawk.dmi b/mods/content/birds/icons/hawk.dmi new file mode 100644 index 0000000000000000000000000000000000000000..304546724903226ba99808dc4555ddc3a5511947 GIT binary patch literal 10319 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%0AIFN-H|zp03ncTe$Mmp{e}s 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 literal 0 HcmV?d00001 diff --git a/mods/content/birds/icons/hutch.dmi b/mods/content/birds/icons/hutch.dmi new file mode 100644 index 0000000000000000000000000000000000000000..8d5f7e2165bdce250d504d2a3faa930b414e4100 GIT binary patch literal 641 zcmV-{0)G98P)D@x2wg|Jao>89l87ZvL!=j0cslBOlUATKRLgRNAP`iO+*i@NGVFbM?0rQ(AY{w` z|CKPnx+aR`l*%D31*Ow8GhHJ^5zsUP#c?VU0LBfB6YEn1(((xg!IBDXI~w4EBnb>g za3X0!OSB?lN+;P6sv2!bGD)D^uyJa)3MKUh5GE!ZTZKw##kfivRZ1t!m8}Ebw*<{a zJE}QiOQ^I!4+e@D`0`yNZm3{{avns&c_A=24yUr&6tbhC#s$AUA z%OSx~)gKb5$|xu*GYT@Jkc$_&_)k#XGI7&q;(y&qcdJP%4iwy-bew^^laBU3Zna|t bNGp5-Pa|u&o;?pe00000NkvXXu0mjfl6Mo| literal 0 HcmV?d00001 diff --git a/mods/content/birds/icons/pigeon.dmi b/mods/content/birds/icons/pigeon.dmi new file mode 100644 index 0000000000000000000000000000000000000000..678fd450c83e463481cf963e6f7c0d55817adcc0 GIT binary patch literal 3772 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 literal 0 HcmV?d00001 diff --git a/mods/content/fantasy/datum/skills.dm b/mods/content/fantasy/datum/skills.dm index 30736399780b..54a75cacac59 100644 --- a/mods/content/fantasy/datum/skills.dm +++ b/mods/content/fantasy/datum/skills.dm @@ -230,8 +230,11 @@ "Master" = "You're a specialized animal caretaker. You can care for even the most exotic, fragile, or dangerous animals." ) -/obj/item/food/egg/examine_skill = SKILL_HUSBANDRY -/mob/living/simple_animal/chick/examine_skill = SKILL_HUSBANDRY +/obj/item/food/egg + examine_skill = SKILL_HUSBANDRY + +/mob/living/simple_animal/chick + examine_skill = SKILL_HUSBANDRY /datum/extension/milkable milking_skill = SKILL_HUSBANDRY diff --git a/mods/~compatibility/patches/fantasy.dm b/mods/~compatibility/patches/fantasy.dm index b0abba63bcd4..3f3ba3462e43 100644 --- a/mods/~compatibility/patches/fantasy.dm +++ b/mods/~compatibility/patches/fantasy.dm @@ -10,4 +10,9 @@ #ifdef MODPACK_BLACKSMITHY #include "fantasy/forging_fantasy.dm" -#endif \ No newline at end of file +#endif + +// Override hawk handling skill. +#ifdef MODPACK_BIRDS +#include "fantasy/bird_fantasy.dm" +#endif diff --git a/mods/~compatibility/patches/fantasy/bird_fantasy.dm b/mods/~compatibility/patches/fantasy/bird_fantasy.dm new file mode 100644 index 000000000000..f6b73ecf75a3 --- /dev/null +++ b/mods/~compatibility/patches/fantasy/bird_fantasy.dm @@ -0,0 +1,2 @@ +/datum/mob_controller/passive/hunter/hawk + handling_skill = SKILL_HUSBANDRY From d3c816b225fcf16d7c20377b8d468ae046b0b9e3 Mon Sep 17 00:00:00 2001 From: mistakenot4892 Date: Fri, 10 Oct 2025 22:32:39 +1100 Subject: [PATCH 2/2] Moving some holder interaction from birds to holders in general. --- code/modules/mob_holder/_holder.dm | 13 +++++++++++-- mods/content/birds/bird.dm | 6 ------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/code/modules/mob_holder/_holder.dm b/code/modules/mob_holder/_holder.dm index 3cc51f873e18..26872e92c37e 100644 --- a/code/modules/mob_holder/_holder.dm +++ b/code/modules/mob_holder/_holder.dm @@ -123,9 +123,18 @@ if(length(cards)) LAZYDISTINCTADD(., cards) +/obj/item/holder/handle_mouse_drop(atom/over, mob/user, params) + if(over == user && user != src && !(user in src)) + for(var/mob/M in contents) + M.show_stripping_window(user) // TODO: verify that you can even strip items from a mob in an item + . = TRUE + . = . || ..() + /obj/item/holder/attack_self(mob/user) - for(var/mob/M in contents) - M.show_stripping_window(user) + var/mob/living/bird = locate() in contents + if(istype(bird?.ai)) + bird.ai.process_holder_interaction(user) + return TRUE /obj/item/holder/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) diff --git a/mods/content/birds/bird.dm b/mods/content/birds/bird.dm index 6be2df996f21..b0d37f607efd 100644 --- a/mods/content/birds/bird.dm +++ b/mods/content/birds/bird.dm @@ -8,12 +8,6 @@ /obj/item/holder/bird w_class = MOB_SIZE_SMALL -/obj/item/holder/bird/attack_self(mob/user) - var/mob/living/bird = locate() in contents - if(istype(bird?.ai) && bird.ai.process_holder_interaction(user)) - return TRUE - return ..() - /obj/item/holder/bird/afterattack(atom/target, mob/user, proximity) if(proximity) return ..()