diff --git a/code/game/objects/structures/crates_lockers/crittercrate.dm b/code/game/objects/structures/crates_lockers/crittercrate.dm index b1a8e7d9e08..c22bb8645b9 100644 --- a/code/game/objects/structures/crates_lockers/crittercrate.dm +++ b/code/game/objects/structures/crates_lockers/crittercrate.dm @@ -75,6 +75,10 @@ name = "pig crate" content_mob = /mob/living/basic/pig +/obj/structure/closet/critter/isopod + name = "ahuitz crate" + content_mob = /mob/living/basic/isopod + /obj/structure/closet/critter/goat name = "goat crate" content_mob = /mob/living/basic/goat @@ -90,6 +94,10 @@ /obj/structure/closet/critter/chick/populate_contents() amount = rand(1, 3) +/obj/structure/closet/critter/isopod_smol + name = "deverka crate" + content_mob = /mob/living/basic/isopod/small + /obj/structure/closet/critter/cat name = "cat crate" content_mob = /mob/living/simple_animal/pet/cat diff --git a/code/modules/events/clogged_disposals.dm b/code/modules/events/clogged_disposals.dm index 8116b861d83..668d833d6a9 100644 --- a/code/modules/events/clogged_disposals.dm +++ b/code/modules/events/clogged_disposals.dm @@ -52,6 +52,7 @@ /mob/living/basic/diona_nymph = 5, /mob/living/basic/crab = 5, /mob/living/basic/mouse = 5, + /mob/living/basic/isopod/small = 5, /mob/living/simple_animal/pet/dog/corgi = 5, /mob/living/simple_animal/hostile/retaliate/carp/koi = 5 ) diff --git a/code/modules/events/infestation.dm b/code/modules/events/infestation.dm index e83031b49c9..241986fee3c 100644 --- a/code/modules/events/infestation.dm +++ b/code/modules/events/infestation.dm @@ -1,6 +1,7 @@ #define VERM_MICE 0 #define VERM_LIZARDS 1 #define VERM_SPIDERS 2 +#define VERM_ISOPODS 3 /datum/event/infestation name = "Vermin Infestation" @@ -53,7 +54,7 @@ /datum/event/infestation/proc/spawn_on_turfs(list/turfs) var/list/spawn_types = list() var/max_number - vermin = rand(0, 2) + vermin = rand(0, 3) switch(vermin) if(VERM_MICE) spawn_types = list(/mob/living/basic/mouse/gray, /mob/living/basic/mouse/brown, /mob/living/basic/mouse/white) @@ -67,6 +68,10 @@ spawn_types = list(/mob/living/basic/spiderling) max_number = 3 vermstring = "spiders" + if(VERM_ISOPODS) + spawn_types = list(/mob/living/basic/isopod/small) + max_number = 2 + vermstring = "isopods" var/amount_to_spawn = rand(2, max_number) while(length(turfs) && amount_to_spawn > 0) var/turf/simulated/floor/T = pick_n_take(turfs) @@ -95,3 +100,4 @@ #undef VERM_MICE #undef VERM_LIZARDS #undef VERM_SPIDERS +#undef VERM_ISOPODS diff --git a/code/modules/mob/living/basic/farm_animals/isopod.dm b/code/modules/mob/living/basic/farm_animals/isopod.dm new file mode 100644 index 00000000000..e5417e05341 --- /dev/null +++ b/code/modules/mob/living/basic/farm_animals/isopod.dm @@ -0,0 +1,153 @@ +/mob/living/basic/isopod + name = "ahuitz" + desc = "A large isopod from Kelune that is usually kept as a ranch animal." + icon_state = "ahuitz" + icon_living = "ahuitz" + icon_dead = "ahuitz_dead" + pass_flags = PASSTABLE | PASSMOB + mob_biotypes = MOB_ORGANIC | MOB_BUG + atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) + butcher_results = list(/obj/item/food/meat = 1) + minimum_survivable_temperature = 0 + + maxHealth = 75 + health = 75 + speed = 2 + + // What they sound like + voice_name = "ahuitz" + speak_emote = list("chitters", "chatters", "clicks", "clacks") + + // Special verbs for when someone interacts with a caterpillar + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "shoos" + response_disarm_simple = "shoo" + response_harm_continuous = "kicks" + response_harm_simple = "kicks" + + // Xenobiology and cargo are the only ways to get the caterpillar. + gold_core_spawnable = FRIENDLY_SPAWN + + melee_attack_cooldown_min = 1.5 SECONDS + melee_attack_cooldown_max = 2.5 SECONDS + melee_damage_lower = 5 + melee_damage_upper = 10 + attack_verb_continuous = "bites" + attack_verb_simple = "bite" + attack_sound = 'sound/weapons/bite.ogg' + + ai_controller = /datum/ai_controller/basic_controller/isopod + + /// List of stuff that we want to eat + var/static/list/edibles = list( + /obj/item/food, + ) + /// Max the bug can eat + var/max_nutrition = 700 + +/mob/living/basic/isopod/Initialize(mapload) + . = ..() + real_name = name + AddElement(/datum/element/wears_collar) + AddElement(/datum/element/ai_retaliate) + AddElement(/datum/element/basic_eating, heal_amt_ = 2, food_types_ = edibles) + ai_controller.set_blackboard_key(BB_BASIC_FOODS, typecacheof(edibles)) + RegisterSignal(src, COMSIG_MOB_PRE_EAT, PROC_REF(check_full)) + RegisterSignal(src, COMSIG_MOB_ATE, PROC_REF(consume)) + +/mob/living/basic/isopod/examine_more(mob/user) + . = ..() + . += "Ahuitz are a species incredibly similar to earth isopods - being crustaceans that are commonly found in Kelune’s oceans. Well suited for cold environments and requiring little \ + food these creatures are often kept as pets or for aquatic ranching. They have a long history of being pseudo selectively bred. With those intended to be pets often being bred for \ + bright colors or smaller sizes. They are commonly served in a stew alongside whatever could be foraged, farmed, fished or hunted for. The Ahuitz have little meat relative to their weight \ + but are very easy to fish up due to their slow speed and inquisitive nature." + +/mob/living/basic/isopod/proc/check_full(datum/source, obj/item/potential_food) + SIGNAL_HANDLER // COMSIG_MOB_PRE_EAT + if(nutrition >= max_nutrition) // Prevents griefing by overeating food items without evolving. + to_chat(src, SPAN_WARNING("You're too full to consume this!")) + return COMSIG_MOB_TERMINATE_EAT + +/mob/living/basic/isopod/proc/consume(datum/source, obj/item/potential_food) + SIGNAL_HANDLER // COMSIG_MOB_ATE + var/food_reagents = potential_food.reagents.get_reagent_amount("nutriment") + potential_food.reagents.get_reagent_amount("plantmatter") + potential_food.reagents.get_reagent_amount("protein") + potential_food.reagents.get_reagent_amount("vitamin") + if(food_reagents < 1) + adjust_nutrition(2) + else + adjust_nutrition(food_reagents * 2) + butcher_results = list(/obj/item/food/meat = (MODULUS(nutrition, 100))) + +/mob/living/basic/isopod/small + name = "deverka" + desc = "A small isopod from Kelune that is usually kept as a pet." + icon_state = "deverka" + icon_living = "deverka" + icon_dead = "deverka_dead" + maxHealth = 30 + health = 30 + melee_damage_lower = 1 + melee_damage_upper = 5 + mob_size = MOB_SIZE_SMALL + ventcrawler = VENTCRAWLER_ALWAYS + holder_type = /obj/item/holder/isopod_smol + ai_controller = /datum/ai_controller/basic_controller/isopod/small + max_nutrition = 400 + +/mob/living/basic/isopod/small/attack_hand(mob/living/carbon/human/M) + // Let people pick the little buggers up. + if(M.a_intent != INTENT_HELP) + return ..() + if(isrobot(M)) + M.visible_message(SPAN_NOTICE("[M] playfully boops [src]!"), SPAN_NOTICE("You playfully boop [src]!")) + else + get_scooped(M) + +/mob/living/basic/isopod/small/consume(datum/source, obj/item/potential_food) + var/food_reagents = potential_food.reagents.get_reagent_amount("nutriment") + potential_food.reagents.get_reagent_amount("plantmatter") + potential_food.reagents.get_reagent_amount("protein") + potential_food.reagents.get_reagent_amount("vitamin") + if(food_reagents < 1) + adjust_nutrition(2) + else + adjust_nutrition(food_reagents * 2) + +/datum/ai_controller/basic_controller/isopod + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_EAT_FOOD_COOLDOWN = 1 MINUTES, // Isopod wants to eat, but not too fast. + BB_SEARCH_RANGE = 3, + ) + + ai_traits = AI_FLAG_STOP_MOVING_WHEN_PULLED | AI_FLAG_PAUSE_DURING_DO_AFTER + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/random_speech/isopod, + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, + /datum/ai_planning_subtree/flee_target, + /datum/ai_planning_subtree/find_food/isopod, + ) + +/datum/ai_controller/basic_controller/isopod/small + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_EAT_FOOD_COOLDOWN = 4 MINUTES, // Smol isopod wants to eat, but not fast at all. + BB_SEARCH_RANGE = 3, + ) + +/datum/ai_planning_subtree/find_food/isopod + +/datum/ai_planning_subtree/find_food/isopod/select_behaviors(datum/ai_controller/controller, seconds_per_tick) + var/mob/living/basic/isopod/pod = controller.pawn + if(pod.nutrition >= pod.max_nutrition) + // Put eating on cooldown so it doesn't keep trying to eat. + var/food_cooldown = controller.blackboard[BB_EAT_FOOD_COOLDOWN] || EAT_FOOD_COOLDOWN + controller.set_blackboard_key(BB_NEXT_FOOD_EAT, world.time + food_cooldown) + return SUBTREE_RETURN_FINISH_PLANNING + return ..() + +/datum/ai_planning_subtree/random_speech/isopod + speech_chance = 2 + sound = list('sound/creatures/chitter.ogg', 'sound/effects/kidanclack.ogg', 'sound/effects/kidanclack2.ogg') + emote_hear = list("clicks.", "chitters.", "chatters.", "clacks.") + emote_see = list("clicks.", "chitters.", "chatters.", "clacks.") + diff --git a/code/modules/mob/living/carbon/human/species/kidan.dm b/code/modules/mob/living/carbon/human/species/kidan.dm index d40808ab3ba..8429abff2e4 100644 --- a/code/modules/mob/living/carbon/human/species/kidan.dm +++ b/code/modules/mob/living/carbon/human/species/kidan.dm @@ -43,7 +43,7 @@ "lantern" = /obj/item/organ/internal/lantern ) - allowed_consumed_mobs = list(/mob/living/basic/diona_nymph) + allowed_consumed_mobs = list(/mob/living/basic/diona_nymph, /mob/living/basic/isopod/small) suicide_messages = list( "is attempting to bite their antenna off!", diff --git a/code/modules/mob/living/carbon/human/species/tajaran.dm b/code/modules/mob/living/carbon/human/species/tajaran.dm index 676c838e209..c1cd7e8b5c8 100644 --- a/code/modules/mob/living/carbon/human/species/tajaran.dm +++ b/code/modules/mob/living/carbon/human/species/tajaran.dm @@ -51,6 +51,7 @@ /mob/living/basic/butterfly, /mob/living/simple_animal/parrot, /mob/living/basic/bee, + /mob/living/basic/isopod/small, ) suicide_messages = list( diff --git a/code/modules/mob/living/carbon/human/species/unathi.dm b/code/modules/mob/living/carbon/human/species/unathi.dm index fd8ec68b51d..b12da08974e 100644 --- a/code/modules/mob/living/carbon/human/species/unathi.dm +++ b/code/modules/mob/living/carbon/human/species/unathi.dm @@ -57,6 +57,7 @@ /mob/living/basic/butterfly, /mob/living/simple_animal/parrot, /mob/living/basic/bee, + /mob/living/basic/isopod/small, ) 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 f08a39deec7..f34fa721293 100644 --- a/code/modules/mob/living/carbon/human/species/vulpkanin.dm +++ b/code/modules/mob/living/carbon/human/species/vulpkanin.dm @@ -47,6 +47,7 @@ /mob/living/basic/butterfly, /mob/living/simple_animal/parrot, /mob/living/basic/bee, + /mob/living/basic/isopod/small, ) suicide_messages = list( diff --git a/code/modules/mob/living/silicon/ai/ai_mob.dm b/code/modules/mob/living/silicon/ai/ai_mob.dm index 62888dd85d2..a6d19861310 100644 --- a/code/modules/mob/living/silicon/ai/ai_mob.dm +++ b/code/modules/mob/living/silicon/ai/ai_mob.dm @@ -1160,6 +1160,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list( "Cockroach", "Nian Caterpillar", "Slime", + "Isopod", "Mecha-Cat", "Mecha-Fairy", "Mecha-Fox", @@ -1228,6 +1229,8 @@ GLOBAL_LIST_INIT(ai_verbs_default, list( holo_icon = getHologramIcon(icon('icons/mob/monkey.dmi', "mothroach"), FALSE, hologram_color) if("Slime") holo_icon = getHologramIcon(icon('icons/mob/slimes.dmi', "grey baby slime"), FALSE, hologram_color) + if("Isopod") + holo_icon = getHologramIcon(icon('icons/mob/animal.dmi', "ahuitz"), FALSE, hologram_color) if("Mecha-Cat") holo_icon = getHologramIcon(icon('icons/mob/pai.dmi', "cat"), FALSE, hologram_color) if("Mecha-Fairy") diff --git a/code/modules/mob/mob_holder.dm b/code/modules/mob/mob_holder.dm index 199044af1bc..9ceb6119fd4 100644 --- a/code/modules/mob/mob_holder.dm +++ b/code/modules/mob/mob_holder.dm @@ -100,6 +100,13 @@ icon_state = "mothroach" slot_flags = ITEM_SLOT_HEAD +/obj/item/holder/isopod_smol + name = "deverka" + desc = "A tiny isopod that wriggles and chitters!" + icon_state = "deverka" + w_class = WEIGHT_CLASS_SMALL + slot_flags = null + /obj/item/holder/drone/emagged icon_state = "drone-emagged" diff --git a/code/modules/supply/supply_packs/pack_organic.dm b/code/modules/supply/supply_packs/pack_organic.dm index 2fb5053b43e..b50ebc0f136 100644 --- a/code/modules/supply/supply_packs/pack_organic.dm +++ b/code/modules/supply/supply_packs/pack_organic.dm @@ -243,6 +243,15 @@ containertype = /obj/structure/closet/critter/pig containername = "pig crate" +/datum/supply_packs/organic/isopod + name = "Ahuitz Crate" + cost = 100 + contains_special = list( + "Ahuitz" + ) + containertype = /obj/structure/closet/critter/cow + containername = "ahuitz crate" + /datum/supply_packs/organic/goat name = "Goat Crate" cost = 100 @@ -291,6 +300,15 @@ /obj/item/toy/cattoy) containername = "cat crate" +/datum/supply_packs/organic/isopod_smol + name = "Deverka Crate" + cost = 300 + contains_special = list( + "Deverka" + ) + containertype = /obj/structure/closet/critter/isopod_smol + containername = "deverka crate" + /datum/supply_packs/organic/pug name = "Pug Crate" cost = 300 diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi index 3426d93c47d..d5af2ac9594 100644 Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi index db57fc42dc4..7fbff6835e2 100644 Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi index bf876a4b9d2..9938e22f30e 100644 Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ diff --git a/icons/obj/objects.dmi b/icons/obj/objects.dmi index c2be59342c5..b477b21658a 100644 Binary files a/icons/obj/objects.dmi and b/icons/obj/objects.dmi differ diff --git a/paradise.dme b/paradise.dme index 7d13ec8ef3f..e06738905c0 100644 --- a/paradise.dme +++ b/paradise.dme @@ -2633,6 +2633,7 @@ #include "code\modules\mob\living\basic\farm_animals\deer_ai.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\isopod.dm" #include "code\modules\mob\living\basic\farm_animals\pig.dm" #include "code\modules\mob\living\basic\farm_animals\seal.dm" #include "code\modules\mob\living\basic\farm_animals\turkey.dm"