diff --git a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_survivalpod.dmm b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_survivalpod.dmm index 0f0b47cb810..653b784e44a 100644 --- a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_survivalpod.dmm +++ b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_survivalpod.dmm @@ -65,9 +65,7 @@ /area/lavaland/surface/outdoors) "o" = ( /obj/effect/decal/cleanable/blood, -/mob/living/simple_animal/hostile/asteroid/goliath/beast{ - health = 0 - }, +/obj/effect/mob_spawn/corpse/goliath, /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) "p" = ( diff --git a/code/__DEFINES/ai/blackboard_defines.dm b/code/__DEFINES/ai/blackboard_defines.dm index c74daddbd25..d6f98e271c5 100644 --- a/code/__DEFINES/ai/blackboard_defines.dm +++ b/code/__DEFINES/ai/blackboard_defines.dm @@ -53,6 +53,8 @@ #define BB_OBSTACLE_TARGETING_WHITELIST "BB_targeting_whitelist" /// some behaviors that check current_target also set this on deep crit mobs #define BB_BASIC_MOB_EXECUTION_TARGET "BB_basic_execution_target" +/// Blackboard key storing how long your targeting strategy has held a particular target +#define BB_BASIC_MOB_HAS_TARGET_TIME "BB_BASIC_MOB_HAS_TARGET_TIME" //Hunting BB keys @@ -230,3 +232,9 @@ // Malf Drones /// Are we active? #define BB_MALF_DRONE_PASSIVE "BB_MALF_DRONE_PASSIVE" + +// Goliath AI keys +/// Key where we store the tentacleing ability +#define BB_GOLIATH_TENTACLES "BB_GOLIATH_TENTACLES" +/// Key where goliath stores a hole it wants to get into +#define BB_GOLIATH_HOLE_TARGET "BB_GOLIATH_HOLE" diff --git a/code/__DEFINES/dcs/mob_signals.dm b/code/__DEFINES/dcs/mob_signals.dm index a619004bed4..dc6f8fd0f6f 100644 --- a/code/__DEFINES/dcs/mob_signals.dm +++ b/code/__DEFINES/dcs/mob_signals.dm @@ -279,5 +279,15 @@ /// From base of /datum/action/cooldown/proc/set_statpanel_format(): (list/stat_panel_data) #define COMSIG_ACTION_SET_STATPANEL "ability_set_statpanel" +/// Fired by a mob which has been grabbed by a goliath +#define COMSIG_GOLIATH_TENTACLED_GRABBED "goliath_tentacle_grabbed" +/// Fired by a goliath tentacle which is returning to the earth +#define COMSIG_GOLIATH_TENTACLE_RETRACTING "goliath_tentacle_retracting" + +/// Called from /mob/living/carbon/help_shake_act, before any hugs have occurred. (mob/living/helper) +#define COMSIG_CARBON_PRE_MISC_HELP "carbon_pre_misc_help" + /// Stops the rest of help act (hugging, etc) from occurring + #define COMPONENT_BLOCK_MISC_HELP (1<<0) + /// From base of /client/Move(): (direction, old_dir) #define COMSIG_MOB_CLIENT_MOVED "mob_client_moved" diff --git a/code/__HELPERS/trait_helpers.dm b/code/__HELPERS/trait_helpers.dm index 07c2f716e03..cc56db5b1cc 100644 --- a/code/__HELPERS/trait_helpers.dm +++ b/code/__HELPERS/trait_helpers.dm @@ -513,6 +513,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_CANNOT_PULL "pullblocked" /// Abstract condition that prevents movement if being pulled and might be resisted against. Handcuffs and straight jackets, basically. #define TRAIT_RESTRAINED "restrained" +#define TRAIT_FROM_TENDRIL "from_tendril" +#define TRAIT_TENTACLE_IMMUNE "tentacle_immune" ///Traits given by station traits #define STATION_TRAIT_BANANIUM_SHIPMENTS "station_trait_bananium_shipments" diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index 47d641ce4fb..473b2767a84 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -121,6 +121,8 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_RELAYING_ATTACKER" = TRAIT_RELAYING_ATTACKER, "TRAIT_LOUD" = TRAIT_LOUD, "TRAIT_WIRE_BLIND" = TRAIT_WIRE_BLIND, + "TRAIT_FROM_TENDRIL" = TRAIT_FROM_TENDRIL, + "TRAIT_TENTACLE_IMMUNE" = TRAIT_TENTACLE_IMMUNE, "TRAIT_BOOTS_OF_JUMPING" = TRAIT_BOOTS_OF_JUMPING ), diff --git a/code/datums/components/ai_has_target_timer.dm b/code/datums/components/ai_has_target_timer.dm new file mode 100644 index 00000000000..12aaf814a7a --- /dev/null +++ b/code/datums/components/ai_has_target_timer.dm @@ -0,0 +1,79 @@ +/// Increments a blackboard key while the attached mob is engaged with a particular target, does nothing else on its own +/datum/component/ai_target_timer + /// Blackboard key to store data inside + var/increment_key + /// Blackboard key to watch to indicate whether we are 'in combat' + var/target_key + /// Amount of time we have spent focused on one target + var/time_on_target = 0 + /// The last target we had + var/atom/last_target + /// Timer used to see if you + var/reset_clock_timer + +/datum/component/ai_target_timer/Initialize(increment_key = BB_BASIC_MOB_HAS_TARGET_TIME, target_key = BB_BASIC_MOB_CURRENT_TARGET) + . = ..() + if(!isliving(parent)) + return COMPONENT_INCOMPATIBLE + var/mob/living/mob_parent = parent + if(isnull(mob_parent.ai_controller)) + return COMPONENT_INCOMPATIBLE + src.increment_key = increment_key + src.target_key = target_key + +/datum/component/ai_target_timer/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_AI_BLACKBOARD_KEY_SET(target_key), PROC_REF(changed_target)) + RegisterSignal(parent, COMSIG_AI_BLACKBOARD_KEY_CLEARED(target_key), PROC_REF(lost_target)) + ADD_TRAIT(parent, TRAIT_SUBTREE_REQUIRED_OPERATIONAL_DATUM, type) + +/datum/component/ai_target_timer/UnregisterFromParent() + finalise_losing_target() + UnregisterSignal(parent, list(COMSIG_AI_BLACKBOARD_KEY_SET(target_key), COMSIG_AI_BLACKBOARD_KEY_CLEARED(target_key))) + REMOVE_TRAIT(parent, TRAIT_SUBTREE_REQUIRED_OPERATIONAL_DATUM, type) + return ..() + +/datum/component/ai_target_timer/Destroy(force) + finalise_losing_target() + return ..() + +/// When we get a new target, reset the timer and start processing +/datum/component/ai_target_timer/proc/changed_target(mob/living/source) + SIGNAL_HANDLER + var/mob/living/living_parent = parent + var/atom/new_target = living_parent.ai_controller.blackboard[target_key] + deltimer(reset_clock_timer) + if(new_target == last_target) + return + time_on_target = 0 + store_current_time() + START_PROCESSING(SSdcs, src) + if(!isnull(last_target)) + UnregisterSignal(last_target, COMSIG_PARENT_QDELETING) + RegisterSignal(new_target, COMSIG_PARENT_QDELETING, PROC_REF(finalise_losing_target)) + last_target = new_target + +/// When we lose our target, start a short timer in case we reacquire it very quickly +/datum/component/ai_target_timer/proc/lost_target() + SIGNAL_HANDLER + reset_clock_timer = addtimer(CALLBACK(src, PROC_REF(finalise_losing_target)), 3 SECONDS, TIMER_STOPPABLE | TIMER_DELETE_ME) + +/// Called if we have had no target for long enough +/datum/component/ai_target_timer/proc/finalise_losing_target() + deltimer(reset_clock_timer) + STOP_PROCESSING(SSdcs, src) + if(!isnull(last_target)) + UnregisterSignal(last_target, COMSIG_PARENT_QDELETING) + last_target = null + time_on_target = 0 + if(!QDELETED(parent)) + store_current_time() + +/// Store the current time on our timer in our blackboard key +/datum/component/ai_target_timer/proc/store_current_time() + var/mob/living/living_parent = parent + living_parent.ai_controller.set_blackboard_key(increment_key, time_on_target) + +/datum/component/ai_target_timer/process(seconds_per_tick) + time_on_target += seconds_per_tick SECONDS + store_current_time() diff --git a/code/datums/components/spawner.dm b/code/datums/components/spawner.dm index a289377cf67..6b331752bd8 100644 --- a/code/datums/components/spawner.dm +++ b/code/datums/components/spawner.dm @@ -53,6 +53,7 @@ spawned_mobs += L L.nest = src L.faction = src.faction + ADD_TRAIT(L, TRAIT_FROM_TENDRIL, INNATE_TRAIT) P.visible_message("[L] [spawn_text] [P].") P.on_mob_spawn(L) return L diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index 8067481defc..3ff685831fa 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -647,11 +647,11 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/newplayer_start) //Without this you sp return INITIALIZE_HINT_QDEL /obj/effect/landmark/mob_spawner/goliath - mobtype = /mob/living/simple_animal/hostile/asteroid/goliath/beast + mobtype = /mob/living/basic/mining/goliath /obj/effect/landmark/mob_spawner/goliath/Initialize(mapload) if(prob(1)) - mobtype = /mob/living/simple_animal/hostile/asteroid/goliath/beast/ancient + mobtype = /mob/living/basic/mining/goliath/ancient . = ..() /obj/effect/landmark/mob_spawner/legion diff --git a/code/game/objects/structures/lavaland/necropolis_tendril.dm b/code/game/objects/structures/lavaland/necropolis_tendril.dm index a2e0c09600b..b69b523b9ed 100644 --- a/code/game/objects/structures/lavaland/necropolis_tendril.dm +++ b/code/game/objects/structures/lavaland/necropolis_tendril.dm @@ -9,7 +9,7 @@ faction = list("mining") max_mobs = 3 max_integrity = 250 - mob_types = list(/mob/living/basic/mining/basilisk/watcher/tendril) + mob_types = list(/mob/living/basic/mining/basilisk/watcher) move_resist = INFINITY // just killing it tears a massive hole in the ground, let's not move it resistance_flags = FIRE_PROOF | LAVA_PROOF @@ -17,10 +17,10 @@ var/obj/effect/light_emitter/tendril/emitted_light /obj/structure/spawner/lavaland/goliath - mob_types = list(/mob/living/simple_animal/hostile/asteroid/goliath/beast/tendril) + mob_types = list(/mob/living/basic/mining/goliath) /obj/structure/spawner/lavaland/legion - mob_types = list(/mob/living/basic/mining/hivelord/legion/tendril) + mob_types = list(/mob/living/basic/mining/hivelord/legion) GLOBAL_LIST_EMPTY(tendrils) diff --git a/code/game/objects/structures/monster_spawner.dm b/code/game/objects/structures/monster_spawner.dm index 0a6897c2139..7ed71b15440 100644 --- a/code/game/objects/structures/monster_spawner.dm +++ b/code/game/objects/structures/monster_spawner.dm @@ -53,7 +53,12 @@ max_mobs = 3 icon = 'icons/mob/nest.dmi' spawn_text = "crawls out of" - 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) + mob_types = list( + /mob/living/basic/mining/goldgrub, + /mob/living/basic/mining/goliath, + /mob/living/basic/mining/hivelord, + /mob/living/basic/mining/basilisk, + ) faction = list("mining") /obj/structure/spawner/mining/goldgrub @@ -64,10 +69,10 @@ /obj/structure/spawner/mining/goliath name = "goliath den" desc = "A den housing a nest of goliaths, oh god why?" - mob_types = list(/mob/living/simple_animal/hostile/asteroid/goliath) + mob_types = list(/mob/living/basic/mining/goliath) /obj/structure/spawner/mining/goliath/space - mob_types = list(/mob/living/simple_animal/hostile/asteroid/goliath/space) + mob_types = list(/mob/living/basic/mining/goliath/space) /obj/structure/spawner/mining/hivelord name = "hivelord den" diff --git a/code/game/objects/structures/nest.dm b/code/game/objects/structures/nest.dm index 9220eacd61d..b86a0f6a252 100644 --- a/code/game/objects/structures/nest.dm +++ b/code/game/objects/structures/nest.dm @@ -71,7 +71,10 @@ 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/basic/mining/goldgrub) + spawn_mob_options = list( + /mob/living/basic/mining/goliath, + /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/awaymissions/mob_spawn.dm b/code/modules/awaymissions/mob_spawn.dm index c40d91d3480..16c1721acad 100644 --- a/code/modules/awaymissions/mob_spawn.dm +++ b/code/modules/awaymissions/mob_spawn.dm @@ -802,7 +802,7 @@ pixel_x = -12 /obj/effect/mob_spawn/corpse/goliath - mob_type = /mob/living/simple_animal/hostile/asteroid/goliath/beast + mob_type = /mob/living/basic/mining/goliath icon = 'icons/mob/lavaland/lavaland_monsters.dmi' icon_state = "goliath_dead" pixel_x = -12 diff --git a/code/modules/mob/living/basic/lavaland/goliath/goliath.dm b/code/modules/mob/living/basic/lavaland/goliath/goliath.dm new file mode 100644 index 00000000000..fff35144332 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/goliath/goliath.dm @@ -0,0 +1,147 @@ +/// A slow but strong beast that tries to stun using its tentacles. +/mob/living/basic/mining/goliath + name = "goliath" + desc = "A massive beast that uses long tentacles to ensnare its prey, threatening them is not advised under any conditions." + icon_state = "goliath" + icon_living = "goliath" + icon_aggro = "goliath" + icon_dead = "goliath_dead" + icon_gib = "syndicate_gib" + speak_emote = list("bellows") + speed = 5 + maxHealth = 300 + health = 300 + harm_intent_damage = 1 // Only the manliest of men can kill a Goliath with only their fists. + obj_damage = 100 + melee_damage_lower = 25 + melee_damage_upper = 25 + attack_verb_simple = "pulverize" + attack_verb_continuous = "pulverizes" + throw_blocked_message = "does nothing to the rocky hide of the" + move_force = MOVE_FORCE_VERY_STRONG + move_resist = MOVE_FORCE_VERY_STRONG + pull_force = MOVE_FORCE_VERY_STRONG + crusher_loot = /obj/item/crusher_trophy/goliath_tentacle + ai_controller = /datum/ai_controller/basic_controller/goliath + faction = list("mining") + butcher_results = list( + /obj/item/food/monstermeat/goliath = 2, + /obj/item/stack/sheet/animalhide/goliath_hide = 1, + /obj/item/stack/sheet/bone = 2, + ) + + /// Icon state to use when tentacles are available + var/tentacle_warning_state = "goliath2" + /// Slight cooldown to prevent double-dipping if we use both abilities at once + COOLDOWN_DECLARE(ability_animation_cooldown) + /// Our base tentacles ability + var/datum/action/cooldown/mob_cooldown/goliath_tentacles/tentacles + /// Things we want to eat off the floor (or a plate, we're not picky) + var/static/list/goliath_foods = list( + /obj/item/food/grown/ash_flora, + ) + + +/mob/living/basic/mining/goliath/Initialize(mapload) + . = ..() + + ADD_TRAIT(src, TRAIT_TENTACLE_IMMUNE, INNATE_TRAIT) + + AddElement(/datum/element/ai_retaliate) + AddElement(/datum/element/basic_eating, heal_amt_ = 10, food_types_ = goliath_foods) + AddComponent(/datum/component/ai_target_timer) + AddComponent(/datum/component/footstep, FOOTSTEP_MOB_HEAVY) + + tentacles = new(src) + tentacles.Grant(src) + + tentacles_ready() + RegisterSignal(src, COMSIG_MOB_ABILITY_FINISHED, PROC_REF(used_ability)) + ai_controller.set_blackboard_key(BB_BASIC_FOODS, typecacheof(goliath_foods)) + ai_controller.set_blackboard_key(BB_GOLIATH_TENTACLES, tentacles) + +/// Called slightly before tentacles ability comes off cooldown, as a warning +/mob/living/basic/mining/goliath/proc/tentacles_ready() + if(stat == DEAD) + return + icon_state = tentacle_warning_state + +/// When we use an ability, activate some kind of visual tell +/mob/living/basic/mining/goliath/proc/used_ability(mob/living/source, datum/action/cooldown/ability) + SIGNAL_HANDLER + if(stat == DEAD || ability.IsAvailable()) + return // We died or the action failed for some reason like being out of range + if(istype(ability, /datum/action/cooldown/mob_cooldown/goliath_tentacles)) + if(ability.cooldown_time <= 2 SECONDS) + return + icon_state = icon_living + addtimer(CALLBACK(src, PROC_REF(tentacles_ready)), ability.cooldown_time - 2 SECONDS, TIMER_DELETE_ME) + return + if(!COOLDOWN_FINISHED(src, ability_animation_cooldown)) + return + COOLDOWN_START(src, ability_animation_cooldown, 2 SECONDS) + Shake(1, 0, 1.5 SECONDS) + +/mob/living/basic/mining/goliath/Destroy() + . = ..() + QDEL_NULL(tentacles) + +/mob/living/basic/mining/goliath/death(gibbed) + move_force = MOVE_FORCE_DEFAULT + move_resist = MOVE_RESIST_DEFAULT + pull_force = PULL_FORCE_DEFAULT + ..(gibbed) + +/mob/living/basic/mining/goliath/ancient + name = "ancient goliath" + desc = "Goliaths are biologically immortal, and rare specimens have survived for centuries. This one is clearly ancient, and its tentacles constantly churn the earth around it." + icon_state = "Goliath" + icon_living = "Goliath" + icon_dead = "Goliath_dead" + maxHealth = 400 + health = 400 + speed = 4 + tentacle_warning_state = "Goliath_preattack" + butcher_results = list( + /obj/item/food/monstermeat/goliath = 2, + /obj/item/stack/sheet/bone = 2, + ) + loot = list(/obj/item/stack/sheet/animalhide/goliath_hide) + crusher_loot = /obj/item/crusher_trophy/goliath_tentacle/ancient + crusher_drop_mod = 100 //These things are rare (1/100 per spawner). You shouldn't have to hope for another stroke of luck to get it's trophy after finding it + /// Don't re-check nearby turfs for this long + COOLDOWN_DECLARE(retarget_turfs_cooldown) + /// List of places we might spawn a tentacle, if we're alive + var/list/tentacle_target_turfs + +/mob/living/basic/mining/goliath/ancient/Life(seconds_per_tick, times_fired) + . = ..() + if(!. || !isturf(loc)) + return + if(!LAZYLEN(tentacle_target_turfs) || COOLDOWN_FINISHED(src, retarget_turfs_cooldown)) + cache_nearby_turfs() + for(var/turf/target_turf in tentacle_target_turfs) + if(target_turf.is_blocked_turf(exclude_mobs = TRUE)) + tentacle_target_turfs -= target_turf + continue + if(prob(10)) + new /obj/effect/temp_visual/goliath_tentacle(target_turf) + +/mob/living/basic/mining/goliath/ancient/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) + . = ..() + if(loc == old_loc || stat == DEAD || !isturf(loc)) + return + cache_nearby_turfs() + +/// Store nearby turfs in our list so we can pop them out later +/mob/living/basic/mining/goliath/ancient/proc/cache_nearby_turfs() + COOLDOWN_START(src, retarget_turfs_cooldown, 10 SECONDS) + LAZYCLEARLIST(tentacle_target_turfs) + for(var/turf/T in orange(4, loc)) + if(isfloorturf(T)) + LAZYADD(tentacle_target_turfs, T) + +/mob/living/basic/mining/goliath/space + +/mob/living/basic/mining/goliath/space/Process_Spacemove(movement_dir, continuous_move) + return TRUE diff --git a/code/modules/mob/living/basic/lavaland/goliath/goliath_actions.dm b/code/modules/mob/living/basic/lavaland/goliath/goliath_actions.dm new file mode 100644 index 00000000000..83ea6f7c9ca --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/goliath/goliath_actions.dm @@ -0,0 +1,32 @@ +/// Place some grappling tentacles underfoot +/datum/action/cooldown/mob_cooldown/goliath_tentacles + name = "Unleash Tentacles" + desc = "Unleash burrowed tentacles at a targeted location, grappling targets after a delay." + button_icon = 'icons/mob/lavaland/lavaland_monsters.dmi' + button_icon_state = "Goliath_tentacle_wiggle" + background_icon_state = "bg_demon" + overlay_icon_state = "bg_demon_border" + cooldown_time = 12 SECONDS + shared_cooldown = NONE + /// Furthest range we can activate ability at + var/max_range = 7 + +/datum/action/cooldown/mob_cooldown/goliath_tentacles/PreActivate(atom/target) + target = get_turf(target) + if(get_dist(owner, target) > max_range) + return FALSE + return ..() + +/datum/action/cooldown/mob_cooldown/goliath_tentacles/Activate(atom/target) + new /obj/effect/temp_visual/goliath_tentacle(target) + var/list/directions = GLOB.cardinal.Copy() + for(var/i in 1 to 3) + var/spawndir = pick_n_take(directions) + var/turf/adjacent_target = get_step(target, spawndir) + if(adjacent_target) + new /obj/effect/temp_visual/goliath_tentacle(adjacent_target) + + if(isliving(target)) + owner.visible_message("[owner] digs its tentacles under [target]!") + StartCooldown() + return TRUE diff --git a/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm b/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm new file mode 100644 index 00000000000..81615341134 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm @@ -0,0 +1,124 @@ +/// We won't use tentacles unless we have had the same target for this long +#define MIN_TIME_TO_TENTACLE 3 SECONDS + +/datum/ai_controller/basic_controller/goliath + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_TARGET_MINIMUM_STAT = UNCONSCIOUS, + BB_AGGRO_RANGE = 5, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/target_retaliate/check_faction, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/targeted_mob_ability/goliath_tentacles, + /datum/ai_planning_subtree/attack_obstacle_in_path, + /datum/ai_planning_subtree/basic_melee_attack_subtree/goliath, + /datum/ai_planning_subtree/find_food, + /datum/ai_planning_subtree/goliath_find_diggable_turf, + /datum/ai_planning_subtree/goliath_dig, + ) + +/datum/ai_planning_subtree/basic_melee_attack_subtree/goliath + operational_datums = list(/datum/component/ai_target_timer) + melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/goliath + +/// Go for the tentacles if they're available +/datum/ai_behavior/basic_melee_attack/goliath + +/datum/ai_behavior/basic_melee_attack/goliath/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key, health_ratio_key) + var/time_on_target = controller.blackboard[BB_BASIC_MOB_HAS_TARGET_TIME] || 0 + if(time_on_target < MIN_TIME_TO_TENTACLE) + return ..() + var/mob/living/target = controller.blackboard[target_key] + // Interrupt attack chain to use tentacles, unless the target is already tentacled + if(ismecha(target) || (isliving(target) && !target.has_status_effect(/datum/status_effect/incapacitating/stun/goliath_tentacled))) + var/datum/action/cooldown/using_action = controller.blackboard[BB_GOLIATH_TENTACLES] + if(using_action?.IsAvailable()) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED + return ..() + +/datum/ai_planning_subtree/targeted_mob_ability/goliath_tentacles + ability_key = BB_GOLIATH_TENTACLES + operational_datums = list(/datum/component/ai_target_timer) + +/datum/ai_planning_subtree/targeted_mob_ability/goliath_tentacles/select_behaviors(datum/ai_controller/controller, seconds_per_tick) + var/mob/living/target = controller.blackboard[target_key] + if(!(isliving(target) || ismecha(target)) || (isliving(target) && target.has_status_effect(/datum/status_effect/incapacitating/stun/goliath_tentacled))) + return // Target can be an item or already grabbed, we don't want to tentacle those + var/time_on_target = controller.blackboard[BB_BASIC_MOB_HAS_TARGET_TIME] || 0 + if(time_on_target < MIN_TIME_TO_TENTACLE) + return // We need to spend some time acquiring our target first + return ..() + +/// If we got nothing better to do, find a turf we can search for tasty roots and such +/datum/ai_planning_subtree/goliath_find_diggable_turf + +/datum/ai_planning_subtree/goliath_find_diggable_turf/select_behaviors(datum/ai_controller/controller, seconds_per_tick) + controller.queue_behavior(/datum/ai_behavior/goliath_find_diggable_turf) + +/datum/ai_behavior/goliath_find_diggable_turf + action_cooldown = 2 SECONDS + /// Where do we store the target data + var/target_key = BB_GOLIATH_HOLE_TARGET + /// How far do we look for turfs? + var/scan_range = 3 + +/datum/ai_behavior/goliath_find_diggable_turf/perform(seconds_per_tick, datum/ai_controller/controller) + var/turf/target_turf = controller.blackboard[target_key] + if(is_valid_turf(target_turf)) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + + var/mob/living/pawn = controller.pawn + var/list/nearby_turfs = RANGE_TURFS(scan_range, pawn) + var/turf/check_turf = pick(nearby_turfs) // This isn't an efficient search algorithm but we don't need it to be + if(!is_valid_turf(check_turf)) + // Otherwise they won't perform idle wanderin + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + controller.set_blackboard_key(target_key, check_turf) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + +/// Return true if this is a turf we can dig +/datum/ai_behavior/goliath_find_diggable_turf/proc/is_valid_turf(turf/check_turf) + var/turf/simulated/floor/plating/asteroid/asteroid_floor = check_turf + if(!istype(asteroid_floor)) + return FALSE + return !asteroid_floor.dug + +/datum/ai_planning_subtree/goliath_dig + /// Where did we store the target data + var/target_key = BB_GOLIATH_HOLE_TARGET + +/datum/ai_planning_subtree/goliath_dig/select_behaviors(datum/ai_controller/controller, seconds_per_tick) + if(!controller.blackboard_key_exists(target_key)) + return + controller.queue_behavior(/datum/ai_behavior/goliath_dig, target_key) + return SUBTREE_RETURN_FINISH_PLANNING + +/// If we got nothing better to do, dig a little hole +/datum/ai_behavior/goliath_dig + action_cooldown = 3 MINUTES + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + +/datum/ai_behavior/goliath_dig/setup(datum/ai_controller/controller, target_key) + . = ..() + var/turf/target_turf = controller.blackboard[target_key] + if(QDELETED(target_turf)) + return + set_movement_target(controller, target_turf) + +/datum/ai_behavior/goliath_dig/perform(seconds_per_tick, datum/ai_controller/controller, target_key) + var/turf/target_turf = controller.blackboard[target_key] + var/mob/living/basic/basic_mob = controller.pawn + if(!basic_mob.can_reach(target_turf)) + return AI_BEHAVIOR_DELAY + basic_mob.melee_attack(target_turf) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + +/datum/ai_behavior/goliath_dig/finish_action(datum/ai_controller/controller, succeeded, target_key) + . = ..() + controller.clear_blackboard_key(target_key) + +#undef MIN_TIME_TO_TENTACLE diff --git a/code/modules/mob/living/basic/lavaland/goliath/tentacle.dm b/code/modules/mob/living/basic/lavaland/goliath/tentacle.dm new file mode 100644 index 00000000000..69026831e83 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/goliath/tentacle.dm @@ -0,0 +1,100 @@ +/obj/effect/temp_visual/goliath_tentacle + name = "goliath tentacle" + icon = 'icons/mob/lavaland/lavaland_monsters.dmi' + icon_state = "Goliath_tentacle_spawn" + layer = BELOW_MOB_LAYER + var/mob/living/spawner + +/obj/effect/temp_visual/goliath_tentacle/Initialize(mapload, mob/living/new_spawner) + . = ..() + for(var/obj/effect/temp_visual/goliath_tentacle/T in loc) + if(T != src) + return INITIALIZE_HINT_QDEL + if(!QDELETED(new_spawner)) + spawner = new_spawner + if(ismineralturf(loc)) + var/turf/simulated/mineral/M = loc + M.gets_drilled() + deltimer(timerid) + timerid = addtimer(CALLBACK(src, PROC_REF(tripanim)), 7, TIMER_STOPPABLE) + +/obj/effect/temp_visual/goliath_tentacle/original/Initialize(mapload, new_spawner) + . = ..() + var/list/directions = GLOB.cardinal.Copy() + for(var/i in 1 to 3) + var/spawndir = pick_n_take(directions) + var/turf/T = get_step(src, spawndir) + if(T) + new /obj/effect/temp_visual/goliath_tentacle(T, spawner) + +/obj/effect/temp_visual/goliath_tentacle/proc/tripanim() + icon_state = "Goliath_tentacle_wiggle" + deltimer(timerid) + timerid = addtimer(CALLBACK(src, PROC_REF(trip)), 3, TIMER_STOPPABLE) + +/obj/effect/temp_visual/goliath_tentacle/proc/trip() + var/latched = FALSE + for(var/mob/living/L in loc) + if((!QDELETED(spawner) && spawner.faction_check_mob(L)) || L.stat == DEAD) + continue + visible_message("[src] grabs hold of [L]!") + L.Stun(10 SECONDS) + L.adjustBruteLoss(rand(10,15)) + latched = TRUE + if(!latched) + retract() + else + deltimer(timerid) + timerid = addtimer(CALLBACK(src, PROC_REF(retract)), 10, TIMER_STOPPABLE) + +/obj/effect/temp_visual/goliath_tentacle/proc/retract() + icon_state = "Goliath_tentacle_retract" + deltimer(timerid) + timerid = QDEL_IN(src, 7) + +/// Goliath tentacle stun with special removal conditions +/datum/status_effect/incapacitating/stun/goliath_tentacled + id = "goliath_tentacled" + duration = 10 SECONDS + /// The tentacle that is tenderly holding us close + var/obj/effect/temp_visual/goliath_tentacle/tentacle + +/datum/status_effect/incapacitating/stun/goliath_tentacled/on_creation(mob/living/new_owner, set_duration, obj/effect/temp_visual/goliath_tentacle/tentacle) + . = ..() + if(!.) + return + src.tentacle = tentacle + +/datum/status_effect/incapacitating/stun/goliath_tentacled/on_apply() + . = ..() + RegisterSignal(owner, COMSIG_CARBON_PRE_MISC_HELP, PROC_REF(on_helped)) + RegisterSignals(owner, SIGNAL_ADDTRAIT(TRAIT_TENTACLE_IMMUNE), PROC_REF(release)) + RegisterSignals(tentacle, list(COMSIG_PARENT_QDELETING, COMSIG_GOLIATH_TENTACLE_RETRACTING), PROC_REF(on_tentacle_left)) + +/datum/status_effect/incapacitating/stun/goliath_tentacled/on_remove() + . = ..() + UnregisterSignal(owner, list(COMSIG_CARBON_PRE_MISC_HELP, SIGNAL_ADDTRAIT(TRAIT_TENTACLE_IMMUNE))) + if(isnull(tentacle)) + return + UnregisterSignal(tentacle, list(COMSIG_PARENT_QDELETING, COMSIG_GOLIATH_TENTACLE_RETRACTING)) + tentacle.retract() + tentacle = null + +/// Some kind soul has rescued us +/datum/status_effect/incapacitating/stun/goliath_tentacled/proc/on_helped(mob/source, mob/helping) + SIGNAL_HANDLER // COMSIG_CARBON_PRE_MISC_HELP + release() + source.visible_message("[helping] rips [source] from the tentacle's grasp!") + return COMPONENT_BLOCK_MISC_HELP + +/// Something happened to make the tentacle let go +/datum/status_effect/incapacitating/stun/goliath_tentacled/proc/release() + SIGNAL_HANDLER // SIGNAL_ADDTRAIT(TRAIT_TENTACLE_IMMUNE) + owner.remove_status_effect(/datum/status_effect/incapacitating/stun/goliath_tentacled) + +/// Something happened to our associated tentacle +/datum/status_effect/incapacitating/stun/goliath_tentacled/proc/on_tentacle_left() + SIGNAL_HANDLER // COMSIG_PARENT_QDELETING + COMSIG_GOLIATH_TENTACLE_RETRACTING + UnregisterSignal(tentacle, list(COMSIG_PARENT_QDELETING, COMSIG_GOLIATH_TENTACLE_RETRACTING)) // No endless loops for us please + tentacle = null + release() diff --git a/code/modules/mob/living/basic/mining/basilisk.dm b/code/modules/mob/living/basic/mining/basilisk.dm index 05b8ad051d6..fb51260d6bb 100644 --- a/code/modules/mob/living/basic/mining/basilisk.dm +++ b/code/modules/mob/living/basic/mining/basilisk.dm @@ -130,6 +130,3 @@ var/mob/living/L = target if(istype(L)) L.apply_status_effect(/datum/status_effect/freon/watcher) - -/mob/living/basic/mining/basilisk/watcher/tendril - from_tendril = TRUE diff --git a/code/modules/mob/living/basic/mining/hivelord.dm b/code/modules/mob/living/basic/mining/hivelord.dm index 8d4ee88f9f5..4a3724bde02 100644 --- a/code/modules/mob/living/basic/mining/hivelord.dm +++ b/code/modules/mob/living/basic/mining/hivelord.dm @@ -183,9 +183,6 @@ crusher_drop_mod = 20 dwarf_mob = TRUE -/mob/living/basic/mining/hivelord/legion/tendril - from_tendril = TRUE - /mob/living/basic/mining/hivelord/legion/death(gibbed) visible_message("The skulls on [src] wail in anger as they flee from their dying host!") var/turf/T = get_turf(src) @@ -193,7 +190,7 @@ if(stored_mob) stored_mob.forceMove(get_turf(src)) stored_mob = null - else if(from_tendril) + else if(HAS_TRAIT(src, TRAIT_FROM_TENDRIL)) new /obj/effect/mob_spawn/human/corpse/charredskeleton(T) else if(dwarf_mob) new /obj/effect/mob_spawn/human/corpse/damaged/legioninfested/dwarf(T) @@ -256,9 +253,6 @@ ai_controller = /datum/ai_controller/basic_controller/hivelord_brood/advanced_legion can_infest_dead = TRUE -/mob/living/basic/mining/hivelord/legion/advanced/tendril - from_tendril = TRUE - // Big legion (billy) /mob/living/basic/mining/big_legion name = "big legion" diff --git a/code/modules/mob/living/basic/mining/mining_mobs.dm b/code/modules/mob/living/basic/mining/mining_mobs.dm index aa585c70222..efa770edc16 100644 --- a/code/modules/mob/living/basic/mining/mining_mobs.dm +++ b/code/modules/mob/living/basic/mining/mining_mobs.dm @@ -20,8 +20,6 @@ var/crusher_loot /// What is the chance the mob drops it if all their health was taken by crusher attacks var/crusher_drop_mod = 25 - /// Whether or not the mob came from a tendril - var/from_tendril = FALSE /// Alternate icon for mobs that are angry var/icon_aggro = null /// If we want the mob to have 66% resist from burn damage projectiles diff --git a/code/modules/mob/living/carbon/carbon_procs.dm b/code/modules/mob/living/carbon/carbon_procs.dm index 04cdfde56c7..74cfb363469 100644 --- a/code/modules/mob/living/carbon/carbon_procs.dm +++ b/code/modules/mob/living/carbon/carbon_procs.dm @@ -247,6 +247,8 @@ /mob/living/carbon/proc/help_shake_act(mob/living/carbon/M) if(health < HEALTH_THRESHOLD_CRIT) return + if(SEND_SIGNAL(src, COMSIG_CARBON_PRE_MISC_HELP, M) & COMPONENT_BLOCK_MISC_HELP) + return if(src == M && ishuman(src)) check_self_for_injuries() return diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm index 08e43832e26..491e6dcdab8 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm @@ -144,9 +144,11 @@ Difficulty: Medium else var/mob/living/basic/mining/hivelord/legion/A if(enraged) - A = new /mob/living/basic/mining/hivelord/legion/advanced/tendril(loc) + A = new /mob/living/basic/mining/hivelord/legion/advanced(loc) + ADD_TRAIT(A, TRAIT_FROM_TENDRIL, INNATE_TRAIT) else - A = new /mob/living/basic/mining/hivelord/legion/tendril(loc) + A = new /mob/living/basic/mining/hivelord/legion(loc) + ADD_TRAIT(A, TRAIT_FROM_TENDRIL, INNATE_TRAIT) A.ai_controller.set_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET, target) A.ai_controller.set_blackboard_key(BB_FRIENDS_LIST, friends) A.faction = faction diff --git a/code/modules/mob/living/simple_animal/hostile/mining/goliath.dm b/code/modules/mob/living/simple_animal/hostile/mining/goliath.dm deleted file mode 100644 index dfd0795b891..00000000000 --- a/code/modules/mob/living/simple_animal/hostile/mining/goliath.dm +++ /dev/null @@ -1,197 +0,0 @@ -//A slow but strong beast that tries to stun using its tentacles -/mob/living/simple_animal/hostile/asteroid/goliath - name = "goliath" - desc = "A massive beast that uses long tentacles to ensnare its prey, threatening them is not advised under any conditions." - icon = 'icons/mob/lavaland/lavaland_monsters.dmi' - icon_state = "Goliath" - icon_living = "Goliath" - icon_aggro = "Goliath_alert" - icon_dead = "Goliath_dead" - icon_gib = "syndicate_gib" - mob_biotypes = MOB_ORGANIC | MOB_BEAST - move_to_delay = 40 - ranged = TRUE - ranged_cooldown_time = 120 - friendly = "wails at" - speak_emote = list("bellows") - speed = 3 - maxHealth = 300 - health = 300 - harm_intent_damage = 1 //Only the manliest of men can kill a Goliath with only their fists. - obj_damage = 100 - melee_damage_lower = 25 - melee_damage_upper = 25 - attacktext = "pulverizes" - attack_sound = 'sound/weapons/punch1.ogg' - throw_message = "does nothing to the rocky hide of the" - vision_range = 5 - move_force = MOVE_FORCE_VERY_STRONG - move_resist = MOVE_FORCE_VERY_STRONG - pull_force = MOVE_FORCE_VERY_STRONG - var/pre_attack = FALSE - var/pre_attack_icon = "Goliath_preattack" - loot = list(/obj/item/stack/sheet/animalhide/goliath_hide) - footstep_type = FOOTSTEP_MOB_HEAVY - contains_xeno_organ = TRUE - surgery_container = /datum/xenobiology_surgery_container/goliath - -/mob/living/simple_animal/hostile/asteroid/goliath/Life() - . = ..() - handle_preattack() - -/mob/living/simple_animal/hostile/asteroid/goliath/proc/handle_preattack() - if(ranged_cooldown <= world.time + ranged_cooldown_time * 0.25 && !pre_attack) - pre_attack++ - if(!pre_attack || stat || AIStatus == AI_IDLE) - return - icon_state = pre_attack_icon - -/mob/living/simple_animal/hostile/asteroid/goliath/revive() - ..() - anchored = TRUE - -/mob/living/simple_animal/hostile/asteroid/goliath/death(gibbed) - move_force = MOVE_FORCE_DEFAULT - move_resist = MOVE_RESIST_DEFAULT - pull_force = PULL_FORCE_DEFAULT - ..(gibbed) - -/mob/living/simple_animal/hostile/asteroid/goliath/OpenFire() - var/tturf = get_turf(target) - if(!isturf(tturf)) - return - if(get_dist(src, target) <= 7)//Screen range check, so you can't get tentacle'd offscreen - visible_message("[src] digs its tentacles under [target]!") - new /obj/effect/temp_visual/goliath_tentacle/original(tturf, src) - ranged_cooldown = world.time + ranged_cooldown_time - icon_state = icon_aggro - pre_attack = FALSE - -/mob/living/simple_animal/hostile/asteroid/goliath/adjustHealth(amount, updating_health = TRUE) - ranged_cooldown -= 10 - handle_preattack() - . = ..() - -/mob/living/simple_animal/hostile/asteroid/goliath/Aggro() - vision_range = aggro_vision_range - handle_preattack() - if(icon_state != icon_aggro) - icon_state = icon_aggro - -//Lavaland Goliath -/mob/living/simple_animal/hostile/asteroid/goliath/beast - desc = "A hulking, armor-plated beast with long tendrils arching from its back." - icon_state = "goliath" - icon_living = "goliath" - icon_aggro = "goliath" - icon_dead = "goliath_dead" - throw_message = "does nothing to the tough hide of the" - pre_attack_icon = "goliath2" - crusher_loot = /obj/item/crusher_trophy/goliath_tentacle - butcher_results = list(/obj/item/food/monstermeat/goliath = 2, /obj/item/stack/sheet/animalhide/goliath_hide = 1, /obj/item/stack/sheet/bone = 2) - loot = list() - stat_attack = UNCONSCIOUS - robust_searching = TRUE - - -/mob/living/simple_animal/hostile/asteroid/goliath/beast/ancient - name = "ancient goliath" - desc = "Goliaths are biologically immortal, and rare specimens have survived for centuries. This one is clearly ancient, and its tentacles constantly churn the earth around it." - icon_state = "Goliath" - icon_living = "Goliath" - icon_aggro = "Goliath_alert" - icon_dead = "Goliath_dead" - maxHealth = 400 - health = 400 - speed = 4 - pre_attack_icon = "Goliath_preattack" - throw_message = "does nothing to the rocky hide of the" - loot = list(/obj/item/stack/sheet/animalhide/goliath_hide) //A throwback to the asteroid days - butcher_results = list(/obj/item/food/monstermeat/goliath= 2, /obj/item/stack/sheet/bone = 2) - crusher_loot = /obj/item/crusher_trophy/goliath_tentacle/ancient - crusher_drop_mod = 100 //These things are rare (1/100 per spawner). You shouldn't have to hope for another stroke of luck to get it's trophy after finding it - wander = FALSE - var/list/cached_tentacle_turfs - var/turf/last_location - var/tentacle_recheck_cooldown = 100 - -/mob/living/simple_animal/hostile/asteroid/goliath/beast/ancient/Life() - . = ..() - if(!.) // dead - return - if(target && isturf(loc)) - if(!LAZYLEN(cached_tentacle_turfs) || loc != last_location || tentacle_recheck_cooldown <= world.time) - LAZYCLEARLIST(cached_tentacle_turfs) - last_location = loc - tentacle_recheck_cooldown = world.time + initial(tentacle_recheck_cooldown) - for(var/turf/simulated/floor/T in orange(4, loc)) - LAZYADD(cached_tentacle_turfs, T) - for(var/t in cached_tentacle_turfs) - if(isfloorturf(t)) - if(prob(10)) - new /obj/effect/temp_visual/goliath_tentacle(t, src) - else - cached_tentacle_turfs -= t - -/mob/living/simple_animal/hostile/asteroid/goliath/beast/tendril - fromtendril = TRUE - -//Tentacles -/obj/effect/temp_visual/goliath_tentacle - name = "goliath tentacle" - icon = 'icons/mob/lavaland/lavaland_monsters.dmi' - icon_state = "Goliath_tentacle_spawn" - layer = BELOW_MOB_LAYER - var/mob/living/spawner - -/obj/effect/temp_visual/goliath_tentacle/Initialize(mapload, mob/living/new_spawner) - . = ..() - for(var/obj/effect/temp_visual/goliath_tentacle/T in loc) - if(T != src) - return INITIALIZE_HINT_QDEL - if(!QDELETED(new_spawner)) - spawner = new_spawner - if(ismineralturf(loc)) - var/turf/simulated/mineral/M = loc - M.gets_drilled() - deltimer(timerid) - timerid = addtimer(CALLBACK(src, PROC_REF(tripanim)), 7, TIMER_STOPPABLE) - -/obj/effect/temp_visual/goliath_tentacle/original/Initialize(mapload, new_spawner) - . = ..() - var/list/directions = GLOB.cardinal.Copy() - for(var/i in 1 to 3) - var/spawndir = pick_n_take(directions) - var/turf/T = get_step(src, spawndir) - if(T) - new /obj/effect/temp_visual/goliath_tentacle(T, spawner) - -/obj/effect/temp_visual/goliath_tentacle/proc/tripanim() - icon_state = "Goliath_tentacle_wiggle" - deltimer(timerid) - timerid = addtimer(CALLBACK(src, PROC_REF(trip)), 3, TIMER_STOPPABLE) - -/obj/effect/temp_visual/goliath_tentacle/proc/trip() - var/latched = FALSE - for(var/mob/living/L in loc) - if((!QDELETED(spawner) && spawner.faction_check_mob(L)) || L.stat == DEAD) - continue - visible_message("[src] grabs hold of [L]!") - L.Stun(10 SECONDS) - L.adjustBruteLoss(rand(10,15)) - latched = TRUE - if(!latched) - retract() - else - deltimer(timerid) - timerid = addtimer(CALLBACK(src, PROC_REF(retract)), 10, TIMER_STOPPABLE) - -/obj/effect/temp_visual/goliath_tentacle/proc/retract() - icon_state = "Goliath_tentacle_retract" - deltimer(timerid) - timerid = QDEL_IN(src, 7) - -/mob/living/simple_animal/hostile/asteroid/goliath/space - -/mob/living/simple_animal/hostile/asteroid/goliath/space/Process_Spacemove(movement_dir, continuous_move) - return TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/mining/mining.dm b/code/modules/mob/living/simple_animal/hostile/mining/mining.dm index 3e447222baf..4ba267e3448 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining/mining.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining/mining.dm @@ -14,7 +14,6 @@ a_intent = INTENT_HARM var/crusher_loot var/throw_message = "bounces off of" - var/fromtendril = FALSE see_in_dark = 8 lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE mob_size = MOB_SIZE_LARGE diff --git a/code/modules/procedural_mapping/mapGenerators/asteroid.dm b/code/modules/procedural_mapping/mapGenerators/asteroid.dm index d8ddacf542e..4aea5157724 100644 --- a/code/modules/procedural_mapping/mapGenerators/asteroid.dm +++ b/code/modules/procedural_mapping/mapGenerators/asteroid.dm @@ -19,10 +19,11 @@ //Monsters /datum/map_generator_module/splatter_layer/asteroid_monsters spawnableTurfs = list() - spawnableAtoms = list(/mob/living/basic/mining/basilisk = 10, \ - /mob/living/basic/mining/hivelord = 10, \ - /mob/living/simple_animal/hostile/asteroid/goliath = 10) - + spawnableAtoms = list( + /mob/living/basic/mining/basilisk = 10, + /mob/living/basic/mining/hivelord = 10, + /mob/living/basic/mining/goliath/space = 10, + ) // GENERATORS diff --git a/paradise.dme b/paradise.dme index 572bb04357f..7fab737b109 100644 --- a/paradise.dme +++ b/paradise.dme @@ -526,6 +526,7 @@ #include "code\datums\cache\powermonitor.dm" #include "code\datums\components\_component.dm" #include "code\datums\components\action_item_overlay.dm" +#include "code\datums\components\ai_has_target_timer.dm" #include "code\datums\components\ai_retaliate_advanced.dm" #include "code\datums\components\anti_magic.dm" #include "code\datums\components\basic_mob_aggro_emote.dm" @@ -2515,6 +2516,10 @@ #include "code\modules\mob\living\basic\hostile\giant_spider\giant_spider_ai.dm" #include "code\modules\mob\living\basic\hostile\gorilla\gorilla.dm" #include "code\modules\mob\living\basic\hostile\gorilla\gorilla_emote.dm" +#include "code\modules\mob\living\basic\lavaland\goliath\goliath.dm" +#include "code\modules\mob\living\basic\lavaland\goliath\goliath_actions.dm" +#include "code\modules\mob\living\basic\lavaland\goliath\goliath_ai.dm" +#include "code\modules\mob\living\basic\lavaland\goliath\tentacle.dm" #include "code\modules\mob\living\basic\minebots\minebot.dm" #include "code\modules\mob\living\basic\minebots\minebot_abilities.dm" #include "code\modules\mob\living\basic\minebots\minebot_ai.dm" @@ -2737,7 +2742,6 @@ #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\goliath.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" diff --git a/tools/ci/check_simplemob_additions.py b/tools/ci/check_simplemob_additions.py index 106fd087029..e6b9c27e54a 100644 --- a/tools/ci/check_simplemob_additions.py +++ b/tools/ci/check_simplemob_additions.py @@ -67,11 +67,6 @@ BURNDOWN_LIST = { "/mob/living/simple_animal/hostile/asteroid/elite/legionnairehead", "/mob/living/simple_animal/hostile/asteroid/elite/legionnairehead/xenobiology", "/mob/living/simple_animal/hostile/asteroid/elite/pandora", - "/mob/living/simple_animal/hostile/asteroid/goliath", - "/mob/living/simple_animal/hostile/asteroid/goliath/beast", - "/mob/living/simple_animal/hostile/asteroid/goliath/beast/ancient", - "/mob/living/simple_animal/hostile/asteroid/goliath/beast/tendril", - "/mob/living/simple_animal/hostile/asteroid/goliath/space", "/mob/living/simple_animal/hostile/clockwork_construct", "/mob/living/simple_animal/hostile/clockwork_construct/clockwork_marauder", "/mob/living/simple_animal/hostile/clockwork_construct/clockwork_marauder/hostile",