Basic gutlunch and goldgrub (#30032)

* Goldgrubs

* Gutlunches, breeding code, goldgrub fixes

* Lints

* Extra define

* Config screwup

* Linters again

* Oops

* Gets rid of extra kangaroo

* Formatting and grammar

Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Signed-off-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com>

---------

Signed-off-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com>
Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
This commit is contained in:
PollardTheDragon
2025-08-25 13:52:42 -04:00
committed by GitHub
parent e6e5f5ce36
commit c6e164a643
22 changed files with 587 additions and 265 deletions
@@ -0,0 +1,54 @@
/// An ore-devouring but easily scared creature
/mob/living/basic/mining/goldgrub
name = "goldgrub"
desc = "A worm that grows fat from eating everything in its sight. Seems to enjoy precious metals and other shiny things, hence the name."
icon_state = "Goldgrub"
icon_living = "Goldgrub"
icon_aggro = "Goldgrub_alert"
icon_dead = "Goldgrub_dead"
icon_gib = "syndicate_gib"
friendly_verb_continuous = "harmlessly rolls into"
friendly_verb_simple = "harmlessly roll into"
speed = 3
maxHealth = 45
health = 45
harm_intent_damage = 5
attack_verb_continuous = "barrels into"
attack_verb_simple = "barrel into"
a_intent = INTENT_HELP
speak_emote = list("screeches")
throw_blocked_message = "sinks in slowly, before being pushed out of "
death_message = "spits up the contents of its stomach before dying!"
status_flags = CANPUSH
contains_xeno_organ = TRUE
surgery_container = /datum/xenobiology_surgery_container/goldgrub
ai_controller = /datum/ai_controller/basic_controller/goldgrub
/// Hungry hungry goldgrubs
var/food_types = list(/obj/item/stack/ore)
/// Does this creature burrow?
var/will_burrow = TRUE
/mob/living/basic/mining/goldgrub/Initialize(mapload)
. = ..()
faction |= "goldgrub"
AddElement(/datum/element/basic_eating, food_types_ = food_types, add_to_contents_ = TRUE)
ai_controller.set_blackboard_key(BB_BASIC_FOODS, typecacheof(food_types))
var/i = rand(1,3)
while(i)
loot += pick(/obj/item/stack/ore/silver, /obj/item/stack/ore/gold, /obj/item/stack/ore/uranium, /obj/item/stack/ore/diamond)
i--
/mob/living/basic/mining/goldgrub/death(gibbed)
barf_contents(gibbed)
return ..()
/mob/living/basic/mining/goldgrub/proc/barf_contents(gibbed)
for(var/obj/item/stack/ore/ore in src)
ore.forceMove(loc)
/mob/living/basic/mining/goldgrub/bullet_act(obj/item/projectile/P)
if(P.armour_penetration_flat + P.armour_penetration_percentage >= 100)
return ..()
visible_message("<span class='danger'>[P.name] was repelled by [name]'s girth!</span>")
@@ -0,0 +1,44 @@
/datum/ai_controller/basic_controller/goldgrub
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
BB_ORE_IGNORE_TYPES = list(/obj/item/stack/ore/iron, /obj/item/stack/ore/glass),
BB_AGGRO_RANGE = 5,
)
ai_movement = /datum/ai_movement/basic_avoidance
idle_behavior = /datum/idle_behavior/idle_random_walk/less_walking
planning_subtrees = list(
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/flee_target,
/datum/ai_planning_subtree/dig_away_from_danger,
/datum/ai_planning_subtree/find_food,
/datum/ai_planning_subtree/mine_walls,
)
/// Only dig away if humans are around
/datum/ai_planning_subtree/dig_away_from_danger
/datum/ai_planning_subtree/dig_away_from_danger/select_behaviors(datum/ai_controller/controller, seconds_per_tick)
var/has_target = controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)
var/mob/living/basic/mining/goldgrub/grub = controller.pawn
// Someone is nearby, its time to escape
if(grub.will_burrow && has_target && ishuman(controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]))
controller.queue_behavior(/datum/ai_behavior/burrow_away)
return SUBTREE_RETURN_FINISH_PLANNING
/datum/ai_behavior/burrow_away
behavior_flags = AI_BEHAVIOR_MOVE_AND_PERFORM | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
/// How long until the grub burrows
var/chase_time = 10 SECONDS
/datum/ai_behavior/burrow_away/perform(seconds_per_tick, datum/ai_controller/controller)
. = ..()
var/mob/living/basic/mining/goldgrub/grub = controller.pawn
grub.addtimer(CALLBACK(src, PROC_REF(burrow), controller.pawn), chase_time)
/// Begin the chase to kill the mob in time
/datum/ai_behavior/burrow_away/proc/burrow(mob/living/pawn)
if(pawn.stat == CONSCIOUS)
pawn.visible_message("<span class='danger'>[pawn] buries into the ground, vanishing from sight!</span>")
qdel(pawn)
@@ -0,0 +1,143 @@
/// Gutlunches, passive mods that devour blood and gibs
/mob/living/basic/mining/gutlunch
name = "gutlunch"
desc = "A scavenger that eats raw meat, often found alongside ash walkers. Produces a thick, medicinally nutritious milk."
icon_state = "gutlunch"
icon_living = "gutlunch"
icon_dead = "gutlunch"
speak_emote = list("warbles", "quavers")
weather_immunities = list("lava","ash")
faction = list("mining", "ashwalker")
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "gently pushes aside"
response_disarm_simple = "gently push aside"
response_harm_continuous = "squishes"
response_harm_simple = "squish"
friendly_verb_continuous = "pinches"
friendly_verb_simple = "pinch"
density = FALSE
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
a_intent = INTENT_HELP
ventcrawler = VENTCRAWLER_ALWAYS
gold_core_spawnable = FRIENDLY_SPAWN
loot = list(/obj/effect/decal/cleanable/blood/gibs)
deathmessage = "is pulped into bugmash."
var/list/food_types = list(
/obj/effect/decal/cleanable/blood/gibs,
/obj/item/organ/internal/eyes,
/obj/item/organ/internal/heart,
/obj/item/organ/internal/lungs,
/obj/item/organ/internal/liver,
/obj/item/organ/internal/kidneys,
/obj/item/organ/internal/appendix
)
var/obj/item/udder/gutlunch/udder
/// can we breed?
var/can_breed = TRUE
/mob/living/basic/mining/gutlunch/Initialize(mapload)
. = ..()
udder = new()
// 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 = food_types.Copy()
AddElement(/datum/element/basic_eating, food_types_ = static_food_types)
AddElement(/datum/element/ai_retaliate)
ai_controller.set_blackboard_key(BB_BASIC_FOODS, typecacheof(static_food_types))
if(can_breed)
add_breeding_component()
/mob/living/basic/mining/gutlunch/Destroy()
QDEL_NULL(udder)
return ..()
/mob/living/basic/mining/gutlunch/regenerate_icons()
..()
if(udder.reagents.total_volume == udder.reagents.maximum_volume)
add_overlay("gl_full")
/mob/living/basic/mining/gutlunch/item_interaction(mob/living/user, obj/item/O, list/modifiers)
if(stat == CONSCIOUS && istype(O, /obj/item/reagent_containers/glass))
udder.milkAnimal(O, user)
regenerate_icons()
return ITEM_INTERACT_COMPLETE
/obj/item/udder/gutlunch
name = "nutrient sac"
/obj/item/udder/gutlunch/generateMilk()
if(prob(60))
reagents.add_reagent("cream", rand(2, 5))
if(prob(45))
reagents.add_reagent("salglu_solution", rand(2, 5))
if(prob(30))
reagents.add_reagent("epinephrine", rand(2, 5))
/mob/living/basic/mining/gutlunch/proc/add_breeding_component()
var/static/list/partner_paths = typecacheof(list(/mob/living/basic/mining/gutlunch))
var/static/list/baby_paths = list(
/mob/living/basic/mining/gutlunch/grublunch = 1,
)
AddComponent(\
/datum/component/breed,\
can_breed_with = partner_paths,\
baby_paths = baby_paths,\
breed_timer = 3 MINUTES,\
)
// Male gutlunch. They're smaller and more colorful!
/mob/living/basic/mining/gutlunch/gubbuck
name = "gubbuck"
gender = MALE
ai_controller = /datum/ai_controller/basic_controller/gutlunch/gubbuck
/mob/living/basic/mining/gutlunch/gubbuck/Initialize(mapload)
. = ..()
add_atom_colour(pick("#E39FBB", "#D97D64", "#CF8C4A"), FIXED_COLOUR_PRIORITY)
resize = 0.85
update_transform()
/// Lady gutlunch. They make the babby.
/mob/living/basic/mining/gutlunch/guthen
name = "guthen"
gender = FEMALE
ai_controller = /datum/ai_controller/basic_controller/gutlunch/guthen
/// Baby gutlunch
/mob/living/basic/mining/gutlunch/grublunch
name = "grublunch"
food_types = list() //They don't eat.
gold_core_spawnable = NO_SPAWN
ai_controller = /datum/ai_controller/basic_controller/gutlunch/gutlunch_baby
var/growth = 0
/mob/living/basic/mining/gutlunch/grublunch/Initialize(mapload)
. = ..()
add_atom_colour("#9E9E9E", FIXED_COLOUR_PRIORITY) // Somewhat hidden
resize = 0.45
update_transform()
/mob/living/basic/mining/gutlunch/grublunch/Life()
..()
growth++
if(growth > 50) //originally used a timer for this but was more problem that it's worth.
growUp()
/mob/living/basic/mining/gutlunch/grublunch/proc/growUp()
var/mob/living/L
if(prob(45))
L = new /mob/living/basic/mining/gutlunch/gubbuck(loc)
else
L = new /mob/living/basic/mining/gutlunch/guthen(loc)
mind?.transfer_to(L)
L.faction = faction.Copy()
L.setDir(dir)
visible_message("<span class='notice'>[src] grows up into [L].</span>")
qdel(src)
@@ -0,0 +1,47 @@
/datum/ai_controller/basic_controller/gutlunch
ai_movement = /datum/ai_movement/basic_avoidance
idle_behavior = /datum/idle_behavior/idle_random_walk
planning_subtrees = list(
/datum/ai_planning_subtree/target_retaliate,
/datum/ai_planning_subtree/flee_target,
/datum/ai_planning_subtree/make_babies,
/datum/ai_planning_subtree/find_food,
/datum/ai_planning_subtree/random_speech/gutlunch,
)
/datum/ai_controller/basic_controller/gutlunch/on_mob_eat()
. = ..()
var/mob/living/basic/mining/gutlunch/gut = pawn
gut.udder.generateMilk()
gut.regenerate_icons()
/datum/ai_controller/basic_controller/gutlunch/gubbuck
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
BB_BABIES_PARTNER_TYPES = list(/mob/living/basic/mining/gutlunch/guthen),
BB_BABIES_CHILD_TYPES = list(/mob/living/basic/mining/gutlunch/grublunch),
BB_MAX_CHILDREN = 5,
)
/datum/ai_controller/basic_controller/gutlunch/guthen
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
BB_BABIES_PARTNER_TYPES = list(/mob/living/basic/mining/gutlunch/gubbuck),
BB_BABIES_CHILD_TYPES = list(/mob/living/basic/mining/gutlunch/grublunch),
BB_MAX_CHILDREN = 5,
)
/datum/ai_controller/basic_controller/gutlunch/gutlunch_baby
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
BB_FIND_MOM_TYPES = list(/mob/living/basic/mining/gutlunch),
)
planning_subtrees = list(
/datum/ai_planning_subtree/target_retaliate,
/datum/ai_planning_subtree/flee_target,
/datum/ai_planning_subtree/look_for_adult,
)
/datum/ai_planning_subtree/random_speech/gutlunch
emote_hear = list("trills.")
emote_see = list("sniffs.", "burps.")