Port goliaths to basic mobs, Round 2 (#30566)

* Port goliaths to basic mobs.

* linting whitespace

* more linting

* wtf

* Addresses reviews on prior PR, adjusts behavior for food searching

* Missing Comma

* Goliath aggro range

* Reduces goliath speed to 5 from 3

---------

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-10-21 15:27:27 -04:00
committed by GitHub
parent 28f7414c64
commit dc3f8f6cc9
26 changed files with 541 additions and 235 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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("<span class='warning'>[owner] digs its tentacles under [target]!</span>")
StartCooldown()
return TRUE

View File

@@ -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

View File

@@ -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("<span class='danger'>[src] grabs hold of [L]!</span>")
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("<span class='notice'>[helping] rips [source] from the tentacle's grasp!</span>")
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()

View File

@@ -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

View File

@@ -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("<span class='warning'>The skulls on [src] wail in anger as they flee from their dying host!</span>")
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"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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("<span class='warning'>[src] digs its tentacles under [target]!</span>")
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("<span class='danger'>[src] grabs hold of [L]!</span>")
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

View File

@@ -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

View File

@@ -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