diff --git a/code/datums/supplypacks/hydroponics_vr.dm b/code/datums/supplypacks/hydroponics_vr.dm new file mode 100644 index 0000000000..6d8db96375 --- /dev/null +++ b/code/datums/supplypacks/hydroponics_vr.dm @@ -0,0 +1,6 @@ +/datum/supply_packs/hydro/goat + name = "Birds Crate" + cost = 200 //You're getting 22 birds. Of course it's going to be a lot! + containertype = /obj/structure/largecrate/birds + containername = "Bird crate" + access = access_hydroponics diff --git a/code/game/objects/structures/crates_lockers/largecrate_vr.dm b/code/game/objects/structures/crates_lockers/largecrate_vr.dm new file mode 100644 index 0000000000..f45636db0c --- /dev/null +++ b/code/game/objects/structures/crates_lockers/largecrate_vr.dm @@ -0,0 +1,38 @@ +/obj/structure/largecrate/birds //This is an awful hack, but it's the only way to get multiple mobs spawned in one crate. + name = "Bird crate" + desc = "You hear chirping and cawing inside the crate. It sounds like there are a lot of birds in there..." + +/obj/structure/largecrate/birds/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/crowbar)) + new /obj/item/stack/material/wood(src) + new /mob/living/simple_animal/cat/bird(src) + new /mob/living/simple_animal/cat/bird/fluff/kea(src) + new /mob/living/simple_animal/cat/bird/fluff/eclectus(src) + new /mob/living/simple_animal/cat/bird/fluff/greybird(src) + new /mob/living/simple_animal/cat/bird/fluff/eclectusf(src) + new /mob/living/simple_animal/cat/bird/fluff/blue_caique(src) + new /mob/living/simple_animal/cat/bird/fluff/white_caique(src) + new /mob/living/simple_animal/cat/bird/fluff/green_budgerigar(src) + new /mob/living/simple_animal/cat/bird/fluff/blue_Budgerigar(src) + new /mob/living/simple_animal/cat/bird/fluff/bluegreen_Budgerigar(src) + new /mob/living/simple_animal/cat/bird/fluff/commonblackbird(src) + new /mob/living/simple_animal/cat/bird/fluff/azuretit(src) + new /mob/living/simple_animal/cat/bird/fluff/europeanrobin(src) + new /mob/living/simple_animal/cat/bird/fluff/goldcrest(src) + new /mob/living/simple_animal/cat/bird/fluff/ringneckdove(src) + new /mob/living/simple_animal/cat/bird/fluff/cockatiel(src) + new /mob/living/simple_animal/cat/bird/fluff/white_cockatiel(src) + new /mob/living/simple_animal/cat/bird/fluff/yellowish_cockatiel(src) + new /mob/living/simple_animal/cat/bird/fluff/grey_cockatiel(src) + new /mob/living/simple_animal/cat/bird/fluff/too(src) + new /mob/living/simple_animal/cat/bird/fluff/hooded_too(src) + new /mob/living/simple_animal/cat/bird/fluff/pink_too(src) + var/turf/T = get_turf(src) + for(var/atom/movable/AM in contents) + if(AM.simulated) AM.forceMove(T) + user.visible_message("[user] pries \the [src] open.", \ + "You pry open \the [src].", \ + "You hear splitting wood.") + qdel(src) + else + return attack_hand(user) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/birds_vr.dm b/code/modules/mob/living/simple_animal/friendly/birds_vr.dm new file mode 100644 index 0000000000..4117cf0f4e --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/birds_vr.dm @@ -0,0 +1,326 @@ +//Cat +/mob/living/simple_animal/cat/bird + name = "parrot" + desc = "A domesticated bird. Has a tendency to 'adopt' crewmembers." + isPredator = 1 + icon = 'icons/mob/birds.dmi' + icon_state = "parrot-flap" + item_state = null + icon_living = "parrot-flap" + icon_dead = "parrot-dead" + speak = list("Chirp!","Caw!","Screech!","Squawk!") + speak_emote = list("chirps", "caws") + emote_hear = list("chirps","caws") + emote_see = list("shakes their head", "ruffles their feathers") + holder_type = /obj/item/weapon/holder/bird + +/mob/living/simple_animal/cat/bird/New() + if(!vore_organs.len) + var/datum/belly/B = new /datum/belly(src) + B.immutable = 1 + B.name = "Stomach" + B.inside_flavor = "Slick birdguts. Cute on the outside, slimy on the inside!" + B.human_prey_swallow_time = swallowTime + B.nonhuman_prey_swallow_time = swallowTime + vore_organs[B.name] = B + vore_selected = B.name + + B.emote_lists[DM_HOLD] = list( + "The birdguts knead and churn around you harmlessly.", + "With a loud glorp, some air shifts inside the belly.", + "A thick drop of warm bellyslime drips onto you from above.", + "The bird goes into the air suddenly, causing you to be tossed about.", + "During a moment of relative silence, you can hear the bird breathing.", + "The slimey stomach walls squeeze you lightly, then relax.") + + B.emote_lists[DM_DIGEST] = list( + "The guts knead at you, trying to work you into thick soup.", + "You're ground on by the slimey walls, treated like a mouse.", + "The acrid air is hard to breathe, and stings at your lungs.", + "You can feel the acids coating you, ground in by the slick walls.", + "The bird's stomach churns hungrily over your form, trying to take you.", + "With a loud glorp, the stomach spills more acids onto you.") + ..() + + + +/mob/living/simple_animal/cat/bird/Life() + //MICE! + if((src.loc) && isturf(src.loc)) + if(!stat && !resting && !buckled) + for(var/mob/living/simple_animal/mouse/M in loc) + if(!M.stat) + M.splat() + visible_emote(pick("bites \the [M]!","toys with \the [M].","chomps on \the [M]!")) + movement_target = null + stop_automated_movement = 0 + break + + ..() + + for(var/mob/living/simple_animal/mouse/snack in oview(src,5)) + if(snack.stat < DEAD && prob(15)) + audible_emote(pick("chirps and caws!","squawks fiercely!","eyes [snack] hungrily.")) + break + + if(!stat && !resting && !buckled) + turns_since_scan++ + if (turns_since_scan > 5) + walk_to(src,0) + turns_since_scan = 0 + + if (flee_target) //fleeing takes precendence + handle_flee_target_b() + else + handle_movement_target() + + if(!stat && !resting && !buckled) //SEE A MICRO AND ARE A PREDATOR, EAT IT! + for(var/mob/living/carbon/human/food in oview(src, 5)) + + if(food.size_multiplier <= RESIZE_A_SMALLTINY) + if(prob(10)) + custom_emote(1, pick("eyes [food] hungrily!","licks their lips and turns towards [food] a little!","pants as they imagine [food] being in their belly.")) + break + else + if(prob(5)) + movement_target = food + break + + for(var/mob/living/carbon/human/bellyfiller in oview(1, src)) + if(bellyfiller in src.prey_excludes) + continue + + if(bellyfiller.size_multiplier <= RESIZE_A_SMALLTINY && isPredator) + movement_target = null + custom_emote(1, pick("pecks at [bellyfiller] with their beak.","looms over [bellyfiller] with their beak agape.","sniffs at [bellyfiller], their belly grumbling hungrily.")) + sleep(10) + custom_emote(1, "starts to scoop [bellyfiller] into their beak!") + if(bellyfiller in oview(1, src)) + animal_nom(bellyfiller) + else + bellyfiller << "You just manage to slip away from [src]'s jaws before you can be sent to a fleshy prison!" + break + +/mob/living/simple_animal/cat/bird/proc/handle_flee_target_b() + //see if we should stop fleeing + if (flee_target && !(flee_target.loc in view(src))) + flee_target = null + stop_automated_movement = 0 + + if (flee_target) + if(prob(25)) say("Squawk!") + stop_automated_movement = 1 + walk_away(src, flee_target, 7, 2) + + +//Basic friend AI +/mob/living/simple_animal/cat/bird/fluff + var/mob/living/carbon/human/friend + var/befriend_job = null + +/mob/living/simple_animal/cat/bird/fluff/handle_movement_target() + if (friend) + var/follow_dist = 4 + if (friend.stat >= DEAD || friend.health <= config.health_threshold_softcrit) //danger + follow_dist = 1 + else if (friend.stat || friend.health <= 50) //danger or just sleeping + follow_dist = 2 + var/near_dist = max(follow_dist - 2, 1) + var/current_dist = get_dist(src, friend) + + if (movement_target != friend) + if (current_dist > follow_dist && !istype(movement_target, /mob/living/simple_animal/mouse) && (friend in oview(src))) + //stop existing movement + walk_to(src,0) + turns_since_scan = 0 + + //walk to friend + stop_automated_movement = 1 + movement_target = friend + walk_to(src, movement_target, near_dist, 4) + + //already following and close enough, stop + else if (current_dist <= near_dist) + walk_to(src,0) + movement_target = null + stop_automated_movement = 0 + if (prob(10)) + say("Caw!") + + if (!friend || movement_target != friend) + ..() + +/mob/living/simple_animal/cat/bird/fluff/Life() + ..() + if (stat || !friend) + return + if (get_dist(src, friend) <= 1) + if (friend.stat >= DEAD || friend.health <= config.health_threshold_softcrit) + if (prob((friend.stat < DEAD)? 50 : 15)) + var/verb = pick("Chirps", "Caws", "Squawks") + audible_emote(pick("[verb] in distress.", "[verb] anxiously.")) + else + if (prob(5)) + visible_emote(pick("nuzzles [friend].", + "brushes against [friend].", + "rubs against [friend].", + "chirps.")) + else if (friend.health <= 50) + if (prob(10)) + var/verb = pick("meows", "mews", "mrowls") + audible_emote("[verb] anxiously.") + +/mob/living/simple_animal/cat/bird/fluff/verb/become_friends_b() + set name = "Become Friends" + set category = "IC" + set src in view(1) + + if(!friend) + var/mob/living/carbon/human/H = usr + if(istype(H) && (!befriend_job || H.job == befriend_job)) + friend = usr + . = 1 + else if(usr == friend) + . = 1 //already friends, but show success anyways + + if(.) + set_dir(get_dir(src, friend)) + visible_emote(pick("nuzzles [friend].", + "brushes against [friend].", + "rubs against [friend].", + "chirps.")) + else + usr << "[src] ignores you." + return + +/mob/living/simple_animal/cat/bird/fluff/kea + name = "Kea" + icon_state = "kea-flap" + icon_living = "kea-flap" + icon_dead = "kea-dead" + +/mob/living/simple_animal/cat/bird/fluff/eclectus + name = "Eclectus" + icon_state = "eclectus-flap" + icon_living = "eclectus-flap" + icon_dead = "eclectus-dead" + +/mob/living/simple_animal/cat/bird/fluff/eclectusf + name = "Eclectus" + icon_state = "eclectusf-flap" + icon_living = "eclectusf-flap" + icon_dead = "eclectusf-dead" + +/mob/living/simple_animal/cat/bird/fluff/greybird + name = "Grey Bird" + icon_state = "agrey-flap" + icon_living = "agrey-flap" + icon_dead = "agrey-dead" + +/mob/living/simple_animal/cat/bird/fluff/blue_caique + name = "Blue Caique " + icon_state = "bcaique-flap" + icon_living = "bcaique-flap" + icon_dead = "bcaique-dead" + +/mob/living/simple_animal/cat/bird/fluff/white_caique + name = "White caique" + icon_state = "wcaique-flap" + icon_living = "wcaique-flap" + icon_dead = "wcaique-dead" + +/mob/living/simple_animal/cat/bird/fluff/green_budgerigar + name = "Green Budgerigar" + icon_state = "gbudge-flap" + icon_living = "gbudge-flap" + icon_dead = "gbudge-dead" + +/mob/living/simple_animal/cat/bird/fluff/blue_Budgerigar + name = "Blue Budgerigar" + icon_state = "bbudge-flap" + icon_living = "bbudge-flap" + icon_dead = "bbudge-dead" + +/mob/living/simple_animal/cat/bird/fluff/bluegreen_Budgerigar + name = "Bluegreen Budgerigar" + icon_state = "bgbudge-flap" + icon_living = "bgbudge-flap" + icon_dead = "bgbudge-dead" + +/mob/living/simple_animal/cat/bird/fluff/commonblackbird + name = "Black Bird" + icon_state = "commonblackbird" + icon_living = "commonblackbird" + icon_dead = "commonblackbird-dead" + +/mob/living/simple_animal/cat/bird/fluff/azuretit + name = "Azure Tit" + icon_state = "azuretit" + icon_living = "azuretit" + icon_dead = "azuretit-dead" + +/mob/living/simple_animal/cat/bird/fluff/europeanrobin + name = "European Robin" + icon_state = "europeanrobin" + icon_living = "europeanrobin" + icon_dead = "europeanrobin-dead" + +/mob/living/simple_animal/cat/bird/fluff/goldcrest + name = "Goldcrest" + icon_state = "goldcrest" + icon_living = "goldcrest" + icon_dead = "goldcrest-dead" + +/mob/living/simple_animal/cat/bird/fluff/ringneckdove + name = "Ringneck Dove" + icon_state = "ringneckdove" + icon_living = "ringneckdove" + icon_dead = "ringneckdove-dead" + +/mob/living/simple_animal/cat/bird/fluff/cockatiel + name = "Cockatiel" + icon_state = "tiel-flap" + icon_living = "tiel-flap" + icon_dead = "tiel-dead" + +/mob/living/simple_animal/cat/bird/fluff/white_cockatiel + name = "White Cockatiel" + icon_state = "wtiel-flap" + icon_living = "wtiel-flap" + icon_dead = "wtiel-dead" + +/mob/living/simple_animal/cat/bird/fluff/yellowish_cockatiel + name = "Yellowish Cockatiel" + icon_state = "luttiel-flap" + icon_living = "luttiel-flap" + icon_dead = "luttiel-dead" + +/mob/living/simple_animal/cat/bird/fluff/grey_cockatiel + name = "Grey Cockatiel" + icon_state = "blutiel-flap" + icon_living = "blutiel-flap" + icon_dead = "blutiel-dead" + +/mob/living/simple_animal/cat/bird/fluff/too + name = "Too" + icon_state = "too-flap" + icon_living = "too-flap" + icon_dead = "too-dead" + +/mob/living/simple_animal/cat/bird/fluff/hooded_too + name = "Utoo" + icon_state = "utoo-flap" + icon_living = "utoo-flap" + icon_dead = "utoo-dead" + +/mob/living/simple_animal/cat/bird/fluff/pink_too + name = "Mtoo" + icon_state = "mtoo-flap" + icon_living = "mtoo-flap" + icon_dead = "mtoo-dead" + +/obj/item/weapon/holder/bird + name = "Bird" + desc = "It's a bird!" + icon_state = null + item_icons = null \ No newline at end of file diff --git a/icons/mob/birds.dmi b/icons/mob/birds.dmi new file mode 100644 index 0000000000..582fcc60a8 Binary files /dev/null and b/icons/mob/birds.dmi differ diff --git a/vorestation.dme b/vorestation.dme index d40f551034..2aaf065957 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -220,6 +220,7 @@ #include "code\datums\supplypacks\engineering.dm" #include "code\datums\supplypacks\hospitality.dm" #include "code\datums\supplypacks\hydroponics.dm" +#include "code\datums\supplypacks\hydroponics_vr.dm" #include "code\datums\supplypacks\materials.dm" #include "code\datums\supplypacks\medical.dm" #include "code\datums\supplypacks\misc.dm" @@ -975,6 +976,7 @@ #include "code\game\objects\structures\crates_lockers\crates.dm" #include "code\game\objects\structures\crates_lockers\crates_vr.dm" #include "code\game\objects\structures\crates_lockers\largecrate.dm" +#include "code\game\objects\structures\crates_lockers\largecrate_vr.dm" #include "code\game\objects\structures\crates_lockers\closets\coffin.dm" #include "code\game\objects\structures\crates_lockers\closets\crittercrate.dm" #include "code\game\objects\structures\crates_lockers\closets\egg_vr.dm" @@ -1685,6 +1687,7 @@ #include "code\modules\mob\living\simple_animal\borer\say.dm" #include "code\modules\mob\living\simple_animal\constructs\constructs.dm" #include "code\modules\mob\living\simple_animal\constructs\soulstone.dm" +#include "code\modules\mob\living\simple_animal\friendly\birds_vr.dm" #include "code\modules\mob\living\simple_animal\friendly\cat.dm" #include "code\modules\mob\living\simple_animal\friendly\corgi.dm" #include "code\modules\mob\living\simple_animal\friendly\corgi_vr.dm"