Skip to content

Commit 8c3c923

Browse files
Adding trained bird module.
1 parent 39d3ec7 commit 8c3c923

File tree

16 files changed

+290
-5
lines changed

16 files changed

+290
-5
lines changed

code/modules/mob/living/simple_animal/crow/crow.dm

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
storage = /datum/storage/backpack/crow
88
material = /decl/material/solid/organic/cloth
99

10+
// TODO: Merge with /mob/living/simple_animal/passive/bird/crow
1011
/mob/living/simple_animal/crow
1112
name = "crow"
1213
desc = "A large crow. Caw caw."
@@ -15,7 +16,7 @@
1516
mob_size = MOB_SIZE_SMALL
1617
speak_emote = list("caws")
1718
ai = /datum/mob_controller/crow
18-
natural_weapon = /obj/item/natural_weapon/crow_claws
19+
natural_weapon = /obj/item/natural_weapon/bird_claws
1920
universal_speak = TRUE
2021

2122
/datum/mob_controller/crow
@@ -34,7 +35,7 @@
3435
/mob/living/simple_animal/crow/get_bodytype()
3536
return GET_DECL(/decl/bodytype/animal/crow)
3637

37-
/obj/item/natural_weapon/crow_claws
38+
/obj/item/natural_weapon/bird_claws
3839
name = "claws"
3940
gender = PLURAL
4041
attack_verb = "clawed"

mods/content/birds/_birds.dm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/decl/modpack/birds
2+
name = "Birds"

mods/content/birds/_birds.dme

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#ifndef MODPACK_BIRDS
2+
#define MODPACK_BIRDS
3+
// BEGIN_INCLUDE
4+
#include "_birds.dm"
5+
#include "bird.dm"
6+
#include "bird_crow.dm"
7+
#include "bird_hawk.dm"
8+
#include "bird_pigeon.dm"
9+
#include "hutch.dm"
10+
// END_INCLUDE
11+
#endif

mods/content/birds/bird.dm

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/mob/living/simple_animal/passive/bird
2+
mob_size = MOB_SIZE_SMALL
3+
pass_flags = PASS_FLAG_TABLE
4+
abstract_type = /mob/living/simple_animal/passive/bird
5+
natural_weapon = /obj/item/natural_weapon/bird_claws
6+
holder_type = /obj/item/holder/bird
7+
8+
/obj/item/holder/bird
9+
w_class = MOB_SIZE_SMALL
10+
11+
/obj/item/holder/bird/attack_self(mob/user)
12+
var/mob/living/bird = locate() in contents
13+
if(istype(bird?.ai) && bird.ai.process_holder_interaction(user))
14+
return TRUE
15+
return ..()
16+
17+
/obj/item/holder/bird/afterattack(atom/target, mob/user, proximity)
18+
if(proximity)
19+
return ..()
20+
var/mob/living/bird = locate() in contents
21+
. = ..()
22+
if(!user || !bird || QDELETED(src) || bird.loc != src)
23+
return
24+
bird.dropInto(loc)
25+
qdel(src) // This will happen shortly regardless, but might as well skip the 1ds delay.
26+
if(isturf(target))
27+
bird.visible_message(SPAN_NOTICE("\The [user] releases \a [bird]!"))
28+
else
29+
bird.visible_message(SPAN_NOTICE("\The [user] indicates \the [target] and releases \a [bird]!"))
30+
if(istype(bird.ai))
31+
bird.ai.process_handler_target(user, target, user.get_intent()?.intent_flags)

mods/content/birds/bird_crow.dm

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/datum/mob_controller/passive/crow
2+
emote_speech = list("Caw.","Caw!","Caw...")
3+
emote_hear = list("croaks", "caws")
4+
emote_see = list("preens its feathers", "hops around")
5+
6+
/mob/living/simple_animal/passive/bird/crow
7+
name = "crow"
8+
icon = 'mods/content/birds/icons/crow.dmi'
9+
ai = /datum/mob_controller/passive/crow
10+
ability_handlers = list(/datum/ability_handler/predator) // should really be /scavenger

mods/content/birds/bird_hawk.dm

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/mob/living/simple_animal/passive/bird/hawk
2+
name = "hawk"
3+
icon = 'mods/content/birds/icons/hawk.dmi'
4+
ai = /datum/mob_controller/passive/hunter/hawk
5+
ability_handlers = list(/datum/ability_handler/predator)
6+
7+
/datum/mob_controller/passive/hunter/hawk
8+
emote_speech = list("Skree!","SKREE!","Skree!?")
9+
emote_hear = list("screeches", "screams")
10+
emote_see = list("preens its feathers", "flicks its wings", "looks sharply around")
11+
var/handler_set_target = FALSE
12+
var/handling_skill = SKILL_BOTANY
13+
var/handling_difficulty = SKILL_ADEPT
14+
15+
/datum/mob_controller/passive/hunter/hawk/consume_prey(mob/living/prey)
16+
if(prey.stat == DEAD && last_handler && handler_set_target)
17+
set_target(last_handler?.resolve())
18+
prey.try_make_grab(body, defer_hand = TRUE)
19+
return
20+
return ..()
21+
22+
/datum/mob_controller/passive/hunter/hawk/set_target(atom/new_target)
23+
. = ..()
24+
handler_set_target = FALSE
25+
26+
/datum/mob_controller/passive/hunter/hawk/process_handler_target(mob/handler, atom/target)
27+
if((. = ..()))
28+
set_target(target)
29+
handler_set_target = TRUE
30+
process_hunting(target)
31+
32+
/datum/mob_controller/passive/hunter/hawk/can_hunt(mob/living/victim)
33+
return handler_set_target || ..()
34+
35+
/datum/mob_controller/passive/hunter/hawk/check_handler_can_order(mob/handler, atom/target, intent_flags)
36+
if(!(. = ..()) && handler.skill_check(handling_skill, handling_difficulty))
37+
add_friend(handler)
38+
return ..()
39+
40+
/datum/mob_controller/passive/hunter/hawk/process_handler_failure(mob/handler, atom/target)
41+
body?.visible_message(SPAN_DANGER("\The [body] ignores \the [target] in favour of attacking \the [handler]!"))
42+
set_target(handler)
43+
handler_set_target = TRUE
44+
next_hunt = 0
45+
return ..()
46+
47+
/datum/mob_controller/passive/hunter/hawk/handle_friend_hunting(mob/user)
48+
..()
49+
set_target(null)
50+
resume_wandering()
51+
if(!body)
52+
return
53+
if(body.scoop_check(user) && body.get_scooped(user, body, silent = TRUE))
54+
body.visible_message(SPAN_NOTICE("\The [body] alights on \the [user]."))
55+
else
56+
body.visible_message(SPAN_NOTICE("\The [body] lands beside \the [user]."))
57+
58+
for(var/obj/item/thing in body.get_equipped_items(include_carried = TRUE))
59+
body.drop_from_inventory(thing)
60+
if(!QDELETED(thing))
61+
user.put_in_hands(thing)
62+
var/equipped_to = user.get_equipped_slot_for_item(thing)
63+
var/datum/inventory_slot/slot = equipped_to && user.get_inventory_slot_datum(equipped_to)
64+
if(istype(slot))
65+
to_chat(user, SPAN_NOTICE("\The [body] drops \a [thing] into your [lowertext(slot.slot_name)]."))
66+
else
67+
to_chat(user, SPAN_NOTICE("\The [body] drops \a [thing]."))
68+
69+
return TRUE
70+
71+
/datum/mob_controller/passive/hunter/hawk/process_hunting(atom/target)
72+
// Handles pathing to the target, and attacking the target if it's a mob.
73+
if(!(. = ..()))
74+
return
75+
// Maybe consider handling structures at some point?
76+
if(isitem(target) && body.Adjacent(target))
77+
body.put_in_hands(target)
78+
if(target.loc != body)
79+
body.visible_message(SPAN_WARNING("\The [body] fails to collect \the [target]!"))
80+
// Return to handler.
81+
set_target(last_handler?.resolve())
82+
return FALSE

mods/content/birds/bird_pigeon.dm

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/mob/living/simple_animal/passive/bird/pigeon
2+
name = "messenger pigeon"
3+
icon = 'mods/content/birds/icons/pigeon.dmi'
4+
ai = /datum/mob_controller/passive/pigeon
5+
holder_type = /obj/item/holder/bird/pigeon
6+
var/weakref/home_hutch
7+
8+
/mob/living/simple_animal/passive/bird/pigeon/Initialize()
9+
. = ..()
10+
update_hutch()
11+
12+
/mob/living/simple_animal/passive/bird/pigeon/proc/go_home(mob/releaser)
13+
if(!is_outside())
14+
return
15+
var/obj/structure/hutch/hutch = home_hutch?.resolve()
16+
if(!istype(hutch) || QDELETED(hutch))
17+
return // todo: check if the hutch is accessible from the sky
18+
if(releaser)
19+
releaser.visible_message(SPAN_NOTICE("\The [releaser] releases \a [src], which flutters away into the sky."))
20+
else
21+
visible_message(SPAN_NOTICE("\The [src] flutters away into the sky."))
22+
set_dir(SOUTH)
23+
// this is done manually due to the actual flying state primarily being handled as a movement state.
24+
icon_state = "world-flying"
25+
new /obj/effect/dummy/fadeout(loc, NORTH, src)
26+
new /obj/effect/dummy/fadein(get_turf(hutch), SOUTH, src)
27+
update_icon()
28+
29+
hutch.visible_message(SPAN_NOTICE("\A [src] alights on \the [hutch] in a flutter of wings."))
30+
var/obj/item/holder/bird_item = new holder_type
31+
forceMove(bird_item)
32+
bird_item.sync(src)
33+
hutch.storage?.handle_item_insertion(null, bird_item)
34+
if(bird_item.loc != hutch)
35+
dropInto(hutch.loc)
36+
qdel(bird_item)
37+
38+
/obj/item/holder/bird/pigeon/attack_self(mob/user)
39+
var/mob/living/simple_animal/passive/bird/pigeon/pigeon = locate() in contents
40+
if(!istype(pigeon))
41+
return ..()
42+
if(!is_outside())
43+
to_chat(user, SPAN_WARNING("You need to be outdoors to release \the [pigeon]."))
44+
return TRUE
45+
if(isnull(pigeon.home_hutch))
46+
var/decl/pronouns/pronouns = pigeon.get_pronouns()
47+
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."))
48+
else
49+
user.drop_from_inventory(src)
50+
pigeon.go_home(user)
51+
qdel(src)
52+
return TRUE
53+
54+
/mob/living/simple_animal/passive/bird/pigeon/proc/update_hutch()
55+
var/obj/structure/hutch/hutch = home_hutch?.resolve()
56+
if(!istype(hutch) || QDELETED(hutch))
57+
hutch = get_recursive_loc_of_type(/obj/structure/hutch)
58+
if(istype(hutch) && !QDELETED(hutch))
59+
home_hutch = weakref(hutch)
60+
events_repository.unregister(/decl/observ/moved, src, src)
61+
else
62+
events_repository.register(/decl/observ/moved, src, src, TYPE_PROC_REF(/mob/living/simple_animal/passive/bird/pigeon, update_hutch))
63+
64+
/datum/mob_controller/passive/pigeon
65+
emote_speech = list("Oo-ooo.","Oo-ooo?","Oo-ooo...")
66+
emote_hear = list("coos")
67+
emote_see = list("preens its feathers", "puffs out its neck", "ruffles its wings")

mods/content/birds/hutch.dm

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/datum/storage/hutch
2+
can_hold = list(/obj/item/holder)
3+
max_w_class = MOB_SIZE_SMALL
4+
storage_slots = 10
5+
6+
/datum/storage/hutch/open(mob/user)
7+
. = ..()
8+
var/atom/hutch = holder
9+
if(istype(hutch))
10+
hutch.queue_icon_update()
11+
12+
/datum/storage/hutch/close(mob/user)
13+
. = ..()
14+
var/atom/hutch = holder
15+
if(istype(hutch))
16+
hutch.queue_icon_update()
17+
18+
/obj/structure/hutch
19+
name = "hutch"
20+
icon = 'mods/content/birds/icons/hutch.dmi'
21+
desc = "A hutch for containing small animals like rabbits."
22+
icon_state = ICON_STATE_WORLD
23+
material = /decl/material/solid/organic/wood/oak
24+
material_alteration = MAT_FLAG_ALTERATION_ALL
25+
storage = /datum/storage/hutch
26+
var/initial_animal_count = 5
27+
var/decl/material/door_material = /decl/material/solid/organic/plantmatter/grass/dry
28+
var/initial_animal_type
29+
30+
/obj/structure/hutch/Initialize(ml, _mat, _reinf_mat)
31+
. = ..()
32+
33+
if(ispath(door_material))
34+
door_material = GET_DECL(door_material)
35+
36+
if(initial_animal_type && initial_animal_count)
37+
for(var/i = 1 to initial_animal_count)
38+
var/mob/bird_type = islist(initial_animal_type) ? pick(initial_animal_type) : initial_animal_type
39+
var/bird_holder_type = bird_type::holder_type
40+
var/obj/item/holder/bird/bird_item = new bird_holder_type(src)
41+
bird_item.sync(new bird_type(bird_item))
42+
else
43+
update_icon()
44+
45+
/obj/structure/hutch/on_update_icon()
46+
. = ..()
47+
if(door_material)
48+
add_overlay(overlay_image(icon, "[icon_state]-doors-[storage?.opened ? "open" : "closed"]", door_material.color, RESET_COLOR))
49+
50+
// Bird subtypes.
51+
/obj/structure/hutch/aviary
52+
name = "aviary"
53+
desc = "A hutch for containing birds like hawks or crows."
54+
icon = 'mods/content/birds/icons/aviary.dmi'
55+
56+
/obj/structure/hutch/aviary/crow
57+
initial_animal_type = /mob/living/simple_animal/passive/bird/crow
58+
59+
/obj/structure/hutch/aviary/pigeon
60+
initial_animal_type = /mob/living/simple_animal/passive/bird/pigeon
61+
62+
/obj/structure/hutch/aviary/hawk
63+
initial_animal_type = /mob/living/simple_animal/passive/bird/hawk
64+
65+
// Rabbits are a kind of bird, right?
66+
/obj/structure/hutch/rabbit
67+
initial_animal_type = list(
68+
/mob/living/simple_animal/passive/rabbit,
69+
/mob/living/simple_animal/passive/rabbit/black,
70+
/mob/living/simple_animal/passive/rabbit/brown
71+
)
718 Bytes
Binary file not shown.

mods/content/birds/icons/crow.dmi

3.37 KB
Binary file not shown.

0 commit comments

Comments
 (0)