diff --git a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm index c24434866ee..b7f4dd7e8ba 100644 --- a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm +++ b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm @@ -249,7 +249,7 @@ dir = 1 }, /obj/structure/stone_tile, -/mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck, +/mob/living/basic/mining/gutlunch/gubbuck, /turf/simulated/floor/indestructible/boss, /area/ruin/unpowered/ash_walkers) "aM" = ( @@ -378,7 +378,7 @@ /obj/structure/stone_tile{ dir = 4 }, -/mob/living/simple_animal/hostile/asteroid/gutlunch/guthen, +/mob/living/basic/mining/gutlunch/guthen, /turf/simulated/floor/indestructible/boss, /area/ruin/unpowered/ash_walkers) "bd" = ( diff --git a/_maps/map_files/RandomRuins/SpaceRuins/abandonedzoo.dmm b/_maps/map_files/RandomRuins/SpaceRuins/abandonedzoo.dmm index 9fb1e246a47..9b351e76dc8 100644 --- a/_maps/map_files/RandomRuins/SpaceRuins/abandonedzoo.dmm +++ b/_maps/map_files/RandomRuins/SpaceRuins/abandonedzoo.dmm @@ -98,7 +98,7 @@ /turf/simulated/floor/grass, /area/ruin/space/unpowered) "ap" = ( -/mob/living/simple_animal/hostile/asteroid/goldgrub{ +/mob/living/basic/mining/goldgrub{ will_burrow = 0 }, /turf/simulated/floor/plating/asteroid/airless, diff --git a/code/__DEFINES/ai/blackboard_defines.dm b/code/__DEFINES/ai/blackboard_defines.dm index 9ed9dc200e0..f41b38f7374 100644 --- a/code/__DEFINES/ai/blackboard_defines.dm +++ b/code/__DEFINES/ai/blackboard_defines.dm @@ -14,6 +14,10 @@ #define BB_BASIC_MOB_FLEE_TARGET_HIDING_LOCATION "BB_BASIC_FLEE_TARGET_HIDING_LOCATION" /// Key defining the targeting strategy for things to flee from #define BB_FLEE_TARGETING_STRATEGY "BB_FLEE_TARGETING_STRATEGY" +/// are we ready to breed? +#define BB_BREED_READY "BB_breed_ready" +/// maximum kids we can have +#define BB_MAX_CHILDREN "BB_max_children" /// Key defining how far we attempt to get away from something we're fleeing from #define BB_BASIC_MOB_FLEE_DISTANCE "BB_BASIC_FLEE_DISTANCE" #define DEFAULT_BASIC_FLEE_DISTANCE 9 @@ -59,11 +63,31 @@ /// Key that holds the cooldown for our hunting subtree #define BB_HUNTING_COOLDOWN(type) "BB_HUNTING_COOLDOWN_[type]" + +// Finding adult mob +/// key holds the adult we found +#define BB_FOUND_MOM "BB_found_mom" +/// list of types of mobs we will look for +#define BB_FIND_MOM_TYPES "BB_find_mom_types" +/// list of types of mobs we must ignore +#define BB_IGNORE_MOM_TYPES "BB_ignore_mom_types" + +// Baby-making blackboard +/// Types of animal we can make babies with. +#define BB_BABIES_PARTNER_TYPES "BB_babies_partner" +/// Types of animal that we make as a baby. +#define BB_BABIES_CHILD_TYPES "BB_babies_child" +/// Current partner target +#define BB_BABIES_TARGET "BB_babies_target" +/// Timeout for finding partners when theres too many of us in 1 location +#define BB_PARTNER_SEARCH_TIMEOUT "BB_partner_search_timeout" + /// Chance to randomly acquire a new target #define BB_RANDOM_AGGRO_CHANCE "BB_random_aggro_chance" /// Chance to randomly drop all of our targets #define BB_RANDOM_DEAGGRO_CHANCE "BB_random_deaggro_chance" + // Food and eating /// list of foods this mob likes diff --git a/code/__HELPERS/trait_helpers.dm b/code/__HELPERS/trait_helpers.dm index b30e1f20ed0..36724ccf80b 100644 --- a/code/__HELPERS/trait_helpers.dm +++ b/code/__HELPERS/trait_helpers.dm @@ -193,6 +193,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_RSG_IMMUNE "rsgimmune" //prevents RSG syringes from piercing your clothing #define TRAIT_DRASK_SUPERCOOL "drask_supercool" +/// trait determines if this mob can breed given by /datum/component/breeding +#define TRAIT_MOB_BREEDER "mob_breeder" + #define TRAIT_NO_BONES "no_bones" #define TRAIT_STURDY_LIMBS "sturdy_limbs" #define TRAIT_BURN_WOUND_IMMUNE "burn_immune" diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index 4fbe48bfaf5..7b4a3e3e03b 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -57,6 +57,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NO_BONES" = TRAIT_NO_BONES, "TRAIT_STURDY_LIMBS" = TRAIT_STURDY_LIMBS, + "TRAIT_MOB_BREEDER" = TRAIT_MOB_BREEDER, "TRAIT_COMIC_SANS" = TRAIT_COMIC_SANS, "TRAIT_CHAV" = TRAIT_CHAV, diff --git a/code/datums/ai/basic_mobs/basic_subtrees/find_parent.dm b/code/datums/ai/basic_mobs/basic_subtrees/find_parent.dm new file mode 100644 index 00000000000..ff794c1589f --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/find_parent.dm @@ -0,0 +1,51 @@ +/datum/ai_planning_subtree/look_for_adult + /// how far we must be from the mom + var/minimum_distance = 1 + +/datum/ai_planning_subtree/look_for_adult/select_behaviors(datum/ai_controller/controller, seconds_per_tick) + . = ..() + var/mob/target = controller.blackboard[BB_FOUND_MOM] + var/mob/baby = controller.pawn + + if(QDELETED(target)) + controller.queue_behavior(/datum/ai_behavior/find_mom, BB_FIND_MOM_TYPES, BB_IGNORE_MOM_TYPES, BB_FOUND_MOM) + return + + if(get_dist(target, baby) > minimum_distance) + controller.queue_behavior(/datum/ai_behavior/travel_towards/stop_on_arrival, BB_FOUND_MOM) + return SUBTREE_RETURN_FINISH_PLANNING + + if(!SPT_PROB(15, seconds_per_tick)) + return + + if(target.stat == DEAD) + controller.queue_behavior(/datum/ai_behavior/perform_emote, "cries for their parent!") + else + controller.queue_behavior(/datum/ai_behavior/perform_emote, "dances around their parent!") + + return SUBTREE_RETURN_FINISH_PLANNING + +/datum/ai_behavior/find_mom + /// range to look for the mom + var/look_range = 7 + +/datum/ai_behavior/find_mom/perform(seconds_per_tick, datum/ai_controller/controller, mom_key, ignore_mom_key, found_mom) + var/mob/living_pawn = controller.pawn + var/list/mom_types = controller.blackboard[mom_key] + var/list/all_moms = list() + var/list/ignore_types = controller.blackboard[ignore_mom_key] + + if(!length(mom_types)) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + + for(var/mob/mother in oview(look_range, living_pawn)) + if(!is_type_in_list(mother, mom_types)) + continue + if(is_type_in_list(mother, ignore_types)) // so the not permanent baby and the permanent baby subtype don't follow each other + continue + all_moms += mother + + if(length(all_moms)) + controller.set_blackboard_key(found_mom, pick(all_moms)) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED diff --git a/code/datums/ai/basic_mobs/basic_subtrees/make_babies.dm b/code/datums/ai/basic_mobs/basic_subtrees/make_babies.dm new file mode 100644 index 00000000000..cd1f7e9d465 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/make_babies.dm @@ -0,0 +1,97 @@ +/** + * Reproduce with a similar mob. + */ +/datum/ai_planning_subtree/make_babies + operational_datums = list(/datum/component/breed) + /// chance to make babies + var/chance = 5 + /// make babies behavior we will use + var/datum/ai_behavior/reproduce_behavior = /datum/ai_behavior/make_babies + +/datum/ai_planning_subtree/make_babies/select_behaviors(datum/ai_controller/controller, seconds_per_tick) + . = ..() + + if(!SPT_PROB(chance, seconds_per_tick) || controller.blackboard[BB_PARTNER_SEARCH_TIMEOUT] >= world.time) + return + + if(controller.blackboard_key_exists(BB_BABIES_TARGET)) + controller.queue_behavior(reproduce_behavior, BB_BABIES_TARGET, BB_BABIES_CHILD_TYPES) + return SUBTREE_RETURN_FINISH_PLANNING + + if(controller.pawn.gender == FEMALE || !controller.blackboard[BB_BREED_READY]) + return + + if(!controller.blackboard[BB_BABIES_PARTNER_TYPES] || !controller.blackboard[BB_BABIES_CHILD_TYPES]) + return + + // Find target + controller.queue_behavior(/datum/ai_behavior/find_partner, BB_BABIES_TARGET, BB_BABIES_PARTNER_TYPES, BB_BABIES_CHILD_TYPES) + +#define FIND_PARTNER_COOLDOWN 1 MINUTES + +/** + * Find a compatible, living partner, if we're also alone. + */ +/datum/ai_behavior/find_partner + action_cooldown = 5 SECONDS + /// Range to look. + var/range = 7 + /// Maximum number of nearby pop + var/max_nearby_pop = 3 + +/datum/ai_behavior/find_partner/perform(seconds_per_tick, datum/ai_controller/controller, target_key, partner_types_key, child_types_key) + var/maximum_pop = controller.blackboard[BB_MAX_CHILDREN] || max_nearby_pop + var/mob/pawn_mob = controller.pawn + var/list/similar_species_types = controller.blackboard[partner_types_key] + controller.blackboard[child_types_key] + var/mob/living/living_pawn = controller.pawn + var/list/possible_partners = list() + + var/nearby_pop = 0 + for(var/mob/living/other in oview(range, pawn_mob)) + if(!pawn_mob.faction_check_mob(other)) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + + if(!is_type_in_list(other, similar_species_types)) + continue + + if(++nearby_pop >= maximum_pop) + controller.set_blackboard_key(BB_PARTNER_SEARCH_TIMEOUT, world.time + FIND_PARTNER_COOLDOWN) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + + if(other.stat != CONSCIOUS) // Check if it's conscious FIRST. + continue + + if(other.gender != living_pawn.gender) + possible_partners += other + + if(!length(possible_partners)) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + + controller.set_blackboard_key(target_key, pick(possible_partners)) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + +/** + * Reproduce. + */ +/datum/ai_behavior/make_babies + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH + +/datum/ai_behavior/make_babies/setup(datum/ai_controller/controller, target_key, child_types_key) + . = ..() + var/atom/target = controller.blackboard[target_key] + if(!target) + return FALSE + set_movement_target(controller, target) + +/datum/ai_behavior/make_babies/perform(seconds_per_tick, datum/ai_controller/controller, target_key, child_types_key) + var/mob/target = controller.blackboard[target_key] + if(QDELETED(target) || target.stat != CONSCIOUS) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + controller.ai_interact(target = target, intent = INTENT_HELP) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + +/datum/ai_behavior/make_babies/finish_action(datum/ai_controller/controller, succeeded, target_key) + . = ..() + controller.clear_blackboard_key(target_key) + +#undef FIND_PARTNER_COOLDOWN diff --git a/code/datums/ai/basic_mobs/basic_subtrees/mine_walls.dm b/code/datums/ai/basic_mobs/basic_subtrees/mine_walls.dm index 0744d33acea..82cd3f47e5b 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/mine_walls.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/mine_walls.dm @@ -29,3 +29,27 @@ if(!test_turf.is_blocked_turf(source_atom = source)) return TRUE return FALSE + + +/datum/ai_planning_subtree/mine_walls + var/find_wall_behavior = /datum/ai_behavior/find_mineral_wall + +/datum/ai_planning_subtree/mine_walls/select_behaviors(datum/ai_controller/controller, seconds_per_tick) + if(controller.blackboard_key_exists(BB_TARGET_MINERAL_WALL)) + controller.queue_behavior(/datum/ai_behavior/interact_with_target/mine_wall, BB_TARGET_MINERAL_WALL) + return SUBTREE_RETURN_FINISH_PLANNING + controller.queue_behavior(find_wall_behavior, BB_TARGET_MINERAL_WALL) + +/datum/ai_behavior/interact_with_target/mine_wall + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + action_cooldown = 15 SECONDS + +/datum/ai_behavior/interact_with_target/mine_wall/perform(seconds_per_tick, datum/ai_controller/controller, target_key) + var/mob/living/basic/living_pawn = controller.pawn + var/turf/simulated/mineral/target = controller.blackboard[target_key] + if(!controller.ai_interact(target = target)) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + if(istype(target) && istype(target.ore, /datum/ore/gibtonite)) + living_pawn.manual_emote("sighs...") // accept whats about to happen to us + + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/components/breeding.dm b/code/datums/components/breeding.dm new file mode 100644 index 00000000000..a585f542121 --- /dev/null +++ b/code/datums/components/breeding.dm @@ -0,0 +1,73 @@ +/* + * A component to allow us to breed + */ +/datum/component/breed + /// additional mobs we can breed with + var/list/can_breed_with + /// weighted list of the possible baby types + var/list/baby_paths + /// time to wait after breeding + var/breed_timer + /// AI key we set when we're ready to breed + var/breed_key = BB_BREED_READY + /// are we ready to breed? + var/ready_to_breed = TRUE + /// callback after we give birth to the child + var/datum/callback/post_birth + +/datum/component/breed/Initialize(list/can_breed_with = list(), breed_timer = 40 SECONDS, baby_paths = list(), post_birth) + if(!isliving(parent)) + return COMPONENT_INCOMPATIBLE + + if(ishuman(parent)) // sin detected + return COMPONENT_INCOMPATIBLE + + if(!length(baby_paths)) + stack_trace("attempted to add a breeding component with invalid baby paths!") + return + + src.can_breed_with = can_breed_with + src.breed_timer = breed_timer + src.baby_paths = baby_paths + src.post_birth = post_birth + + ADD_TRAIT(parent, TRAIT_SUBTREE_REQUIRED_OPERATIONAL_DATUM, type) + +/datum/component/breed/RegisterWithParent() + RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(breed_with_partner)) + ADD_TRAIT(parent, TRAIT_MOB_BREEDER, ref(src)) + var/mob/living/parent_mob = parent + parent_mob.ai_controller?.set_blackboard_key(breed_key, TRUE) + +/datum/component/breed/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET) + REMOVE_TRAIT(parent, TRAIT_MOB_BREEDER, ref(src)) + post_birth = null + + +/datum/component/breed/proc/breed_with_partner(mob/living/source, mob/living/target) + SIGNAL_HANDLER // COMSIG_HOSTILE_PRE_ATTACKINGTARGET + + if(!is_type_in_typecache(target, can_breed_with)) + return + + if(!HAS_TRAIT(target, TRAIT_MOB_BREEDER) || target.gender == source.gender) + return + + if(!ready_to_breed) + return COMPONENT_HOSTILE_NO_ATTACK + + var/turf/delivery_destination = get_turf(source) + var/chosen_baby_path = pickweight(baby_paths) + var/atom/baby = new chosen_baby_path(delivery_destination) + new /obj/effect/temp_visual/heart(delivery_destination) + toggle_status(source) + + addtimer(CALLBACK(src, PROC_REF(toggle_status), source), breed_timer) + post_birth?.Invoke(baby, target) + return COMPONENT_HOSTILE_NO_ATTACK + +/datum/component/breed/proc/toggle_status(mob/living/source) + ready_to_breed = !ready_to_breed + source.ai_controller?.set_blackboard_key(BB_BREED_READY, ready_to_breed) + diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index 63371c92f82..44d19b6f38b 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -667,14 +667,14 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/newplayer_start) //Without this you sp . = ..() /obj/effect/landmark/mob_spawner/goldgrub - mobtype = /mob/living/simple_animal/hostile/asteroid/goldgrub + mobtype = /mob/living/basic/mining/goldgrub /obj/effect/landmark/mob_spawner/gutlunch - mobtype = /mob/living/simple_animal/hostile/asteroid/gutlunch + mobtype = /mob/living/basic/mining/gutlunch /obj/effect/landmark/mob_spawner/gutlunch/Initialize(mapload) if(prob(5)) - mobtype = /mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck + mobtype = /mob/living/basic/mining/gutlunch/gubbuck . = ..() /obj/effect/landmark/mob_spawner/abandoned_minebot diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index d7d151a4dd0..c65afc2bfba 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -307,7 +307,7 @@ return to_transfer /obj/item/stack/proc/split(mob/user, amount) - var/obj/item/stack/material = new type(loc, amount) + var/obj/item/stack/material = new type(loc, amount, FALSE) material.copy_evidences(src) if(isliving(user)) add_fingerprint(user) diff --git a/code/game/objects/structures/monster_spawner.dm b/code/game/objects/structures/monster_spawner.dm index f3ced161b44..0a6897c2139 100644 --- a/code/game/objects/structures/monster_spawner.dm +++ b/code/game/objects/structures/monster_spawner.dm @@ -53,13 +53,13 @@ max_mobs = 3 icon = 'icons/mob/nest.dmi' spawn_text = "crawls out of" - mob_types = list(/mob/living/simple_animal/hostile/asteroid/goldgrub, /mob/living/simple_animal/hostile/asteroid/goliath, /mob/living/basic/mining/hivelord, /mob/living/basic/mining/basilisk) + mob_types = list(/mob/living/basic/mining/goldgrub, /mob/living/simple_animal/hostile/asteroid/goliath, /mob/living/basic/mining/hivelord, /mob/living/basic/mining/basilisk) faction = list("mining") /obj/structure/spawner/mining/goldgrub name = "goldgrub den" desc = "A den housing a nest of goldgrubs, annoying but arguably much better than anything else you'll find in a nest." - mob_types = list(/mob/living/simple_animal/hostile/asteroid/goldgrub) + mob_types = list(/mob/living/basic/mining/goldgrub) /obj/structure/spawner/mining/goliath name = "goliath den" diff --git a/code/game/objects/structures/nest.dm b/code/game/objects/structures/nest.dm index 891d78046b5..46fdcd4a2ec 100644 --- a/code/game/objects/structures/nest.dm +++ b/code/game/objects/structures/nest.dm @@ -71,7 +71,7 @@ visible_message("\A [spawned_mob.name] crawls out of \the [name]!") /obj/structure/nest/lavaland - spawn_mob_options = list(/mob/living/simple_animal/hostile/asteroid/goliath/beast, /mob/living/simple_animal/hostile/asteroid/goldgrub) + spawn_mob_options = list(/mob/living/simple_animal/hostile/asteroid/goliath/beast, /mob/living/basic/mining/goldgrub) /obj/structure/nest/carppuppy spawn_mob_options = list(/mob/living/basic/carp, /mob/living/simple_animal/pet/dog/corgi/puppy/void) diff --git a/code/modules/mining/lavaland/loot/colossus_loot.dm b/code/modules/mining/lavaland/loot/colossus_loot.dm index 2088bb6636f..d47a2e511a2 100644 --- a/code/modules/mining/lavaland/loot/colossus_loot.dm +++ b/code/modules/mining/lavaland/loot/colossus_loot.dm @@ -84,7 +84,7 @@ if("lavaland")//Free cult metal, I guess. NewTerrainFloors = /turf/simulated/floor/plating/false_asteroid NewTerrainWalls = /turf/simulated/wall/cult - NewFlora = list(/mob/living/simple_animal/hostile/asteroid/goldgrub) + NewFlora = list(/mob/living/basic/mining/goldgrub) florachance = 1 if("winter") //Snow terrain is slow to move in and cold! Get the assistants to shovel your driveway. NewTerrainFloors = /turf/simulated/floor/snow // Needs to be updated after turf update diff --git a/code/modules/mob/living/basic/mining/goldgrub/goldgrub.dm b/code/modules/mob/living/basic/mining/goldgrub/goldgrub.dm new file mode 100644 index 00000000000..a9528cb7be1 --- /dev/null +++ b/code/modules/mob/living/basic/mining/goldgrub/goldgrub.dm @@ -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("[P.name] was repelled by [name]'s girth!") diff --git a/code/modules/mob/living/basic/mining/goldgrub/goldgrub_ai.dm b/code/modules/mob/living/basic/mining/goldgrub/goldgrub_ai.dm new file mode 100644 index 00000000000..804e9d0e5a4 --- /dev/null +++ b/code/modules/mob/living/basic/mining/goldgrub/goldgrub_ai.dm @@ -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("[pawn] buries into the ground, vanishing from sight!") + qdel(pawn) diff --git a/code/modules/mob/living/basic/mining/gutlunch.dm b/code/modules/mob/living/basic/mining/gutlunch.dm new file mode 100644 index 00000000000..40aeec5e249 --- /dev/null +++ b/code/modules/mob/living/basic/mining/gutlunch.dm @@ -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("[src] grows up into [L].") + qdel(src) diff --git a/code/modules/mob/living/basic/mining/gutlunch_ai.dm b/code/modules/mob/living/basic/mining/gutlunch_ai.dm new file mode 100644 index 00000000000..581174a249f --- /dev/null +++ b/code/modules/mob/living/basic/mining/gutlunch_ai.dm @@ -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.") diff --git a/code/modules/mob/living/carbon/human/species/unathi.dm b/code/modules/mob/living/carbon/human/species/unathi.dm index a86247eb1ad..04e20ea2042 100644 --- a/code/modules/mob/living/carbon/human/species/unathi.dm +++ b/code/modules/mob/living/carbon/human/species/unathi.dm @@ -143,11 +143,13 @@ fire.Remove(H) var/datum/action/innate/unathi_ignite/ash_walker/fire = new() fire.Grant(H) + H.faction |= "ashwalker" /datum/species/unathi/ashwalker/on_species_loss(mob/living/carbon/human/H) ..() for(var/datum/action/innate/unathi_ignite/ash_walker/fire in H.actions) fire.Remove(H) + H.faction -= "ashwalker" /datum/species/unathi/ashwalker/movement_delay(mob/living/carbon/human/H) . = ..() diff --git a/code/modules/mob/living/simple_animal/hostile/mining/goldgrub.dm b/code/modules/mob/living/simple_animal/hostile/mining/goldgrub.dm deleted file mode 100644 index a57ad115237..00000000000 --- a/code/modules/mob/living/simple_animal/hostile/mining/goldgrub.dm +++ /dev/null @@ -1,82 +0,0 @@ -//An ore-devouring but easily scared creature -/mob/living/simple_animal/hostile/asteroid/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 = 'icons/mob/lavaland/lavaland_monsters.dmi' - icon_state = "Goldgrub" - icon_living = "Goldgrub" - icon_aggro = "Goldgrub_alert" - icon_dead = "Goldgrub_dead" - icon_gib = "syndicate_gib" - mob_biotypes = MOB_ORGANIC | MOB_BEAST - move_to_delay = 5 - friendly = "harmlessly rolls into" - maxHealth = 45 - health = 45 - harm_intent_damage = 5 - attacktext = "barrels into" - attack_sound = 'sound/weapons/punch1.ogg' - a_intent = INTENT_HELP - speak_emote = list("screeches") - throw_message = "sinks in slowly, before being pushed out of " - deathmessage = "spits up the contents of its stomach before dying!" - status_flags = CANPUSH - search_objects = 1 - contains_xeno_organ = TRUE - surgery_container = /datum/xenobiology_surgery_container/goldgrub - wanted_objects = list(/obj/item/stack/ore/diamond, /obj/item/stack/ore/gold, /obj/item/stack/ore/silver, - /obj/item/stack/ore/uranium) - - var/chase_time = 100 - var/will_burrow = TRUE - -/mob/living/simple_animal/hostile/asteroid/goldgrub/Initialize(mapload) - . = ..() - faction |= "goldgrub" - - 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/simple_animal/hostile/asteroid/goldgrub/GiveTarget(new_target) - target = new_target - if(target != null) - if(istype(target, /obj/item/stack/ore) && length(loot) < 10) - visible_message("[src] looks at [target.name] with hungry eyes.") - else if(isliving(target)) - Aggro() - visible_message("[src] tries to flee from [target.name]!") - retreat_distance = 10 - minimum_distance = 10 - if(will_burrow) - addtimer(CALLBACK(src, PROC_REF(Burrow)), chase_time) - -/mob/living/simple_animal/hostile/asteroid/goldgrub/AttackingTarget() - if(istype(target, /obj/item/stack/ore)) - EatOre(target) - return - return ..() - -/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/EatOre(atom/targeted_ore) - for(var/obj/item/stack/ore/O in get_turf(targeted_ore)) - if(length(loot) < 10) - var/using = min(10 - length(loot), O.amount) - for(var/i in 1 to using) - loot += O.type - O.use(using) - visible_message("The ore was swallowed whole!") - -/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/Burrow()//Begin the chase to kill the goldgrub in time - if(stat == CONSCIOUS) - visible_message("[src] buries into the ground, vanishing from sight!") - qdel(src) - -/mob/living/simple_animal/hostile/asteroid/goldgrub/bullet_act(obj/item/projectile/P) - if(P.armour_penetration_flat + P.armour_penetration_percentage >= 100) - return ..() - visible_message("[P.name] was repelled by [name]'s girth!") - -/mob/living/simple_animal/hostile/asteroid/goldgrub/adjustHealth(amount, updating_health = TRUE) - vision_range = 9 - . = ..() diff --git a/code/modules/mob/living/simple_animal/hostile/mining/gutlunch.dm b/code/modules/mob/living/simple_animal/hostile/mining/gutlunch.dm deleted file mode 100644 index 7ff8fbe854c..00000000000 --- a/code/modules/mob/living/simple_animal/hostile/mining/gutlunch.dm +++ /dev/null @@ -1,164 +0,0 @@ -//Gutlunches, passive mods that devour blood and gibs -/mob/living/simple_animal/hostile/asteroid/gutlunch - name = "gutlunch" - desc = "A scavenger that eats raw meat, often found alongside ash walkers. Produces a thick, medicinally nutritious milk." - icon = 'icons/mob/lavaland/lavaland_monsters.dmi' - icon_state = "gutlunch" - icon_living = "gutlunch" - icon_dead = "gutlunch" - mob_biotypes = MOB_ORGANIC | MOB_BEAST - speak_emote = list("warbles", "quavers") - emote_hear = list("trills.") - emote_see = list("sniffs.", "burps.") - weather_immunities = list("lava","ash") - faction = list("mining", "ashwalker") - density = FALSE - speak_chance = 1 - turns_per_move = 8 - obj_damage = 0 - environment_smash = ENVIRONMENT_SMASH_NONE - move_to_delay = 15 - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "squishes" - friendly = "pinches" - a_intent = INTENT_HELP - ventcrawler = VENTCRAWLER_ALWAYS - gold_core_spawnable = FRIENDLY_SPAWN - stat_attack = UNCONSCIOUS - gender = NEUTER - stop_automated_movement_when_pulled = TRUE - stat_exclusive = TRUE - robust_searching = TRUE - search_objects = 3 //Ancient simplemob AI shitcode. This makes them ignore all other mobs. - del_on_death = TRUE - loot = list(/obj/effect/decal/cleanable/blood/gibs) - deathmessage = "is pulped into bugmash." - - animal_species = /mob/living/simple_animal/hostile/asteroid/gutlunch - childtype = list(/mob/living/simple_animal/hostile/asteroid/gutlunch/grublunch = 100) - - wanted_objects = 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 = null - -/mob/living/simple_animal/hostile/asteroid/gutlunch/Initialize(mapload) - udder = new() - . = ..() - -/mob/living/simple_animal/hostile/asteroid/gutlunch/Destroy() - QDEL_NULL(udder) - return ..() - -/mob/living/simple_animal/hostile/asteroid/gutlunch/regenerate_icons() - ..() - if(udder.reagents.total_volume == udder.reagents.maximum_volume) - add_overlay("gl_full") - -/mob/living/simple_animal/hostile/asteroid/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 - -/mob/living/simple_animal/hostile/asteroid/gutlunch/CanAttack(atom/the_target) // Gutlunch-specific version of CanAttack to handle stupid stat_exclusive = true crap so we don't have to do it for literally every single simple_animal/hostile except the two that spawn in lavaland - if(isturf(the_target) || !the_target || the_target.type == /atom/movable/lighting_object) // bail out on invalids - return FALSE - - if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it - return FALSE - - if(isliving(the_target)) - var/mob/living/L = the_target - - if(faction_check_mob(L) && !attack_same) - return FALSE - if(L.stat > stat_attack || L.stat != stat_attack && stat_exclusive) - return FALSE - - return TRUE - - if(isobj(the_target) && is_type_in_typecache(the_target, wanted_objects)) - return TRUE - - return FALSE - -/mob/living/simple_animal/hostile/asteroid/gutlunch/AttackingTarget() - if(is_type_in_typecache(target,wanted_objects)) //we eats - udder.generateMilk() - regenerate_icons() - visible_message("[src] slurps up [target].") - qdel(target) - return ..() - -/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)) - - -//Male gutlunch. They're smaller and more colorful! -/mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck - name = "gubbuck" - gender = MALE - -/mob/living/simple_animal/hostile/asteroid/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/simple_animal/hostile/asteroid/gutlunch/guthen - name = "guthen" - gender = FEMALE - -/mob/living/simple_animal/hostile/asteroid/gutlunch/guthen/Life() - ..() - if(udder.reagents.total_volume == udder.reagents.maximum_volume) //Only breed when we're full. - make_babies() - -/mob/living/simple_animal/hostile/asteroid/gutlunch/guthen/make_babies() - . = ..() - if(.) - udder.reagents.clear_reagents() - regenerate_icons() - -/mob/living/simple_animal/hostile/asteroid/gutlunch/grublunch - name = "grublunch" - wanted_objects = list() //They don't eat. - gold_core_spawnable = NO_SPAWN - var/growth = 0 - -//Baby gutlunch -/mob/living/simple_animal/hostile/asteroid/gutlunch/grublunch/Initialize(mapload) - . = ..() - add_atom_colour("#9E9E9E", FIXED_COLOUR_PRIORITY) //Somewhat hidden - resize = 0.45 - update_transform() - -/mob/living/simple_animal/hostile/asteroid/gutlunch/grublunch/Life() - ..() - growth++ - if(growth > 50) //originally used a timer for this but was more problem that it's worth. - growUp() - -/mob/living/simple_animal/hostile/asteroid/gutlunch/grublunch/proc/growUp() - var/mob/living/L - if(prob(45)) - L = new /mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck(loc) - else - L = new /mob/living/simple_animal/hostile/asteroid/gutlunch/guthen(loc) - mind?.transfer_to(L) - L.faction = faction.Copy() - L.setDir(dir) - visible_message("[src] grows up into [L].") - qdel(src) diff --git a/paradise.dme b/paradise.dme index cd472d0a44c..317dd1fe2a5 100644 --- a/paradise.dme +++ b/paradise.dme @@ -476,8 +476,10 @@ #include "code\datums\ai\basic_mobs\basic_subtrees\attack_obstacle_in_path.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\capricious_retaliate.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_food.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\find_parent.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\flee_target.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\maintain_distance.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\make_babies.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\mine_walls.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\prowl.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\random_speech.dm" @@ -521,6 +523,7 @@ #include "code\datums\components\basic_mob_aggro_emote.dm" #include "code\datums\components\boomerang.dm" #include "code\datums\components\boss_music.dm" +#include "code\datums\components\breeding.dm" #include "code\datums\components\caltrop.dm" #include "code\datums\components\codeword_hearing.dm" #include "code\datums\components\connect_containers.dm" @@ -2458,13 +2461,22 @@ #include "code\modules\mob\living\basic\hostile\killertomato.dm" #include "code\modules\mob\living\basic\hostile\pirate.dm" #include "code\modules\mob\living\basic\hostile\skeleton_mob.dm" -#include "code\modules\mob\living\basic\hostile\soviet.dm" #include "code\modules\mob\living\basic\hostile\alien\alien_mob_ai.dm" #include "code\modules\mob\living\basic\hostile\alien\alien_mob_drone.dm" #include "code\modules\mob\living\basic\hostile\alien\alien_mob_hunter.dm" #include "code\modules\mob\living\basic\hostile\alien\alien_mob_maid.dm" #include "code\modules\mob\living\basic\hostile\alien\alien_mob_queen.dm" #include "code\modules\mob\living\basic\hostile\alien\alien_mob_sentinel.dm" +#include "code\modules\mob\living\basic\mining\basilisk.dm" +#include "code\modules\mob\living\basic\mining\basilisk_ai.dm" +#include "code\modules\mob\living\basic\mining\gutlunch.dm" +#include "code\modules\mob\living\basic\mining\gutlunch_ai.dm" +#include "code\modules\mob\living\basic\mining\hivelord.dm" +#include "code\modules\mob\living\basic\mining\hivelord_ai.dm" +#include "code\modules\mob\living\basic\mining\goldgrub\goldgrub.dm" +#include "code\modules\mob\living\basic\mining\goldgrub\goldgrub_ai.dm" +#include "code\modules\mob\living\basic\mining\mining_mobs.dm" +#include "code\modules\mob\living\basic\hostile\soviet.dm" #include "code\modules\mob\living\basic\hostile\giant_spider\giant_spider.dm" #include "code\modules\mob\living\basic\hostile\giant_spider\giant_spider_actions.dm" #include "code\modules\mob\living\basic\hostile\giant_spider\giant_spider_ai.dm" @@ -2474,11 +2486,6 @@ #include "code\modules\mob\living\basic\minebots\minebot_abilities.dm" #include "code\modules\mob\living\basic\minebots\minebot_ai.dm" #include "code\modules\mob\living\basic\minebots\minebot_upgrades.dm" -#include "code\modules\mob\living\basic\mining\basilisk.dm" -#include "code\modules\mob\living\basic\mining\basilisk_ai.dm" -#include "code\modules\mob\living\basic\mining\hivelord.dm" -#include "code\modules\mob\living\basic\mining\hivelord_ai.dm" -#include "code\modules\mob\living\basic\mining\mining_mobs.dm" #include "code\modules\mob\living\basic\nether_mobs\blankbody.dm" #include "code\modules\mob\living\basic\nether_mobs\faithless.dm" #include "code\modules\mob\living\basic\nether_mobs\migo.dm" @@ -2694,9 +2701,7 @@ #include "code\modules\mob\living\simple_animal\hostile\megafauna\legion.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\megafauna.dm" #include "code\modules\mob\living\simple_animal\hostile\mining\abandoned_minebot.dm" -#include "code\modules\mob\living\simple_animal\hostile\mining\goldgrub.dm" #include "code\modules\mob\living\simple_animal\hostile\mining\goliath.dm" -#include "code\modules\mob\living\simple_animal\hostile\mining\gutlunch.dm" #include "code\modules\mob\living\simple_animal\hostile\mining\mining.dm" #include "code\modules\mob\living\simple_animal\hostile\mining\elites\elite.dm" #include "code\modules\mob\living\simple_animal\hostile\mining\elites\goliath_broodmother.dm"