Goliath basic mob (#76754)
## About The Pull Request Converts Goliaths to the basic mob framework and gives them some new moves because I can't leave things well enough alone. I am planning on touching all the lavaland fauna and then maybe even the icebox ones if I haven't got bored. The Golaith is the first because it is iconic. https://www.youtube.com/watch?v=JNcKvMwT4-Q Here's me getting killed by one as a demonstration. Despite my poor performance I would contend that they aren't a _lot_ more dangerous, but they are a little more dangerous. The chief difference here is that they have two new attacks which they will only use in response to being attacked. If fired at from range, they will target the attacker with a line of tentacles (it doesn't track you, so is easily sidestepped). If attacked in melee, they will surround _themselves_ with tentacles, on a longer cooldown. Something else you may notice in this video: I discovered that basic mobs are actually _too smart_ to be Lavaland fauna. Typically (unlike their old form) a mob on our new AI system is smart enough to attack someone _the moment they come into range_ rather than only checking on predictable ticks, which would make using the Crusher an essentially unviable prospect. To counteract this, Goliaths now have a delayed attack component which gives you a visual warning and short duration to get out of range before they swing at you. I will probably put this on all mining fauna that get reworked, it wouldn't be a terrible thing to put on other mobs to be honest. Other changes: The goliath stun is now a status effect with _buckles_ you to the tentacle as if grabbed, as well as its previous effects. While this seems purely worse, any nearby helpers can now help-click on you to instantly remove the debuff. Experiencing the effect of a Lobstrosity Rush Gland makes you immune to being grabbed by tentacles and an implanted one will automatically trigger and free you if you are hit, and the explosive effect of Brimdust also causes the tentacle to retract (although you'd need to take damage for this to happen). Using the tools of the land, you can make these creatures less threatening. The ability for a Goliath to chain-apply the ability has now also been reduced, it won't refresh its duration if you are hit when already buckled. When not occupied hounding miners, Goliaths will intermittently dig up the asteroid sand and eat any worms that this produces. I also made some new sprites for riding a Goliath because they've been broken since the Lavaland mob update and also kind of were ugly before then anyway:  Other code changes: - I made an element which only lets an attached object move every x seconds. This is because Goliaths are far too slow to use the speed system (the glide just looks bugged as hell) but one thing I am invested in when converting these is to make sure that they share the same behaviour when player or AI controlled. This is disabled while you're riding them because it was interminably slow. - The Goliath tentacle trail uses a supertype object now shared with the Meteor Heart which did something kind of similar. ## Why It's Good For The Game It begins the process of moving one of our larger subsets of NPCs onto the newer framework for NPC behaviour. It adds a little bit more life to an iconic but slightly uninteresting foe which mostly just walked at you slowly. This PR contains a few components I expect to apply more widely to other mobs in the future. ## Changelog 🆑 refactor: Goliaths now use the Basic Mob framework, please report any unusual behaviour. add: Goliaths learned a couple of new attacks which they will use in self-defence. balance: Help-clicking a miner grabbed by Goliath tentacles will immediately free them, as will the effect of several items you can scavenge from around Lavaland. image: New sprites for the Goliath saddle. /🆑
@@ -496,7 +496,7 @@
|
||||
/turf/open/floor/carpet/blue/lavaland,
|
||||
/area/ruin/unpowered)
|
||||
"Fg" = (
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/beast,
|
||||
/mob/living/basic/mining/goliath,
|
||||
/obj/effect/decal/cleanable/blood/old,
|
||||
/turf/open/misc/asteroid/basalt/lava_land_surface,
|
||||
/area/lavaland/surface/outdoors)
|
||||
|
||||
@@ -4376,7 +4376,7 @@
|
||||
/turf/open/floor/iron/smooth_edge,
|
||||
/area/mine/laborcamp/quarters)
|
||||
"zS" = (
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/beast,
|
||||
/mob/living/basic/mining/goliath,
|
||||
/turf/open/misc/asteroid/basalt/lava_land_surface,
|
||||
/area/lavaland/surface/outdoors)
|
||||
"zU" = (
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
/turf/open/misc/asteroid,
|
||||
/area/shuttle/escape/meteor)
|
||||
"f" = (
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath,
|
||||
/mob/living/basic/mining/goliath/ancient,
|
||||
/turf/open/misc/asteroid,
|
||||
/area/shuttle/escape/meteor)
|
||||
"g" = (
|
||||
|
||||
@@ -309,3 +309,8 @@
|
||||
//Festivus AI keys
|
||||
/// Key where we store the charging apc ability
|
||||
#define BB_FESTIVE_APC "BB_festive_apc"
|
||||
|
||||
/// 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"
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
#define BASIC_MOB_MAX_STAMINALOSS 200
|
||||
|
||||
///Basic mob flags
|
||||
|
||||
/// Delete mob upon death
|
||||
#define DEL_ON_DEATH (1<<0)
|
||||
/// Rotate mob 180 degrees while it is dead
|
||||
#define FLIP_ON_DEATH (1<<1)
|
||||
/// Mob remains dense while dead
|
||||
#define REMAIN_DENSE_WHILE_DEAD (1<<2)
|
||||
/// Mob can be set on fire
|
||||
#define FLAMMABLE_MOB (1<<3)
|
||||
/// Mob never takes damage from unarmed attacks
|
||||
#define IMMUNE_TO_FISTS (1<<4)
|
||||
|
||||
/// Temporary trait applied when an attack forecast animation has completed
|
||||
#define TRAIT_BASIC_ATTACK_FORECAST "trait_basic_attack_forecast"
|
||||
#define INTERACTION_BASIC_ATTACK_FORCEAST "interaction_basic_attack_forecast"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/// Fired by a mob which has been grabbed by a goliath
|
||||
#define COMSIG_GOLIATH_TENTACLED_GRABBED "comsig_goliath_tentacle_grabbed"
|
||||
/// Fired by a goliath tentacle which is returning to the earth
|
||||
#define COMSIG_GOLIATH_TENTACLE_RETRACTING "comsig_goliath_tentacle_retracting"
|
||||
/// Fired by a mob which has triggered a brimdust explosion from itself (not the mobs that get hit)
|
||||
#define COMSIG_BRIMDUST_EXPLOSION "comsig_brimdust_explosion"
|
||||
@@ -614,6 +614,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
#define TRAIT_VOIDSTORM_IMMUNE "voidstorm_immune"
|
||||
#define TRAIT_WEATHER_IMMUNE "weather_immune" //Immune to ALL weather effects.
|
||||
|
||||
/// Cannot be grabbed by goliath tentacles
|
||||
#define TRAIT_TENTACLE_IMMUNE "tentacle_immune"
|
||||
|
||||
//non-mob traits
|
||||
/// Used for limb-based paralysis, where replacing the limb will fix it.
|
||||
#define TRAIT_PARALYSIS "paralysis"
|
||||
|
||||
@@ -50,8 +50,6 @@ multiple modular subtrees with behaviors
|
||||
// Movement related things here
|
||||
///Reference to the movement datum we use. Is a type on initialize but becomes a ref afterwards.
|
||||
var/datum/ai_movement/ai_movement = /datum/ai_movement/dumb
|
||||
///Cooldown until next movement
|
||||
COOLDOWN_DECLARE(movement_cooldown)
|
||||
///Delay between movements. This is on the controller so we can keep the movement datum singleton
|
||||
var/movement_delay = 0.1 SECONDS
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
/datum/ai_behavior/find_and_set/perform(seconds_per_tick, datum/ai_controller/controller, set_key, locate_path, search_range)
|
||||
. = ..()
|
||||
var/atom/current_target = controller.blackboard[set_key]
|
||||
if (!QDELETED(current_target))
|
||||
return
|
||||
var/find_this_thing = search_tactic(controller, locate_path, search_range)
|
||||
if(find_this_thing)
|
||||
controller.set_blackboard_key(set_key, find_this_thing)
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Delays outgoing attacks which are directed at mobs to give players time to get out of the way
|
||||
*/
|
||||
/datum/component/basic_mob_attack_telegraph
|
||||
/// Time to wait before attack can complete
|
||||
var/telegraph_duration
|
||||
/// Overlay which we display over targets
|
||||
var/mutable_appearance/target_overlay
|
||||
/// Our current target, if we have one
|
||||
var/mob/living/current_target
|
||||
/// Callback executed when we start aiming at something
|
||||
var/datum/callback/on_began_forecast
|
||||
|
||||
/datum/component/basic_mob_attack_telegraph/Initialize(
|
||||
telegraph_icon = 'icons/mob/telegraphing/telegraph.dmi',
|
||||
telegraph_state = ATTACK_EFFECT_BITE,
|
||||
telegraph_duration = 0.3 SECONDS,
|
||||
datum/callback/on_began_forecast,
|
||||
)
|
||||
. = ..()
|
||||
if (!isbasicmob(parent))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
target_overlay = mutable_appearance(telegraph_icon, telegraph_state)
|
||||
src.telegraph_duration = telegraph_duration
|
||||
src.on_began_forecast = on_began_forecast
|
||||
|
||||
/datum/component/basic_mob_attack_telegraph/RegisterWithParent()
|
||||
. = ..()
|
||||
RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(on_attack))
|
||||
|
||||
/datum/component/basic_mob_attack_telegraph/UnregisterFromParent()
|
||||
if (current_target)
|
||||
forget_target(current_target)
|
||||
QDEL_NULL(target_overlay)
|
||||
REMOVE_TRAIT(parent, TRAIT_BASIC_ATTACK_FORECAST, REF(src))
|
||||
UnregisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)
|
||||
return ..()
|
||||
|
||||
/// When we attempt to attack, check if it is allowed
|
||||
/datum/component/basic_mob_attack_telegraph/proc/on_attack(mob/living/basic/source, atom/target)
|
||||
SIGNAL_HANDLER
|
||||
if (!isliving(target))
|
||||
return
|
||||
if (HAS_TRAIT_FROM(source, TRAIT_BASIC_ATTACK_FORECAST, REF(src)))
|
||||
REMOVE_TRAIT(source, TRAIT_BASIC_ATTACK_FORECAST, REF(src))
|
||||
return
|
||||
|
||||
if (!DOING_INTERACTION(source, INTERACTION_BASIC_ATTACK_FORCEAST))
|
||||
INVOKE_ASYNC(src, PROC_REF(delayed_attack), source, target)
|
||||
return COMPONENT_HOSTILE_NO_ATTACK
|
||||
|
||||
/// Perform an attack after a delay
|
||||
/datum/component/basic_mob_attack_telegraph/proc/delayed_attack(mob/living/basic/source, mob/living/target)
|
||||
current_target = target
|
||||
target.add_overlay(target_overlay)
|
||||
RegisterSignal(target, COMSIG_QDELETING, PROC_REF(forget_target))
|
||||
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(target_moved))
|
||||
|
||||
on_began_forecast?.Invoke(target)
|
||||
if (!do_after(source, delay = telegraph_duration, target = source, interaction_key = INTERACTION_BASIC_ATTACK_FORCEAST))
|
||||
forget_target(target)
|
||||
return
|
||||
if (!current_target) // They got out of the way :(
|
||||
return
|
||||
ADD_TRAIT(source, TRAIT_BASIC_ATTACK_FORECAST, REF(src))
|
||||
source.melee_attack(current_target)
|
||||
forget_target(current_target)
|
||||
|
||||
/// The guy we're trying to attack moved, is he still in range?
|
||||
/datum/component/basic_mob_attack_telegraph/proc/target_moved(mob/living/target)
|
||||
SIGNAL_HANDLER
|
||||
if (in_range(parent, target))
|
||||
return
|
||||
forget_target(target)
|
||||
|
||||
/// The guy we're trying to attack isn't a valid target any more
|
||||
/datum/component/basic_mob_attack_telegraph/proc/forget_target(atom/target)
|
||||
SIGNAL_HANDLER
|
||||
current_target = null
|
||||
target.cut_overlay(target_overlay)
|
||||
UnregisterSignal(target, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED))
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Automatically triggers a linked ability at a target who attacks us.
|
||||
* The ability might not necessarily be on our mob.
|
||||
* Make sure that /datum/element/relay_attackers is also present or you'll never receive the triggering signal.
|
||||
*/
|
||||
/datum/component/revenge_ability
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
/// The ability to use when we are attacked
|
||||
var/datum/action/cooldown/ability
|
||||
/// Optional datum for validating targets
|
||||
var/datum/targetting_datum/targetting
|
||||
/// Trigger only if target is at least this far away
|
||||
var/min_range
|
||||
/// Trigger only if target is at least this close
|
||||
var/max_range
|
||||
/// Target the ability at ourself instead of at the offender
|
||||
var/target_self
|
||||
|
||||
/datum/component/revenge_ability/Initialize(datum/action/cooldown/ability, datum/targetting_datum/targetting, min_range = 0, max_range = INFINITY, target_self = FALSE)
|
||||
. = ..()
|
||||
if (!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
src.ability = ability
|
||||
src.targetting = targetting
|
||||
src.min_range = min_range
|
||||
src.max_range = max_range
|
||||
src.target_self = target_self
|
||||
|
||||
RegisterSignal(ability, COMSIG_QDELETING, PROC_REF(ability_destroyed))
|
||||
|
||||
/datum/component/revenge_ability/RegisterWithParent()
|
||||
. = ..()
|
||||
RegisterSignal(parent, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_attacked))
|
||||
|
||||
/datum/component/revenge_ability/UnregisterFromParent()
|
||||
UnregisterSignal(parent, COMSIG_ATOM_WAS_ATTACKED)
|
||||
if (ability)
|
||||
UnregisterSignal(ability, COMSIG_QDELETING)
|
||||
return ..()
|
||||
|
||||
/// If we were attacked, get revenge
|
||||
/datum/component/revenge_ability/proc/on_attacked(mob/living/victim, atom/attacker)
|
||||
SIGNAL_HANDLER
|
||||
var/atom/ability_user = ability.owner
|
||||
var/distance = get_dist(ability_user, attacker)
|
||||
if (distance < min_range || distance > max_range)
|
||||
return
|
||||
if (targetting && !targetting.can_attack(victim, attacker))
|
||||
return
|
||||
INVOKE_ASYNC(ability, TYPE_PROC_REF(/datum/action/cooldown, InterceptClickOn), ability_user, null, (target_self) ? ability_user : attacker)
|
||||
|
||||
/// For whatever reason we lost our linked ability so we can drop this behaviour
|
||||
/datum/component/revenge_ability/proc/ability_destroyed(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
qdel(src)
|
||||
@@ -200,6 +200,11 @@
|
||||
return FALSE
|
||||
riding_offsets["[index]"] = offsets
|
||||
|
||||
/datum/component/riding/proc/set_vehicle_offsets(list/offsets)
|
||||
if(!islist(offsets))
|
||||
return FALSE
|
||||
directional_vehicle_offsets = offsets
|
||||
|
||||
/**
|
||||
* This proc is used to see if we have the appropriate key to drive this atom, if such a key is needed. Returns FALSE if we don't have what we need to drive.
|
||||
*
|
||||
|
||||
@@ -378,12 +378,24 @@
|
||||
|
||||
/datum/component/riding/creature/goliath
|
||||
keytype = /obj/item/key/lasso
|
||||
vehicle_move_delay = 4
|
||||
|
||||
/datum/component/riding/creature/goliath/Initialize(mob/living/riding_mob, force, ride_check_flags, potion_boost)
|
||||
. = ..()
|
||||
var/mob/living/basic/mining/goliath/goliath = parent
|
||||
goliath.RemoveElement(/datum/element/move_cooldown, move_delay = goliath.movement_delay)
|
||||
|
||||
/datum/component/riding/creature/goliath/Destroy(force, silent)
|
||||
var/mob/living/basic/mining/goliath/goliath = parent
|
||||
goliath.AddElement(/datum/element/move_cooldown, move_delay = goliath.movement_delay)
|
||||
return ..()
|
||||
|
||||
/datum/component/riding/creature/goliath/handle_specials()
|
||||
. = ..()
|
||||
set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 8), TEXT_SOUTH = list(0, 8), TEXT_EAST = list(-2, 8), TEXT_WEST = list(2, 8)))
|
||||
set_vehicle_offsets(list(TEXT_NORTH = list(-12, 0), TEXT_SOUTH = list(-12, 0), TEXT_EAST = list(-12, 0), TEXT_WEST = list(-12, 0)))
|
||||
set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 12), TEXT_SOUTH = list(0, 12), TEXT_EAST = list(-4, 12), TEXT_WEST = list(3, 12)))
|
||||
set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER)
|
||||
set_vehicle_dir_layer(NORTH, OBJ_LAYER)
|
||||
set_vehicle_dir_layer(NORTH, ABOVE_MOB_LAYER)
|
||||
set_vehicle_dir_layer(EAST, OBJ_LAYER)
|
||||
set_vehicle_dir_layer(WEST, OBJ_LAYER)
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
/// Remove weakrefs to atoms which have been killed or deleted without us picking it up somehow
|
||||
/datum/component/spawner/proc/validate_references()
|
||||
for (var/datum/weakref/weak_thing as anything in spawned_things)
|
||||
var/atom/previously_spawned = weak_thing.resolve()
|
||||
var/atom/previously_spawned = weak_thing?.resolve()
|
||||
if (!previously_spawned)
|
||||
spawned_things -= weak_thing
|
||||
continue
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Allows something to move only every x interval
|
||||
* For instances where they'd otherwise need to move so slowly that the glide would look stupid
|
||||
* Does not differentiate between voluntary and involuntary movement so this is beneficial in some niche circumstances
|
||||
*/
|
||||
/datum/element/move_cooldown
|
||||
element_flags = ELEMENT_BESPOKE
|
||||
argument_hash_start_idx = 2
|
||||
/// Time to wait between moves
|
||||
var/move_delay
|
||||
/// List of refs to atoms vs when they can next move
|
||||
var/list/next_move_cache = list()
|
||||
|
||||
/datum/element/move_cooldown/Attach(datum/target, move_delay = 1 SECONDS)
|
||||
. = ..()
|
||||
if (!ismovable(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
src.move_delay = move_delay
|
||||
next_move_cache[REF(target)] = 0
|
||||
RegisterSignal(target, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(tried_move))
|
||||
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
|
||||
|
||||
/datum/element/move_cooldown/Detach(datum/source)
|
||||
UnregisterSignal(source, list(COMSIG_MOVABLE_PRE_MOVE, COMSIG_MOVABLE_MOVED))
|
||||
next_move_cache -= REF(source)
|
||||
return ..()
|
||||
|
||||
/// Called when something we're tracking tries to move, check if it's allowed
|
||||
/datum/element/move_cooldown/proc/tried_move(atom/movable/source, new_loc)
|
||||
SIGNAL_HANDLER
|
||||
if (source.pulledby || source.throwing || !isturf(new_loc) || !isturf(source.loc))
|
||||
return
|
||||
if (world.time <= next_move_cache[REF(source)])
|
||||
return COMPONENT_MOVABLE_BLOCK_PRE_MOVE
|
||||
|
||||
/// Called when we moved successfully, start the cooldown
|
||||
/datum/element/move_cooldown/proc/on_moved(atom/movable/source, old_loc, direction, forced)
|
||||
SIGNAL_HANDLER
|
||||
if (forced || source.pulledby || source.throwing || !isturf(old_loc) || !isturf(source.loc))
|
||||
return // Can't really eliminate involuntary movement but we'll try
|
||||
if (!(source.movement_type & FLYING) && !source.has_gravity())
|
||||
return // Skip newtonian movement if it's not under control
|
||||
next_move_cache[REF(source)] = world.time + move_delay
|
||||
@@ -51,7 +51,12 @@
|
||||
/datum/map_generator/cave_generator/New()
|
||||
. = ..()
|
||||
if(!weighted_mob_spawn_list)
|
||||
weighted_mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/goldgrub = 1, /mob/living/simple_animal/hostile/asteroid/goliath = 5, /mob/living/simple_animal/hostile/asteroid/basilisk = 4, /mob/living/simple_animal/hostile/asteroid/hivelord = 3)
|
||||
weighted_mob_spawn_list = list(
|
||||
/mob/living/basic/mining/goliath/ancient = 5,
|
||||
/mob/living/simple_animal/hostile/asteroid/basilisk = 4,
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelord = 3,
|
||||
/mob/living/simple_animal/hostile/asteroid/goldgrub = 1,
|
||||
)
|
||||
mob_spawn_list = expand_weights(weighted_mob_spawn_list)
|
||||
mob_spawn_no_mega_list = expand_weights(weighted_mob_spawn_list - SPAWN_MEGAFAUNA)
|
||||
if(!weighted_megafauna_spawn_list)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
weighted_closed_turf_types = list(/turf/closed/mineral/random/volcanic = 1)
|
||||
|
||||
weighted_mob_spawn_list = list(
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/beast/random = 50,
|
||||
/mob/living/basic/mining/goliath/random = 50,
|
||||
/obj/structure/spawner/lavaland/goliath = 3,
|
||||
/mob/living/simple_animal/hostile/asteroid/basilisk/watcher/random = 40,
|
||||
/obj/structure/spawner/lavaland = 2,
|
||||
|
||||
@@ -255,6 +255,7 @@
|
||||
/mob/living/basic/cow/wisdom,
|
||||
/mob/living/basic/giant_spider,
|
||||
/mob/living/basic/giant_spider/hunter,
|
||||
/mob/living/basic/mining/goliath,
|
||||
/mob/living/basic/headslug,
|
||||
/mob/living/basic/killer_tomato,
|
||||
/mob/living/basic/lizard,
|
||||
@@ -269,7 +270,6 @@
|
||||
/mob/living/basic/stickman/dog,
|
||||
/mob/living/simple_animal/crab,
|
||||
/mob/living/simple_animal/hostile/asteroid/basilisk/watcher,
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/beast,
|
||||
/mob/living/simple_animal/hostile/bear,
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/independent,
|
||||
/mob/living/simple_animal/hostile/gorilla,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"a tendril hand can easily dig through basalt and obliterate hostile fauna, but your glove-wearing days are behind you...",
|
||||
)
|
||||
input_obj_or_mob = list(
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath,
|
||||
/mob/living/basic/mining/goliath,
|
||||
)
|
||||
output_organs = list(
|
||||
/obj/item/organ/internal/brain/goliath,
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/// An invisible effect which chases a target, spawning spikes every so often.
|
||||
/obj/effect/temp_visual/effect_trail
|
||||
name = "effect trail"
|
||||
desc = "An invisible effect, how did you examine this?"
|
||||
icon = 'icons/mob/silicon/cameramob.dmi'
|
||||
icon_state = "marker"
|
||||
duration = 15 SECONDS
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
/// Typepath of our spawned effect
|
||||
var/spawned_effect
|
||||
/// How often do we spawn our other effect?
|
||||
var/spawn_interval = 0.5 SECONDS
|
||||
/// Speed at which we chase target
|
||||
var/move_speed = 3
|
||||
/// What are we chasing?
|
||||
var/atom/target
|
||||
/// Stop spawning if we have this many effects already
|
||||
var/max_spawned = 20
|
||||
/// Do we home in after we started moving?
|
||||
var/homing = TRUE
|
||||
/// Handles chasing the target
|
||||
var/datum/move_loop/movement
|
||||
|
||||
/obj/effect/temp_visual/effect_trail/Initialize(mapload, atom/target)
|
||||
. = ..()
|
||||
if (!target)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
AddElement(/datum/element/floor_loving)
|
||||
AddComponent(/datum/component/spawner, spawn_types = list(spawned_effect), max_spawned = max_spawned, spawn_time = spawn_interval)
|
||||
src.target = target
|
||||
movement = SSmove_manager.move_towards(src, chasing = target, delay = move_speed, home = homing, timeout = duration, flags = MOVEMENT_LOOP_START_FAST)
|
||||
|
||||
RegisterSignal(target, COMSIG_QDELETING, PROC_REF(on_target_invalid))
|
||||
if (isliving(target))
|
||||
RegisterSignal(target, COMSIG_LIVING_DEATH, PROC_REF(on_target_invalid))
|
||||
|
||||
/// Destroy ourselves if the target is no longer valid
|
||||
/obj/effect/temp_visual/effect_trail/proc/on_target_invalid()
|
||||
SIGNAL_HANDLER
|
||||
target = null
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/temp_visual/effect_trail/Destroy()
|
||||
QDEL_NULL(movement)
|
||||
return ..()
|
||||
@@ -178,7 +178,7 @@ GLOBAL_LIST_INIT(leather_recipes, list ( \
|
||||
new/datum/stack_recipe("muzzle", /obj/item/clothing/mask/muzzle, 2, check_density = FALSE, category = CAT_ENTERTAINMENT), \
|
||||
new/datum/stack_recipe("basketball", /obj/item/toy/basketball, 20, check_density = FALSE, category = CAT_ENTERTAINMENT), \
|
||||
new/datum/stack_recipe("baseball", /obj/item/toy/beach_ball/baseball, 3, check_density = FALSE, category = CAT_ENTERTAINMENT), \
|
||||
new/datum/stack_recipe("saddle", /obj/item/saddle, 5, check_density = FALSE, category = CAT_EQUIPMENT), \
|
||||
new/datum/stack_recipe("saddle", /obj/item/goliath_saddle, 5, check_density = FALSE, category = CAT_EQUIPMENT), \
|
||||
new/datum/stack_recipe("leather shoes", /obj/item/clothing/shoes/laceup, 2, check_density = FALSE, category = CAT_CLOTHING), \
|
||||
new/datum/stack_recipe("cowboy boots", /obj/item/clothing/shoes/cowboy, 2, check_density = FALSE, category = CAT_CLOTHING), \
|
||||
new/datum/stack_recipe("botany gloves", /obj/item/clothing/gloves/botanic_leather, 3, check_density = FALSE, category = CAT_CLOTHING), \
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
|
||||
/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/simple_animal/hostile/asteroid/hivelord/legion/tendril)
|
||||
|
||||
@@ -53,7 +53,18 @@
|
||||
max_integrity = 200
|
||||
max_mobs = 15
|
||||
spawn_time = 15 SECONDS
|
||||
mob_types = list(/mob/living/simple_animal/hostile/retaliate/clown, /mob/living/simple_animal/hostile/retaliate/clown/fleshclown, /mob/living/simple_animal/hostile/retaliate/clown/clownhulk, /mob/living/simple_animal/hostile/retaliate/clown/longface, /mob/living/simple_animal/hostile/retaliate/clown/clownhulk/chlown, /mob/living/simple_animal/hostile/retaliate/clown/clownhulk/honcmunculus, /mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton, /mob/living/simple_animal/hostile/retaliate/clown/banana, /mob/living/simple_animal/hostile/retaliate/clown/honkling, /mob/living/simple_animal/hostile/retaliate/clown/lube)
|
||||
mob_types = list(
|
||||
/mob/living/simple_animal/hostile/retaliate/clown,
|
||||
/mob/living/simple_animal/hostile/retaliate/clown/banana,
|
||||
/mob/living/simple_animal/hostile/retaliate/clown/clownhulk,
|
||||
/mob/living/simple_animal/hostile/retaliate/clown/clownhulk/chlown,
|
||||
/mob/living/simple_animal/hostile/retaliate/clown/clownhulk/honcmunculus,
|
||||
/mob/living/simple_animal/hostile/retaliate/clown/fleshclown,
|
||||
/mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton,
|
||||
/mob/living/simple_animal/hostile/retaliate/clown/honkling,
|
||||
/mob/living/simple_animal/hostile/retaliate/clown/longface,
|
||||
/mob/living/simple_animal/hostile/retaliate/clown/lube,
|
||||
)
|
||||
spawn_text = "climbs out of"
|
||||
faction = list(FACTION_CLOWN)
|
||||
|
||||
@@ -65,7 +76,13 @@
|
||||
max_mobs = 3
|
||||
icon = 'icons/mob/simple/lavaland/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/simple_animal/hostile/asteroid/hivelord, /mob/living/simple_animal/hostile/asteroid/basilisk, /mob/living/basic/wumborian_fugu)
|
||||
mob_types = list(
|
||||
/mob/living/basic/mining/goliath/ancient,
|
||||
/mob/living/basic/wumborian_fugu,
|
||||
/mob/living/simple_animal/hostile/asteroid/basilisk,
|
||||
/mob/living/simple_animal/hostile/asteroid/goldgrub,
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelord,
|
||||
)
|
||||
faction = list(FACTION_MINING)
|
||||
|
||||
/obj/structure/spawner/mining/goldgrub
|
||||
@@ -76,7 +93,7 @@
|
||||
/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/ancient)
|
||||
|
||||
/obj/structure/spawner/mining/hivelord
|
||||
name = "hivelord den"
|
||||
@@ -102,7 +119,11 @@
|
||||
max_mobs = 15
|
||||
icon = 'icons/mob/simple/lavaland/nest.dmi'
|
||||
spawn_text = "crawls through"
|
||||
mob_types = list(/mob/living/basic/migo, /mob/living/basic/creature, /mob/living/basic/blankbody)
|
||||
mob_types = list(
|
||||
/mob/living/basic/blankbody,
|
||||
/mob/living/basic/creature,
|
||||
/mob/living/basic/migo,
|
||||
)
|
||||
faction = list(FACTION_NETHER)
|
||||
|
||||
/obj/structure/spawner/nether/Initialize(mapload)
|
||||
|
||||
@@ -171,6 +171,7 @@
|
||||
var/armor = target.run_armor_check(attack_flag = BOMB)
|
||||
target.apply_damage(damage_dealt, damagetype = BURN, blocked = armor, spread_damage = TRUE)
|
||||
|
||||
SEND_SIGNAL(owner, COMSIG_BRIMDUST_EXPLOSION)
|
||||
add_stacks(-1)
|
||||
|
||||
/// Slowdown applied when you are detonated on the space station
|
||||
|
||||
@@ -21,6 +21,14 @@
|
||||
if (owner.health <= HEALTH_DANGER_ZONE)
|
||||
trigger_organ_action()
|
||||
|
||||
/obj/item/organ/internal/monster_core/rush_gland/on_insert(mob/living/carbon/organ_owner)
|
||||
. = ..()
|
||||
RegisterSignal(organ_owner, COMSIG_GOLIATH_TENTACLED_GRABBED, PROC_REF(trigger_organ_action))
|
||||
|
||||
/obj/item/organ/internal/monster_core/rush_gland/on_remove(mob/living/carbon/organ_owner, special)
|
||||
. = ..()
|
||||
UnregisterSignal(organ_owner, COMSIG_GOLIATH_TENTACLED_GRABBED)
|
||||
|
||||
/obj/item/organ/internal/monster_core/rush_gland/on_triggered_internal()
|
||||
owner.apply_status_effect(/datum/status_effect/lobster_rush/extended)
|
||||
|
||||
@@ -44,14 +52,14 @@
|
||||
. = ..()
|
||||
RegisterSignal(owner, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_move))
|
||||
RegisterSignal(owner, COMSIG_MOVABLE_BUMP, PROC_REF(on_bump))
|
||||
ADD_TRAIT(owner, TRAIT_IGNORESLOWDOWN, TRAIT_STATUS_EFFECT(id))
|
||||
owner.add_traits(list(TRAIT_IGNORESLOWDOWN, TRAIT_TENTACLE_IMMUNE), TRAIT_STATUS_EFFECT(id))
|
||||
owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/lobster_rush)
|
||||
to_chat(owner, span_notice("You feel your blood pumping!"))
|
||||
|
||||
/datum/status_effect/lobster_rush/on_remove()
|
||||
. = ..()
|
||||
UnregisterSignal(owner, list(COMSIG_MOVABLE_PRE_MOVE, COMSIG_MOVABLE_BUMP))
|
||||
REMOVE_TRAIT(owner, TRAIT_IGNORESLOWDOWN, TRAIT_STATUS_EFFECT(id))
|
||||
owner.remove_traits(list(TRAIT_IGNORESLOWDOWN, TRAIT_TENTACLE_IMMUNE), TRAIT_STATUS_EFFECT(id))
|
||||
owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/lobster_rush)
|
||||
to_chat(owner, span_notice("Your pulse returns to normal."))
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
to_chat(user, span_danger("You [response_harm_simple] [src]!"))
|
||||
playsound(loc, attacked_sound, 25, TRUE, -1)
|
||||
var/obj/item/bodypart/arm/active_arm = user.get_active_hand()
|
||||
var/damage = rand(active_arm.unarmed_damage_low, active_arm.unarmed_damage_high)
|
||||
var/damage = (basic_mob_flags & IMMUNE_TO_FISTS) ? 0 : rand(active_arm.unarmed_damage_low, active_arm.unarmed_damage_high)
|
||||
|
||||
attack_threshold_check(damage)
|
||||
log_combat(user, src, "attacked")
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
icon_state = "bileworm"
|
||||
icon_living = "bileworm"
|
||||
icon_dead = "bileworm_dead"
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
mob_biotypes = MOB_BUG
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
/// Slow moving mob which attempts to immobilise its target
|
||||
/mob/living/basic/mining/goliath
|
||||
name = "goliath"
|
||||
desc = "A hulking, armor-plated beast with long tendrils arching from its back."
|
||||
icon = 'icons/mob/simple/lavaland/lavaland_monsters_wide.dmi'
|
||||
icon_state = "goliath"
|
||||
icon_living = "goliath"
|
||||
icon_dead = "goliath_dead"
|
||||
pixel_x = -12
|
||||
base_pixel_x = -12
|
||||
gender = MALE // Female ones are the bipedal elites
|
||||
basic_mob_flags = IMMUNE_TO_FISTS
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BEAST
|
||||
maxHealth = 300
|
||||
health = 300
|
||||
friendly_verb_continuous = "wails at"
|
||||
friendly_verb_simple = "wail at"
|
||||
speak_emote = list("bellows")
|
||||
obj_damage = 100
|
||||
melee_damage_lower = 25
|
||||
melee_damage_upper = 25
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
attack_verb_continuous = "pulverizes"
|
||||
attack_verb_simple = "pulverize"
|
||||
throw_blocked_message = "does nothing to the tough hide of"
|
||||
move_force = MOVE_FORCE_VERY_STRONG
|
||||
move_resist = MOVE_FORCE_VERY_STRONG
|
||||
pull_force = MOVE_FORCE_VERY_STRONG
|
||||
|
||||
ai_controller = /datum/ai_controller/basic_controller/goliath
|
||||
|
||||
crusher_loot = /obj/item/crusher_trophy/goliath_tentacle
|
||||
butcher_results = list(/obj/item/food/meat/slab/goliath = 2, /obj/item/stack/sheet/bone = 2)
|
||||
guaranteed_butcher_results = list(/obj/item/stack/sheet/animalhide/goliath_hide = 1)
|
||||
/// Goliath can only take a step in intervals of this
|
||||
var/movement_delay = 4 SECONDS
|
||||
/// Icon state to use when tentacles are available
|
||||
var/tentacle_warning_state = "goliath_preattack"
|
||||
/// Can this kind of goliath be tamed?
|
||||
var/tameable = TRUE
|
||||
/// Has this particular goliath been tamed?
|
||||
var/tamed = FALSE
|
||||
/// Can someone ride us around like a horse?
|
||||
var/saddled = FALSE
|
||||
/// 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/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, /obj/item/food/bait/worm)
|
||||
|
||||
/mob/living/basic/mining/goliath/Initialize(mapload)
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_TENTACLE_IMMUNE, INNATE_TRAIT)
|
||||
AddElement(/datum/element/ai_retaliate)
|
||||
AddElement(/datum/element/footstep, FOOTSTEP_MOB_HEAVY)
|
||||
AddElement(/datum/element/basic_eating, heal_amt = 10, food_types = goliath_foods)
|
||||
AddElement(/datum/element/move_cooldown, move_delay = movement_delay)
|
||||
AddComponent(/datum/component/basic_mob_attack_telegraph)
|
||||
AddComponentFrom(INNATE_TRAIT, /datum/component/shovel_hands)
|
||||
if (tameable)
|
||||
AddComponent(\
|
||||
/datum/component/tameable,\
|
||||
food_types = list(/obj/item/food/grown/ash_flora),\
|
||||
tame_chance = 10,\
|
||||
bonus_tame_chance = 5,\
|
||||
after_tame = CALLBACK(src, PROC_REF(tamed)),\
|
||||
)
|
||||
|
||||
tentacles = new (src)
|
||||
tentacles.Grant(src)
|
||||
var/datum/action/cooldown/tentacle_burst/melee_tentacles = new (src)
|
||||
melee_tentacles.Grant(src)
|
||||
AddComponent(/datum/component/revenge_ability, melee_tentacles, targetting = ai_controller.blackboard[BB_TARGETTING_DATUM], max_range = 1, target_self = TRUE)
|
||||
var/datum/action/cooldown/tentacle_grasp/ranged_tentacles = new (src)
|
||||
ranged_tentacles.Grant(src)
|
||||
AddComponent(/datum/component/revenge_ability, ranged_tentacles, targetting = ai_controller.blackboard[BB_TARGETTING_DATUM], min_range = 2, max_range = 9)
|
||||
|
||||
tentacles_ready()
|
||||
RegisterSignal(src, COMSIG_MOB_ABILITY_FINISHED, PROC_REF(used_ability))
|
||||
ai_controller.set_blackboard_key(BB_BASIC_FOODS, goliath_foods)
|
||||
ai_controller.set_blackboard_key(BB_GOLIATH_TENTACLES, tentacles)
|
||||
|
||||
/mob/living/basic/mining/goliath/Destroy()
|
||||
QDEL_NULL(tentacles)
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/mining/goliath/examine(mob/user)
|
||||
. = ..()
|
||||
if (saddled)
|
||||
. += span_info("Someone appears to have attached a saddle to this one.")
|
||||
|
||||
/mob/living/basic/mining/goliath/revive(full_heal_flags, excess_healing, force_grab_ghost)
|
||||
. = ..()
|
||||
if (!.)
|
||||
return
|
||||
move_force = initial(move_force)
|
||||
move_resist = initial(move_resist)
|
||||
pull_force = initial(pull_force)
|
||||
|
||||
/mob/living/basic/mining/goliath/death(gibbed)
|
||||
move_force = MOVE_FORCE_DEFAULT
|
||||
move_resist = MOVE_RESIST_DEFAULT
|
||||
pull_force = PULL_FORCE_DEFAULT
|
||||
return ..()
|
||||
|
||||
// Goliaths can summon tentacles more frequently as they take damage, scary.
|
||||
/mob/living/basic/mining/goliath/apply_damage(damage, damagetype, def_zone, blocked, forced, spread_damage, wound_bonus, bare_wound_bonus, sharpness, attack_direction, attacking_item)
|
||||
. = ..()
|
||||
if (!.)
|
||||
return
|
||||
if (damage <= 0)
|
||||
return
|
||||
if (tentacles.cooldown_time > 1 SECONDS)
|
||||
tentacles.cooldown_time -= 1 SECONDS
|
||||
|
||||
/mob/living/basic/mining/goliath/attackby(obj/item/attacking_item, mob/living/user, params)
|
||||
if (!istype(attacking_item, /obj/item/goliath_saddle))
|
||||
return ..()
|
||||
if (!tameable)
|
||||
balloon_alert(user, "doesn't fit!")
|
||||
return
|
||||
if (saddled)
|
||||
balloon_alert(user, "already saddled!")
|
||||
return
|
||||
if (!tamed)
|
||||
balloon_alert(user, "too rowdy!")
|
||||
return
|
||||
balloon_alert(user, "affixing saddle...")
|
||||
if (!do_after(user, delay = 5.5 SECONDS, target = src))
|
||||
return
|
||||
balloon_alert(user, "ready to ride")
|
||||
qdel(attacking_item)
|
||||
saddled = TRUE
|
||||
buckle_lying = 0
|
||||
add_overlay("goliath_saddled")
|
||||
AddElement(/datum/element/ridable, /datum/component/riding/creature/goliath)
|
||||
|
||||
/// 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/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)
|
||||
playsound(src, 'sound/magic/demon_attack1.ogg', vol = 50, vary = TRUE)
|
||||
Shake(1, 0, 1.5 SECONDS)
|
||||
|
||||
/// 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
|
||||
|
||||
/// Get ready for mounting
|
||||
/mob/living/basic/mining/goliath/proc/tamed()
|
||||
tamed = TRUE
|
||||
|
||||
// Copy entire faction rather than just placing user into faction, to avoid tentacle peril on station
|
||||
/mob/living/basic/mining/goliath/befriend(mob/living/new_friend)
|
||||
. = ..()
|
||||
faction = new_friend.faction.Copy()
|
||||
|
||||
/// Goliath which sometimes replaces itself with a rare variant
|
||||
/mob/living/basic/mining/goliath/random
|
||||
|
||||
/mob/living/basic/mining/goliath/random/Initialize(mapload)
|
||||
. = ..()
|
||||
if(!prob(1))
|
||||
return
|
||||
new /mob/living/basic/mining/goliath/ancient/immortal(loc)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/// Legacy Goliath mob with different sprites, largely the same behaviour
|
||||
/mob/living/basic/mining/goliath/ancient
|
||||
name = "ancient goliath"
|
||||
desc = "A massive beast that uses long tentacles to ensnare its prey, threatening them is not advised under any conditions."
|
||||
icon = 'icons/mob/simple/lavaland/lavaland_monsters_wide.dmi'
|
||||
icon_state = "ancient_goliath"
|
||||
icon_living = "ancient_goliath"
|
||||
icon_dead = "ancient_goliath_dead"
|
||||
tentacle_warning_state = "ancient_goliath_preattack"
|
||||
tameable = FALSE
|
||||
|
||||
/// Rare Goliath variant which occasionally replaces the normal mining mob, releases shitloads of tentacles
|
||||
/mob/living/basic/mining/goliath/ancient/immortal
|
||||
name = "immortal 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."
|
||||
maxHealth = 400
|
||||
health = 400
|
||||
crusher_drop_chance = 30 // Wow a whole 5% more likely, how generous
|
||||
/// 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/immortal/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/goliath_tentacle(target_turf)
|
||||
|
||||
/mob/living/basic/mining/goliath/ancient/immortal/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/immortal/proc/cache_nearby_turfs()
|
||||
COOLDOWN_START(src, retarget_turfs_cooldown, 10 SECONDS)
|
||||
LAZYCLEARLIST(tentacle_target_turfs)
|
||||
for(var/turf/open/floor in orange(4, loc))
|
||||
LAZYADD(tentacle_target_turfs, floor)
|
||||
|
||||
/// Use this to ride a goliath
|
||||
/obj/item/goliath_saddle
|
||||
name = "goliath saddle"
|
||||
desc = "This rough saddle will give you a serviceable seat upon a goliath! Provided you can get one to stand still."
|
||||
icon = 'icons/obj/mining.dmi'
|
||||
icon_state = "goliath_saddle"
|
||||
@@ -0,0 +1,85 @@
|
||||
/// Place some grappling tentacles underfoot
|
||||
/datum/action/cooldown/goliath_tentacles
|
||||
name = "Unleash Tentacles"
|
||||
desc = "Unleash burrowed tentacles at a targetted location, grappling targets after a delay."
|
||||
button_icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
|
||||
button_icon_state = "goliath_tentacle_wiggle"
|
||||
background_icon_state = "bg_demon"
|
||||
overlay_icon_state = "bg_demon_border"
|
||||
click_to_activate = TRUE
|
||||
cooldown_time = 12 SECONDS
|
||||
melee_cooldown_time = 0
|
||||
check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_INCAPACITATED
|
||||
/// Furthest range we can activate ability at
|
||||
var/max_range = 7
|
||||
|
||||
/datum/action/cooldown/goliath_tentacles/PreActivate(atom/target)
|
||||
target = get_turf(target)
|
||||
if (get_dist(owner, target) > max_range)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/action/cooldown/goliath_tentacles/Activate(atom/target)
|
||||
. = ..()
|
||||
new /obj/effect/goliath_tentacle(target)
|
||||
var/list/directions = GLOB.cardinals.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/goliath_tentacle(adjacent_target)
|
||||
|
||||
if (isliving(target))
|
||||
owner.visible_message(span_warning("[owner] digs its tentacles under [target]!"))
|
||||
return TRUE
|
||||
|
||||
/// Place grappling tentacles around you to grab attackers
|
||||
/datum/action/cooldown/tentacle_burst
|
||||
name = "Tentacle Burst"
|
||||
desc = "Unleash burrowed tentacles in an area around you, grappling targets after a delay."
|
||||
button_icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
|
||||
button_icon_state = "goliath_tentacle_wiggle"
|
||||
background_icon_state = "bg_demon"
|
||||
overlay_icon_state = "bg_demon_border"
|
||||
cooldown_time = 24 SECONDS
|
||||
melee_cooldown_time = 0
|
||||
check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_INCAPACITATED
|
||||
|
||||
/datum/action/cooldown/tentacle_burst/Activate(atom/target)
|
||||
. = ..()
|
||||
var/list/directions = GLOB.alldirs.Copy()
|
||||
for (var/dir in directions)
|
||||
var/turf/adjacent_target = get_step(target, dir)
|
||||
if(adjacent_target)
|
||||
new /obj/effect/goliath_tentacle(adjacent_target)
|
||||
owner.visible_message(span_warning("[owner] unleashes tentacles from the ground around it!"))
|
||||
return TRUE
|
||||
|
||||
/// Summon a line of tentacles towards the target
|
||||
/datum/action/cooldown/tentacle_grasp
|
||||
name = "Tentacle Grasp"
|
||||
desc = "Unleash burrowed tentacles in a line towards a targetted location, grappling targets after a delay."
|
||||
button_icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
|
||||
button_icon_state = "goliath_tentacle_wiggle"
|
||||
background_icon_state = "bg_demon"
|
||||
overlay_icon_state = "bg_demon_border"
|
||||
click_to_activate = TRUE
|
||||
cooldown_time = 12 SECONDS
|
||||
melee_cooldown_time = 0
|
||||
check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_INCAPACITATED
|
||||
|
||||
/datum/action/cooldown/tentacle_grasp/Activate(atom/target)
|
||||
. = ..()
|
||||
new /obj/effect/temp_visual/effect_trail/burrowed_tentacle(owner.loc, target)
|
||||
if (isliving(target))
|
||||
owner.visible_message(span_warning("[owner] reaches for [target] with its tentacles!"))
|
||||
return TRUE
|
||||
|
||||
/// An invisible effect which chases a target, spawning tentacles every so often.
|
||||
/obj/effect/temp_visual/effect_trail/burrowed_tentacle
|
||||
name = "burrowed_tentacle"
|
||||
duration = 2 SECONDS
|
||||
move_speed = 2
|
||||
homing = FALSE
|
||||
spawn_interval = 0.1 SECONDS
|
||||
spawned_effect = /obj/effect/goliath_tentacle
|
||||
@@ -0,0 +1,115 @@
|
||||
/datum/ai_controller/basic_controller/goliath
|
||||
blackboard = list(
|
||||
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items/goliath,
|
||||
)
|
||||
|
||||
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/simple_find_target,
|
||||
/datum/ai_planning_subtree/find_food,
|
||||
/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/goliath_find_diggable_turf,
|
||||
/datum/ai_planning_subtree/goliath_dig,
|
||||
)
|
||||
|
||||
/datum/targetting_datum/basic/allow_items/goliath
|
||||
stat_attack = HARD_CRIT
|
||||
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree/goliath
|
||||
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, targetting_datum_key, hiding_location_key, health_ratio_key)
|
||||
var/mob/living/target = controller.blackboard[target_key]
|
||||
// Interrupt attack chain to use tentacles, unless the target is already tentacled
|
||||
if (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())
|
||||
finish_action(controller, succeeded = FALSE)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/goliath_tentacles
|
||||
ability_key = BB_GOLIATH_TENTACLES
|
||||
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/goliath_tentacles/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/mob/living/target = controller.blackboard[target_key]
|
||||
if (!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
|
||||
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/SelectBehaviors(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))
|
||||
finish_action(controller, succeeded = FALSE)
|
||||
return
|
||||
|
||||
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))
|
||||
finish_action(controller, succeeded = FALSE) // Otherwise they won't perform idle wanderin
|
||||
return
|
||||
controller.set_blackboard_key(target_key, check_turf)
|
||||
finish_action(controller, succeeded = TRUE)
|
||||
|
||||
/// Return true if this is a turf we can dig
|
||||
/datum/ai_behavior/goliath_find_diggable_turf/proc/is_valid_turf(turf/check_turf)
|
||||
if (!isasteroidturf(check_turf))
|
||||
return FALSE
|
||||
var/turf/open/misc/asteroid/floor = check_turf
|
||||
return !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/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/turf/target_turf = controller.blackboard[target_key]
|
||||
if (QDELETED(target_turf))
|
||||
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 = 1 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
|
||||
basic_mob.melee_attack(target_turf)
|
||||
finish_action(controller, succeeded = TRUE)
|
||||
|
||||
/datum/ai_behavior/goliath_dig/finish_action(datum/ai_controller/controller, succeeded, target_key)
|
||||
. = ..()
|
||||
controller.clear_blackboard_key(target_key)
|
||||
@@ -0,0 +1,120 @@
|
||||
/// A tentacle which grabs you if you don't get away from it
|
||||
/obj/effect/goliath_tentacle
|
||||
name = "goliath tentacle"
|
||||
icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
|
||||
icon_state = "goliath_tentacle_spawn"
|
||||
layer = BELOW_MOB_LAYER
|
||||
plane = GAME_PLANE
|
||||
anchored = TRUE
|
||||
/// Timer for our current action stage
|
||||
var/action_timer
|
||||
/// Time in which to grab people
|
||||
var/grapple_time = 10 SECONDS
|
||||
/// Lower bound of damage to inflict
|
||||
var/min_damage = 10
|
||||
/// Upper bound of damage to inflict
|
||||
var/max_damage = 15
|
||||
|
||||
/obj/effect/goliath_tentacle/Initialize(mapload)
|
||||
. = ..()
|
||||
if (!isopenturf(loc) || isspaceturf(loc) || isopenspaceturf(loc))
|
||||
return INITIALIZE_HINT_QDEL
|
||||
for (var/obj/effect/goliath_tentacle/tentacle in loc)
|
||||
if (tentacle != src)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
if (ismineralturf(loc))
|
||||
var/turf/closed/mineral/floor = loc
|
||||
floor.gets_drilled()
|
||||
deltimer(action_timer)
|
||||
action_timer = addtimer(CALLBACK(src, PROC_REF(animate_grab)), 0.7 SECONDS, TIMER_STOPPABLE)
|
||||
|
||||
/obj/effect/goliath_tentacle/Destroy()
|
||||
deltimer(action_timer)
|
||||
return ..()
|
||||
|
||||
/// Change to next icon state and set up grapple
|
||||
/obj/effect/goliath_tentacle/proc/animate_grab()
|
||||
icon_state = "goliath_tentacle_wiggle"
|
||||
deltimer(action_timer)
|
||||
addtimer(CALLBACK(src, PROC_REF(grab)), 0.3 SECONDS, TIMER_STOPPABLE)
|
||||
|
||||
/// Grab everyone we share space with. If it's nobody, go home.
|
||||
/obj/effect/goliath_tentacle/proc/grab()
|
||||
for (var/mob/living/victim in loc)
|
||||
if (victim.stat == DEAD || HAS_TRAIT(victim, TRAIT_TENTACLE_IMMUNE))
|
||||
continue
|
||||
balloon_alert(victim, "grabbed")
|
||||
visible_message(span_danger("[src] grabs hold of [victim]!"))
|
||||
victim.adjustBruteLoss(rand(min_damage, max_damage))
|
||||
if (victim.apply_status_effect(/datum/status_effect/incapacitating/stun/goliath_tentacled, grapple_time, src))
|
||||
buckle_mob(victim, TRUE)
|
||||
SEND_SIGNAL(victim, COMSIG_GOLIATH_TENTACLED_GRABBED)
|
||||
if (!has_buckled_mobs())
|
||||
retract()
|
||||
return
|
||||
deltimer(action_timer)
|
||||
action_timer = addtimer(CALLBACK(src, PROC_REF(retract)), grapple_time, TIMER_STOPPABLE)
|
||||
|
||||
/// Play exit animation.
|
||||
/obj/effect/goliath_tentacle/proc/retract()
|
||||
if (icon_state == "goliath_tentacle_retract")
|
||||
return // Already retracting
|
||||
SEND_SIGNAL(src, COMSIG_GOLIATH_TENTACLE_RETRACTING)
|
||||
unbuckle_all_mobs(force = TRUE)
|
||||
icon_state = "goliath_tentacle_retract"
|
||||
deltimer(action_timer)
|
||||
action_timer = QDEL_IN_STOPPABLE(src, 0.7 SECONDS)
|
||||
|
||||
/obj/effect/goliath_tentacle/attack_hand(mob/living/user, list/modifiers)
|
||||
. = ..()
|
||||
if (. || !has_buckled_mobs())
|
||||
return
|
||||
retract()
|
||||
return TRUE
|
||||
|
||||
/// 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/goliath_tentacle/tentacle
|
||||
|
||||
/datum/status_effect/incapacitating/stun/goliath_tentacled/on_creation(mob/living/new_owner, set_duration, obj/effect/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, list(SIGNAL_ADDTRAIT(TRAIT_TENTACLE_IMMUNE), COMSIG_BRIMDUST_EXPLOSION), PROC_REF(release))
|
||||
RegisterSignals(tentacle, list(COMSIG_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), COMSIG_BRIMDUST_EXPLOSION))
|
||||
if (isnull(tentacle))
|
||||
return
|
||||
UnregisterSignal(tentacle, list(COMSIG_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
|
||||
release()
|
||||
source.visible_message(span_notice("[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
|
||||
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
|
||||
UnregisterSignal(tentacle, list(COMSIG_QDELETING, COMSIG_GOLIATH_TENTACLE_RETRACTING)) // No endless loops for us please
|
||||
tentacle = null
|
||||
release()
|
||||
@@ -1,6 +1,7 @@
|
||||
///prototype for mining mobs
|
||||
/mob/living/basic/mining
|
||||
combat_mode = TRUE
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
faction = list(FACTION_MINING)
|
||||
unsuitable_atmos_damage = 0
|
||||
minimum_survivable_temperature = 0
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
/mob/living/basic/cat_butcherer/Initialize(mapload)
|
||||
. = ..()
|
||||
apply_dynamic_human_appearance(src, mob_spawn_path = /obj/effect/mob_spawn/corpse/human/cat_butcher, l_hand = /obj/item/circular_saw, bloody_slots = ITEM_SLOT_GLOVES|ITEM_SLOT_OCLOTHING)
|
||||
AddElement(/datum/element/ai_retaliate)
|
||||
AddElement(/datum/element/death_drops, drop_on_death)
|
||||
RegisterSignal(src, COMSIG_HOSTILE_POST_ATTACKINGTARGET, PROC_REF(after_attack))
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
/datum/action/cooldown/chasing_spikes/Activate(atom/target)
|
||||
. = ..()
|
||||
playsound(owner, 'sound/magic/demon_attack1.ogg', vol = 100, vary = TRUE, pressure_affected = FALSE)
|
||||
var/obj/effect/temp_visual/spike_chaser/chaser = new(get_turf(owner), target)
|
||||
var/obj/effect/temp_visual/effect_trail/spike_chaser/chaser = new(get_turf(owner), target)
|
||||
LAZYADD(active_chasers, WEAKREF(chaser))
|
||||
RegisterSignal(chaser, COMSIG_QDELETING, PROC_REF(on_chaser_destroyed))
|
||||
|
||||
@@ -27,42 +27,9 @@
|
||||
return ..()
|
||||
|
||||
/// An invisible effect which chases a target, spawning spikes every so often.
|
||||
/obj/effect/temp_visual/spike_chaser
|
||||
/obj/effect/temp_visual/effect_trail/spike_chaser
|
||||
name = "spike chaser"
|
||||
desc = "An invisible effect, how did you examine this?"
|
||||
icon = 'icons/mob/silicon/cameramob.dmi'
|
||||
icon_state = "marker"
|
||||
duration = 15 SECONDS
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
/// Speed at which we chase target
|
||||
var/move_speed = 3
|
||||
/// What are we chasing?
|
||||
var/datum/weakref/target
|
||||
/// Handles chasing the target
|
||||
var/datum/move_loop/movement
|
||||
|
||||
/obj/effect/temp_visual/spike_chaser/Initialize(mapload, atom/target)
|
||||
. = ..()
|
||||
if (!target)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
AddElement(/datum/element/floor_loving)
|
||||
AddComponent(/datum/component/spawner, spawn_types = list(/obj/effect/temp_visual/emerging_ground_spike), spawn_time = 0.5 SECONDS)
|
||||
src.target = WEAKREF(target)
|
||||
movement = SSmove_manager.move_towards(src, chasing = target, delay = move_speed, home = TRUE, timeout = duration, flags = MOVEMENT_LOOP_START_FAST)
|
||||
|
||||
RegisterSignal(target, COMSIG_QDELETING, PROC_REF(on_target_invalid))
|
||||
if (isliving(target))
|
||||
RegisterSignal(target, COMSIG_LIVING_DEATH, PROC_REF(on_target_invalid))
|
||||
|
||||
/// Destroy ourselves if the target is no longer valid
|
||||
/obj/effect/temp_visual/spike_chaser/proc/on_target_invalid()
|
||||
SIGNAL_HANDLER
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/temp_visual/spike_chaser/Destroy()
|
||||
QDEL_NULL(movement)
|
||||
return ..()
|
||||
spawned_effect = /obj/effect/temp_visual/emerging_ground_spike
|
||||
|
||||
/// A spike comes out of the ground, dealing damage after a short delay
|
||||
/obj/effect/temp_visual/emerging_ground_spike
|
||||
|
||||
@@ -1390,6 +1390,7 @@
|
||||
/mob/living/basic/cow,
|
||||
/mob/living/basic/giant_spider,
|
||||
/mob/living/basic/giant_spider/hunter,
|
||||
/mob/living/basic/mining/goliath,
|
||||
/mob/living/basic/headslug,
|
||||
/mob/living/basic/killer_tomato,
|
||||
/mob/living/basic/lizard,
|
||||
@@ -1404,7 +1405,6 @@
|
||||
/mob/living/basic/stickman/dog,
|
||||
/mob/living/simple_animal/crab,
|
||||
/mob/living/simple_animal/hostile/asteroid/basilisk/watcher,
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/beast,
|
||||
/mob/living/simple_animal/hostile/bear,
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/independent,
|
||||
/mob/living/simple_animal/hostile/gorilla,
|
||||
|
||||
@@ -53,6 +53,10 @@
|
||||
var/rand_tent = 0
|
||||
var/list/mob/living/simple_animal/hostile/asteroid/elite/broodmother_child/children_list = list()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother/Initialize(mapload)
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_TENTACLE_IMMUNE, INNATE_TRAIT)
|
||||
|
||||
/datum/action/innate/elite_attack/tentacle_patch
|
||||
name = "Tentacle Patch"
|
||||
button_icon_state = "tentacle_patch"
|
||||
@@ -112,7 +116,7 @@
|
||||
var/tentacle_loc = spiral_range_turfs(5, get_turf(src))
|
||||
for(var/i in 1 to tentacle_amount)
|
||||
var/turf/t = pick_n_take(tentacle_loc)
|
||||
new /obj/effect/temp_visual/goliath_tentacle/broodmother(t, src)
|
||||
new /obj/effect/goliath_tentacle/broodmother(t, src)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother/proc/tentacle_patch(target)
|
||||
ranged_cooldown = world.time + 15
|
||||
@@ -120,7 +124,7 @@
|
||||
if(!isturf(tturf))
|
||||
return
|
||||
visible_message(span_warning("[src] digs its tentacles under [target]!"))
|
||||
new /obj/effect/temp_visual/goliath_tentacle/broodmother/patch(tturf, src)
|
||||
new /obj/effect/goliath_tentacle/broodmother/patch(tturf, src)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother/proc/spawn_children(target)
|
||||
ranged_cooldown = world.time + 40
|
||||
@@ -188,6 +192,10 @@
|
||||
status_flags = CANPUSH
|
||||
var/mob/living/simple_animal/hostile/asteroid/elite/broodmother/mother = null
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother_child/Initialize(mapload)
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_TENTACLE_IMMUNE, INNATE_TRAIT)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother_child/OpenFire(target)
|
||||
ranged_cooldown = world.time + 40
|
||||
var/tturf = get_turf(target)
|
||||
@@ -195,7 +203,7 @@
|
||||
return
|
||||
if(get_dist(src, target) <= 7)//Screen range check, so it can't attack people off-screen
|
||||
visible_message(span_warning("[src] digs one of its tentacles under [target]!"))
|
||||
new /obj/effect/temp_visual/goliath_tentacle/broodmother(tturf, src)
|
||||
new /obj/effect/goliath_tentacle/broodmother(tturf, src)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother_child/death()
|
||||
. = ..()
|
||||
@@ -205,35 +213,24 @@
|
||||
explosion(src, flame_range = 3, adminlog = FALSE)
|
||||
gib()
|
||||
|
||||
//Tentacles have less stun time compared to regular variant, to balance being able to use them much more often. Also, 10 more damage.
|
||||
/obj/effect/temp_visual/goliath_tentacle/broodmother/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_danger("[src] grabs hold of [L]!"))
|
||||
L.Stun(10)
|
||||
L.adjustBruteLoss(rand(30,35))
|
||||
latched = TRUE
|
||||
if(!latched)
|
||||
retract()
|
||||
else
|
||||
deltimer(timerid)
|
||||
timerid = addtimer(CALLBACK(src, PROC_REF(retract)), 10, TIMER_STOPPABLE)
|
||||
/obj/effect/goliath_tentacle/broodmother
|
||||
grapple_time = 1 SECONDS
|
||||
min_damage = 30
|
||||
max_damage = 35
|
||||
|
||||
/obj/effect/temp_visual/goliath_tentacle/broodmother/patch/Initialize(mapload, new_spawner)
|
||||
/obj/effect/goliath_tentacle/broodmother/patch/Initialize(mapload, new_spawner)
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, PROC_REF(createpatch))
|
||||
|
||||
/obj/effect/temp_visual/goliath_tentacle/broodmother/patch/proc/createpatch()
|
||||
/obj/effect/goliath_tentacle/broodmother/patch/proc/createpatch()
|
||||
var/tentacle_locs = spiral_range_turfs(1, get_turf(src))
|
||||
for(var/T in tentacle_locs)
|
||||
new /obj/effect/temp_visual/goliath_tentacle/broodmother(T, spawner)
|
||||
new /obj/effect/goliath_tentacle/broodmother(T)
|
||||
var/list/directions = GLOB.cardinals.Copy()
|
||||
for(var/i in directions)
|
||||
var/turf/T = get_step(get_turf(src), i)
|
||||
T = get_step(T, i)
|
||||
new /obj/effect/temp_visual/goliath_tentacle/broodmother(T, spawner)
|
||||
new /obj/effect/goliath_tentacle/broodmother(T)
|
||||
|
||||
// Broodmother's loot: Broodmother Tongue
|
||||
/obj/item/crusher_trophy/broodmother_tongue
|
||||
@@ -251,7 +248,7 @@
|
||||
|
||||
/obj/item/crusher_trophy/broodmother_tongue/on_mark_detonation(mob/living/target, mob/living/user)
|
||||
if(prob(bonus_value) && target.stat != DEAD)
|
||||
new /obj/effect/temp_visual/goliath_tentacle/broodmother/patch(get_turf(target), user)
|
||||
new /obj/effect/goliath_tentacle/broodmother/patch(get_turf(target), user)
|
||||
|
||||
/obj/item/crusher_trophy/broodmother_tongue/attack_self(mob/user)
|
||||
if(!isliving(user))
|
||||
|
||||
@@ -1,243 +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/simple/lavaland/lavaland_monsters_wide.dmi'
|
||||
icon_state = "ancient_goliath"
|
||||
icon_living = "ancient_goliath"
|
||||
icon_aggro = "ancient_goliath_alert"
|
||||
icon_dead = "ancient_goliath_dead"
|
||||
icon_gib = "syndicate_gib"
|
||||
pixel_x = -12
|
||||
base_pixel_x = -12
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BEAST
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
move_to_delay = 40
|
||||
ranged = 1
|
||||
ranged_cooldown_time = 120
|
||||
friendly_verb_continuous = "wails at"
|
||||
friendly_verb_simple = "wail at"
|
||||
speak_emote = list("bellows")
|
||||
speed = 3
|
||||
maxHealth = 300
|
||||
health = 300
|
||||
harm_intent_damage = 0
|
||||
obj_damage = 100
|
||||
melee_damage_lower = 25
|
||||
melee_damage_upper = 25
|
||||
attack_verb_continuous = "pulverizes"
|
||||
attack_verb_simple = "pulverize"
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
throw_message = "does nothing to the rocky hide of the"
|
||||
vision_range = 5
|
||||
aggro_vision_range = 9
|
||||
move_force = MOVE_FORCE_VERY_STRONG
|
||||
move_resist = MOVE_FORCE_VERY_STRONG
|
||||
pull_force = MOVE_FORCE_VERY_STRONG
|
||||
gender = MALE//lavaland elite goliath says that i'''' 't s female and i ''t s stronger because of sexual dimorphism, so normal goliaths should be male
|
||||
var/pre_attack = 0
|
||||
var/pre_attack_icon = "ancient_goliath_preattack"
|
||||
loot = list(/obj/item/stack/sheet/animalhide/goliath_hide)
|
||||
|
||||
footstep_type = FOOTSTEP_MOB_HEAVY
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/Life(seconds_per_tick = SSMOBS_DT, times_fired)
|
||||
. = ..()
|
||||
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(full_heal_flags = NONE, excess_healing = 0, force_grab_ghost = FALSE)//who the fuck anchors mobs
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
move_force = initial(move_force)
|
||||
move_resist = initial(move_resist)
|
||||
pull_force = initial(pull_force)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/death(gibbed)
|
||||
move_force = MOVE_FORCE_DEFAULT
|
||||
move_resist = MOVE_RESIST_DEFAULT
|
||||
pull_force = PULL_FORCE_DEFAULT
|
||||
return ..()
|
||||
|
||||
/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_warning("[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 = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
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
|
||||
name = "goliath"
|
||||
desc = "A hulking, armor-plated beast with long tendrils arching from its back."
|
||||
icon = 'icons/mob/simple/lavaland/lavaland_monsters_wide.dmi'
|
||||
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 = "goliath_preattack"
|
||||
crusher_loot = /obj/item/crusher_trophy/goliath_tentacle
|
||||
butcher_results = list(/obj/item/food/meat/slab/goliath = 2, /obj/item/stack/sheet/bone = 2)
|
||||
guaranteed_butcher_results = list(/obj/item/stack/sheet/animalhide/goliath_hide = 1)
|
||||
loot = list()
|
||||
stat_attack = HARD_CRIT
|
||||
robust_searching = 1
|
||||
|
||||
var/can_saddle = FALSE
|
||||
var/saddled = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/beast/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/grown/ash_flora), tame_chance = 10, bonus_tame_chance = 5, after_tame = CALLBACK(src, PROC_REF(tamed)))
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/beast/attackby(obj/item/O, mob/user, params)
|
||||
if(!istype(O, /obj/item/saddle) || saddled)
|
||||
return ..()
|
||||
|
||||
if(can_saddle && do_after(user,55,target=src))
|
||||
user.visible_message(span_notice("You manage to put [O] on [src], you can now ride [p_them()]."))
|
||||
qdel(O)
|
||||
saddled = TRUE
|
||||
buckle_lying = 0
|
||||
add_overlay("goliath_saddled")
|
||||
AddElement(/datum/element/ridable, /datum/component/riding/creature/goliath)
|
||||
else
|
||||
user.visible_message(span_warning("[src] is rocking around! You can't put the saddle on!"))
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/beast/proc/tamed(mob/living/tamer)
|
||||
can_saddle = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/beast/random/Initialize(mapload)
|
||||
. = ..()
|
||||
if(prob(1))
|
||||
new /mob/living/simple_animal/hostile/asteroid/goliath/beast/ancient(loc)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/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 = "ancient_goliath"
|
||||
icon_living = "ancient_goliath"
|
||||
icon_aggro = "ancient_goliath_alert"
|
||||
icon_dead = "ancient_goliath_dead"
|
||||
maxHealth = 400
|
||||
health = 400
|
||||
speed = 4
|
||||
pre_attack_icon = "ancient_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/meat/slab/goliath = 2, /obj/item/stack/sheet/bone = 2)
|
||||
guaranteed_butcher_results = list()
|
||||
crusher_drop_mod = 30
|
||||
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(seconds_per_tick = SSMOBS_DT, times_fired)
|
||||
. = ..()
|
||||
if(!.) // dead
|
||||
return
|
||||
if(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/open/T in orange(4, loc))
|
||||
LAZYADD(cached_tentacle_turfs, T)
|
||||
for(var/t in cached_tentacle_turfs)
|
||||
if(isopenturf(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
|
||||
from_spawner = TRUE
|
||||
|
||||
//tentacles
|
||||
/obj/effect/temp_visual/goliath_tentacle
|
||||
name = "goliath tentacle"
|
||||
icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
|
||||
icon_state = "goliath_tentacle_spawn"
|
||||
layer = BELOW_MOB_LAYER
|
||||
plane = GAME_PLANE
|
||||
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/closed/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.cardinals.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_danger("[src] grabs hold of [L]!"))
|
||||
L.Stun(100)
|
||||
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_STOPPABLE(src, 7)
|
||||
|
||||
/obj/item/saddle
|
||||
name = "saddle"
|
||||
desc = "This saddle will solve all your problems with being killed by lava beasts!"
|
||||
icon = 'icons/obj/mining.dmi'
|
||||
icon_state = "goliath_saddle"
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
///dead goliath spawner
|
||||
/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/simple/lavaland/lavaland_monsters_wide.dmi'
|
||||
icon_state = "goliath_dead_helper"
|
||||
pixel_x = -12
|
||||
|
||||
@@ -19,9 +19,11 @@
|
||||
//Monsters
|
||||
/datum/map_generator_module/splatter_layer/asteroid_monsters
|
||||
spawnableTurfs = list()
|
||||
spawnableAtoms = list(/mob/living/simple_animal/hostile/asteroid/basilisk = 10, \
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelord = 10, \
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath = 10)
|
||||
spawnableAtoms = list(
|
||||
/mob/living/basic/mining/goliath/ancient = 10,
|
||||
/mob/living/simple_animal/hostile/asteroid/basilisk = 10,
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelord = 10,
|
||||
)
|
||||
|
||||
|
||||
// GENERATORS
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
/datum/map_generator_module/splatter_layer/lavaland_monsters
|
||||
spawnableTurfs = list()
|
||||
spawnableAtoms = list(/mob/living/simple_animal/hostile/asteroid/goliath/beast = 10,
|
||||
spawnableAtoms = list(/mob/living/basic/mining/goliath = 10,
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelord/legion = 10,
|
||||
/mob/living/simple_animal/hostile/asteroid/basilisk/watcher = 10)
|
||||
|
||||
|
||||
@@ -73,11 +73,6 @@
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/legionnairehead,
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/pandora,
|
||||
/mob/living/simple_animal/hostile/asteroid/goldgrub,
|
||||
/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/random,
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/beast/tendril,
|
||||
/mob/living/simple_animal/hostile/asteroid/gutlunch,
|
||||
/mob/living/simple_animal/hostile/asteroid/gutlunch/grublunch,
|
||||
/mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck,
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
|
||||
/obj/item/key/lasso
|
||||
name = "bone lasso"
|
||||
desc = "Perfect for taming all kinds of supernatural beasts! (Warning: only perfect for taming one kind of supernatural beast.)"
|
||||
desc = "The perfect tool for directing a Goliath! If only it made them move any faster..."
|
||||
force = 12
|
||||
icon_state = "lasso"
|
||||
inhand_icon_state = "chain"
|
||||
|
||||
|
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 57 KiB |
@@ -291,6 +291,7 @@
|
||||
#include "code\__DEFINES\dcs\signals\signals_light_eater.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_medical.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_mind.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_mining.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_mod.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_moveloop.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_movetype.dm"
|
||||
@@ -876,6 +877,7 @@
|
||||
#include "code\datums\components\attached_sticker.dm"
|
||||
#include "code\datums\components\aura_healing.dm"
|
||||
#include "code\datums\components\bakeable.dm"
|
||||
#include "code\datums\components\basic_mob_attack_telegraph.dm"
|
||||
#include "code\datums\components\beetlejuice.dm"
|
||||
#include "code\datums\components\blood_walk.dm"
|
||||
#include "code\datums\components\bloodysoles.dm"
|
||||
@@ -988,6 +990,7 @@
|
||||
#include "code\datums\components\religious_tool.dm"
|
||||
#include "code\datums\components\remote_materials.dm"
|
||||
#include "code\datums\components\rename.dm"
|
||||
#include "code\datums\components\revenge_ability.dm"
|
||||
#include "code\datums\components\rot.dm"
|
||||
#include "code\datums\components\rotation.dm"
|
||||
#include "code\datums\components\scope.dm"
|
||||
@@ -1237,6 +1240,7 @@
|
||||
#include "code\datums\elements\light_eater.dm"
|
||||
#include "code\datums\elements\loomable.dm"
|
||||
#include "code\datums\elements\mob_killed_tally.dm"
|
||||
#include "code\datums\elements\move_cooldown.dm"
|
||||
#include "code\datums\elements\movement_turf_changer.dm"
|
||||
#include "code\datums\elements\movetype_handler.dm"
|
||||
#include "code\datums\elements\nerfed_pulling.dm"
|
||||
@@ -1840,6 +1844,7 @@
|
||||
#include "code\game\objects\effects\spawners\random\trash.dm"
|
||||
#include "code\game\objects\effects\spawners\random\vending.dm"
|
||||
#include "code\game\objects\effects\temporary_visuals\cult.dm"
|
||||
#include "code\game\objects\effects\temporary_visuals\effect_trail.dm"
|
||||
#include "code\game\objects\effects\temporary_visuals\miscellaneous.dm"
|
||||
#include "code\game\objects\effects\temporary_visuals\temporary_visual.dm"
|
||||
#include "code\game\objects\effects\temporary_visuals\projectiles\impact.dm"
|
||||
@@ -4030,6 +4035,10 @@
|
||||
#include "code\modules\mob\living\basic\lavaland\bileworm\bileworm_instrument.dm"
|
||||
#include "code\modules\mob\living\basic\lavaland\bileworm\bileworm_loot.dm"
|
||||
#include "code\modules\mob\living\basic\lavaland\bileworm\bileworm_vileworm.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\pets\dog.dm"
|
||||
#include "code\modules\mob\living\basic\pets\fox.dm"
|
||||
#include "code\modules\mob\living\basic\pets\pet.dm"
|
||||
@@ -4334,7 +4343,6 @@
|
||||
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\brimdemon.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\curse_blob.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\goldgrub.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\goliath.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\gutlunch.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\hivelord.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\ice_demon.dm"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/beast : /mob/living/basic/mining/goliath{@OLD}
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/beast/random : /mob/living/basic/mining/goliath/random{@OLD}
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath : /mob/living/basic/mining/goliath/ancient{@OLD}
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/beast/ancient : /mob/living/basic/mining/goliath/ancient/immortal{@OLD}
|
||||
/obj/item/saddle : /obj/item/goliath_saddle{@OLD}
|
||||