Basic Heretic Mobs: The Rest of Them (#78757)

## About The Pull Request

Raw Prophet and Armsy had fun stuff going on and merited their own PRs,
but the rest of these guys are basically just statblocks with abilities
so I converted them all at once.

Rust Walkers are present in a ruin and so have new AI which will
actually use their abilities. They rust the area around where they spawn
and throw their rust blast at people.

I also gave Flesh Stalkers AI even though nobody has put them in a map
because I thought it would be cool. This adds an AI behaviour where if
they're not doing anything else they will turn into an animal and chill
until someone's been around them for a bit, before attacking. They will
also use EMP almost immediately upon performing their ambush, which
kills the lights in that room. Spooky!
To support this I needed to make some changes to let AI continue
processing and targetting correctly while shapeshifted.

I didn't give Maids or Ash Spirits AI because they'd be really boring.

Other changes:
I made the maid in the mirror flicker when it takes examine damage
because the `visible_message` says it does but despite having the power,
nobody made it actually flicker...

## Why It's Good For The Game

No more simple mob heretic summons.

## Changelog

🆑
refactor: Rust Walkers, Ash Spirits, Flesh Stalkers, and The Maid in the
Mirror now use the basic mob framework. Please report any unusual
behaviour.
/🆑

---------

Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
This commit is contained in:
Jacquerel
2023-10-06 16:06:22 -06:00
committed by GitHub
co-authored by MrMelbert
parent c3446fa542
commit 5e2c8459dd
26 changed files with 266 additions and 181 deletions
@@ -1984,10 +1984,7 @@
/obj/effect/decal/cleanable/glass,
/obj/item/shard,
/obj/item/stack/sheet/iron,
/mob/living/simple_animal/hostile/heretic_summon/rust_spirit{
AIStatus = 1;
stop_automated_movement = 0
},
/mob/living/basic/heretic_summon/rust_walker,
/turf/open/floor/plating/rust,
/area/ruin/space/has_grav/dangerous_research/lab)
"zR" = (
@@ -3717,10 +3714,7 @@
/turf/open/floor/engine/airless,
/area/ruin/space/has_grav/dangerous_research/maint)
"Xh" = (
/mob/living/simple_animal/hostile/heretic_summon/rust_spirit{
AIStatus = 1;
stop_automated_movement = 0
},
/mob/living/basic/heretic_summon/rust_walker,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/structure/cable,
@@ -3862,10 +3856,7 @@
/turf/open/floor/iron/white,
/area/ruin/space/has_grav/dangerous_research/medical)
"YZ" = (
/mob/living/simple_animal/hostile/heretic_summon/rust_spirit{
AIStatus = 1;
stop_automated_movement = 0
},
/mob/living/basic/heretic_summon/rust_walker,
/turf/open/floor/plating/rust,
/area/ruin/space/has_grav/dangerous_research/lab)
"Zc" = (
+2
View File
@@ -32,6 +32,8 @@
#define CAN_ACT_WHILE_DEAD (1<<1)
/// Stop processing while in a progress bar
#define PAUSE_DURING_DO_AFTER (1<<2)
/// Continue processing while in stasis
#define CAN_ACT_IN_STASIS (1<<3)
//Base Subtree defines
+3
View File
@@ -54,6 +54,9 @@
/// Generic key for a non-specific action
#define BB_GENERIC_ACTION "BB_generic_action"
/// Generic key for a shapeshifting action
#define BB_SHAPESHIFT_ACTION "BB_shapeshift_action"
///How long have we spent with no target?
#define BB_TARGETLESS_TIME "BB_targetless_time"
+1
View File
@@ -25,6 +25,7 @@
#define FOOTSTEP_MOB_SHOE "footstep_shoe"
#define FOOTSTEP_MOB_HUMAN "footstep_human" //Warning: Only works on /mob/living/carbon/human
#define FOOTSTEP_MOB_SLIME "footstep_slime"
#define FOOTSTEP_MOB_RUST "footstep_rust"
#define FOOTSTEP_OBJ_MACHINE "footstep_machine"
#define FOOTSTEP_OBJ_ROBOT "footstep_robot"
-2
View File
@@ -72,7 +72,6 @@ GLOBAL_LIST_INIT(phobia_mobs, list(
"doctors" = typecacheof(list(/mob/living/simple_animal/bot/medbot)),
"heresy" = typecacheof(list(
/mob/living/basic/heretic_summon,
/mob/living/simple_animal/hostile/heretic_summon,
)),
"insects" = typecacheof(list(
/mob/living/basic/cockroach,
@@ -99,7 +98,6 @@ GLOBAL_LIST_INIT(phobia_mobs, list(
/mob/living/simple_animal/bot/mulebot/paranormal,
/mob/living/simple_animal/hostile/construct,
/mob/living/simple_animal/hostile/dark_wizard,
/mob/living/simple_animal/hostile/heretic_summon,
/mob/living/simple_animal/hostile/skeleton,
/mob/living/simple_animal/hostile/wizard,
/mob/living/simple_animal/hostile/zombie,
@@ -18,7 +18,10 @@
if(!isliving(pawn))
return
var/mob/living/living_pawn = pawn
if(!(ai_traits & CAN_ACT_WHILE_DEAD) && IS_DEAD_OR_INCAP(living_pawn))
var/incap_flags = NONE
if (ai_traits & CAN_ACT_IN_STASIS)
incap_flags |= IGNORE_STASIS
if(!(ai_traits & CAN_ACT_WHILE_DEAD) && (living_pawn.incapacitated(incap_flags) || living_pawn.stat))
return FALSE
if(ai_traits & PAUSE_DURING_DO_AFTER && LAZYLEN(living_pawn.do_afters))
return FALSE
@@ -11,7 +11,8 @@
finish_action(controller, FALSE, ability_key, target_key)
return
var/mob/pawn = controller.pawn
var/result = ability.InterceptClickOn(pawn, null, target)
pawn.face_atom(target)
var/result = ability.Trigger(target = target)
finish_action(controller, result, ability_key, target_key)
/datum/ai_behavior/targeted_mob_ability/finish_action(datum/ai_controller/controller, succeeded, ability_key, target_key)
@@ -23,7 +23,8 @@
var/aggro_range = controller.blackboard[aggro_range_key] || vision_range
controller.clear_blackboard_key(target_key)
var/list/potential_targets = hearers(aggro_range, controller.pawn) - living_mob //Remove self, so we don't suicide
var/list/potential_targets = hearers(aggro_range, get_turf(controller.pawn)) - living_mob //Remove self, so we don't suicide
for(var/HM in typecache_filter_list(range(aggro_range, living_mob), hostile_machines)) //Can we see any hostile machines?
if(can_see(living_mob, HM, aggro_range))
@@ -0,0 +1,41 @@
/// Shapeshift when we have no target, until someone has been nearby for long enough
/datum/ai_planning_subtree/shapechange_ambush
operational_datums = list(/datum/component/ai_target_timer)
/// Key where we keep our ability
var/ability_key = BB_SHAPESHIFT_ACTION
/// Key where we keep our target
var/target_key = BB_BASIC_MOB_CURRENT_TARGET
/// How long to lull our target into a false sense of security
var/minimum_target_time = 8 SECONDS
/datum/ai_planning_subtree/shapechange_ambush/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/mob/living/living_pawn = controller.pawn
var/is_shifted = ismob(living_pawn.loc)
var/has_target = controller.blackboard_key_exists(target_key)
var/datum/action/cooldown/using_action = controller.blackboard[ability_key]
if (!is_shifted)
if (has_target)
return // We're busy
if (using_action?.IsAvailable())
controller.queue_behavior(/datum/ai_behavior/use_mob_ability/shapeshift, BB_SHAPESHIFT_ACTION) // Shift
return SUBTREE_RETURN_FINISH_PLANNING
if (!has_target || !using_action?.IsAvailable())
return SUBTREE_RETURN_FINISH_PLANNING // Lie in wait
var/time_on_target = controller.blackboard[BB_BASIC_MOB_HAS_TARGET_TIME] || 0
if (time_on_target < minimum_target_time)
return // Wait a bit longer
controller.queue_behavior(/datum/ai_behavior/use_mob_ability/shapeshift, BB_SHAPESHIFT_ACTION) // Surprise!
/// Selects a random shapeshift ability before shifting
/datum/ai_behavior/use_mob_ability/shapeshift
/datum/ai_behavior/use_mob_ability/shapeshift/setup(datum/ai_controller/controller, ability_key)
var/datum/action/cooldown/spell/shapeshift/using_action = controller.blackboard[ability_key]
if (!using_action?.IsAvailable())
return FALSE
if (isnull(using_action.shapeshift_type)) // If we don't have a shape then pick one, AI can't use context wheels
using_action.shapeshift_type = pick(using_action.possible_shapes)
return ..()
@@ -26,7 +26,7 @@
if(isnull(our_controller))
return FALSE
if(isturf(the_target) || !the_target) // bail out on invalids
if(isturf(the_target) || isnull(the_target)) // bail out on invalids
return FALSE
if(isobj(the_target.loc))
@@ -35,6 +35,8 @@
return FALSE
if(ismob(the_target)) //Target is in godmode, ignore it.
if(living_mob.loc == the_target)
return FALSE // We've either been eaten or are shapeshifted, let's assume the latter because we're still alive
var/mob/M = the_target
if(M.status_flags & GODMODE)
return FALSE
@@ -45,7 +47,7 @@
if(living_mob.see_invisible < the_target.invisibility) //Target's invisible to us, forget it
return FALSE
if(isturf(the_target.loc) && living_mob.z != the_target.z) // z check will always fail if target is in a mech
if(isturf(living_mob.loc) && isturf(the_target.loc) && living_mob.z != the_target.z) // z check will always fail if target is in a mech or pawn is shapeshifted or jaunting
return FALSE
if(isliving(the_target)) //Targeting vs living mobs
+2
View File
@@ -40,6 +40,8 @@
footstep_sounds = GLOB.heavyfootstep
if(FOOTSTEP_MOB_SHOE)
footstep_sounds = GLOB.footstep
if(FOOTSTEP_MOB_RUST)
footstep_sounds = 'sound/effects/footstep/rustystep1.ogg'
if(FOOTSTEP_MOB_SLIME)
footstep_sounds = 'sound/effects/footstep/slime1.ogg'
if(FOOTSTEP_OBJ_MACHINE)
@@ -99,7 +99,7 @@
return TRUE
/datum/action/cooldown/track_target/Trigger(trigger_flags)
/datum/action/cooldown/track_target/Trigger(trigger_flags, atom/target)
right_clicked = !!(trigger_flags & TRIGGER_SECONDARY_ACTION)
return ..()
@@ -294,7 +294,7 @@
/obj/item/pen = 1,
/obj/item/paper = 1,
)
mob_to_summon = /mob/living/simple_animal/hostile/heretic_summon/stalker
mob_to_summon = /mob/living/basic/heretic_summon/stalker
cost = 1
route = PATH_FLESH
poll_ignore_define = POLL_IGNORE_STALKER
@@ -71,7 +71,7 @@
/obj/item/bodypart/head = 1,
/obj/item/book = 1,
)
mob_to_summon = /mob/living/simple_animal/hostile/heretic_summon/ash_spirit
mob_to_summon = /mob/living/basic/heretic_summon/ash_spirit
cost = 1
route = PATH_SIDE
poll_ignore_define = POLL_IGNORE_ASH_SPIRIT
@@ -88,7 +88,7 @@
/obj/item/book = 1,
/obj/item/bodypart/head = 1,
)
mob_to_summon = /mob/living/simple_animal/hostile/heretic_summon/rust_spirit
mob_to_summon = /mob/living/basic/heretic_summon/rust_walker
cost = 1
route = PATH_SIDE
poll_ignore_define = POLL_IGNORE_RUST_SPIRIT
@@ -159,5 +159,5 @@
)
cost = 1
route = PATH_SIDE
mob_to_summon = /mob/living/simple_animal/hostile/heretic_summon/maid_in_the_mirror
mob_to_summon = /mob/living/basic/heretic_summon/maid_in_the_mirror
poll_ignore_define = POLL_IGNORE_MAID_IN_MIRROR
@@ -6,10 +6,10 @@
cooldown_time = 20 SECONDS
die_with_shapeshifted_form = FALSE
possible_shapes = list(
/mob/living/basic/heretic_summon/ash_spirit,
/mob/living/basic/heretic_summon/raw_prophet/ascended,
/mob/living/simple_animal/hostile/heretic_summon/rust_spirit,
/mob/living/simple_animal/hostile/heretic_summon/ash_spirit,
/mob/living/simple_animal/hostile/heretic_summon/stalker,
/mob/living/basic/heretic_summon/rust_walker,
/mob/living/basic/heretic_summon/stalker,
)
/datum/action/cooldown/spell/shapeshift/eldritch/ascension/do_shapeshift(mob/living/caster)
@@ -28,7 +28,7 @@
. = ..()
transform *= 3
if(isnull(monster_types))
monster_types = subtypesof(/mob/living/simple_animal/hostile/heretic_summon) + subtypesof(/mob/living/basic/heretic_summon) - monster_types_blacklist
monster_types = subtypesof(/mob/living/basic/heretic_summon) - monster_types_blacklist
if(!isnull(ascendant_mind))
ascendee = ascendant_mind
RegisterSignals(ascendant_mind.current, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING), PROC_REF(end_madness))
@@ -0,0 +1,25 @@
/**
* Player-only mob which is fast, can jaunt a short distance, and is dangerous at close range
*/
/mob/living/basic/heretic_summon/ash_spirit
name = "Ash Spirit"
real_name = "Ashy"
desc = "A manifestation of ash, trailing a perpetual cloud of short-lived cinders."
icon_state = "ash_walker"
icon_living = "ash_walker"
maxHealth = 75
health = 75
melee_damage_lower = 15
melee_damage_upper = 20
sight = SEE_TURFS
/mob/living/basic/heretic_summon/ash_spirit/Initialize(mapload)
. = ..()
var/static/list/actions_to_add = list(
/datum/action/cooldown/spell/fire_sworn,
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash,
/datum/action/cooldown/spell/pointed/cleave,
)
for (var/action in actions_to_add)
var/datum/action/cooldown/new_action = new action(src)
new_action.Grant(src)
@@ -0,0 +1,46 @@
/// Durable ambush mob with an EMP ability
/mob/living/basic/heretic_summon/stalker
name = "Flesh Stalker"
real_name = "Flesh Stalker"
desc = "An abomination cobbled together from varied remains. Its appearance changes slightly every time you blink."
icon_state = "stalker"
icon_living = "stalker"
maxHealth = 150
health = 150
melee_damage_lower = 15
melee_damage_upper = 20
sight = SEE_MOBS
ai_controller = /datum/ai_controller/basic_controller/stalker
/// Associative list of action types we would like to have, and what blackboard key (if any) to put it in
var/static/list/actions_to_add = list(
/datum/action/cooldown/spell/emp/eldritch = BB_GENERIC_ACTION,
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash = null,
/datum/action/cooldown/spell/shapeshift/eldritch = BB_SHAPESHIFT_ACTION,
)
/mob/living/basic/heretic_summon/stalker/Initialize(mapload)
. = ..()
AddComponent(/datum/component/ai_target_timer)
for (var/action_type in actions_to_add)
var/datum/action/new_action = new action_type(src)
new_action.Grant(src)
var/blackboard_key = actions_to_add[action_type]
if (!isnull(blackboard_key))
ai_controller?.set_blackboard_key(blackboard_key, new_action)
/// Changes shape and lies in wait when it has no target, uses EMP and attacks once it does
/datum/ai_controller/basic_controller/stalker
ai_traits = CAN_ACT_IN_STASIS
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
)
ai_movement = /datum/ai_movement/basic_avoidance
idle_behavior = /datum/idle_behavior/idle_random_walk
planning_subtrees = list(
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/shapechange_ambush,
/datum/ai_planning_subtree/use_mob_ability,
/datum/ai_planning_subtree/attack_obstacle_in_path,
/datum/ai_planning_subtree/basic_melee_attack_subtree,
)
@@ -1,11 +1,11 @@
// A summon which floats around the station incorporeally, and can appear in any mirror
/mob/living/simple_animal/hostile/heretic_summon/maid_in_the_mirror
/// Scout and assassin who can appear and disappear from glass surfaces. Damaged by being examined.
/mob/living/basic/heretic_summon/maid_in_the_mirror
name = "Maid in the Mirror"
real_name = "Maid in the Mirror"
desc = "A floating and flowing wisp of chilled air. Glancing at it causes it to shimmer slightly."
icon = 'icons/mob/simple/mob.dmi'
icon_state = "stand"
icon_living = "stand" // Placeholder sprite
icon_living = "stand" // Placeholder sprite... still
speak_emote = list("whispers")
movement_type = FLOATING
status_flags = CANSTUN | CANPUSH
@@ -16,36 +16,34 @@
melee_damage_upper = 16
sight = SEE_MOBS | SEE_OBJS | SEE_TURFS
death_message = "shatters and vanishes, releasing a gust of cold air."
loot = list(
/obj/item/shard,
/obj/effect/decal/cleanable/ash,
/obj/item/clothing/suit/armor/vest,
/obj/item/organ/internal/lungs,
)
actions_to_add = list(/datum/action/cooldown/spell/jaunt/mirror_walk)
/// Whether we take damage when we're examined
var/weak_on_examine = TRUE
/// The cooldown after being examined that the same mob cannot trigger it again
/// Whether we take damage when someone looks at us
var/harmed_by_examine = TRUE
/// How often being examined by a specific mob can hurt us
var/recent_examine_damage_cooldown = 10 SECONDS
/// A list of REFs to people who recently examined us
var/list/recent_examiner_refs = list()
/mob/living/simple_animal/hostile/heretic_summon/maid_in_the_mirror/death(gibbed)
/mob/living/basic/heretic_summon/Initialize(mapload)
. = ..()
var/static/list/loot = list(
/obj/effect/decal/cleanable/ash,
/obj/item/clothing/suit/armor/vest,
/obj/item/organ/internal/lungs,
/obj/item/shard,
)
AddElement(/datum/element/death_drops, loot)
var/datum/action/cooldown/spell/jaunt/mirror_walk/jaunt = new (src)
jaunt.Grant(src)
/mob/living/basic/heretic_summon/maid_in_the_mirror/death(gibbed)
var/turf/death_turf = get_turf(src)
death_turf.TakeTemperature(-40)
death_turf.TakeTemperature(-40) // Spooky
return ..()
// Examining them will harm them, on a cooldown.
/mob/living/simple_animal/hostile/heretic_summon/maid_in_the_mirror/examine(mob/user)
/mob/living/basic/heretic_summon/maid_in_the_mirror/examine(mob/user)
. = ..()
if(!weak_on_examine)
return
if(!isliving(user) || user.stat == DEAD)
return
if(IS_HERETIC_OR_MONSTER(user) || user == src)
if(!harmed_by_examine || user == src || user.stat == DEAD || !isliving(user) || IS_HERETIC_OR_MONSTER(user))
return
var/user_ref = REF(user)
@@ -62,7 +60,9 @@
recent_examiner_refs += user_ref
apply_damage(maxHealth * 0.1) // We take 10% of our health as damage upon being examined
playsound(src, 'sound/effects/ghost2.ogg', 40, TRUE)
addtimer(CALLBACK(src, PROC_REF(clear_recent_examiner), user_ref), recent_examine_damage_cooldown)
addtimer(CALLBACK(src, PROC_REF(clear_recent_examiner), user_ref), recent_examine_damage_cooldown, TIMER_DELETE_ME)
animate(src, alpha = 120, time = 0.5 SECONDS, easing = ELASTIC_EASING, loop = 2, flags = ANIMATION_PARALLEL)
animate(alpha = 255, time = 0.5 SECONDS, easing = ELASTIC_EASING)
// If we're examined on low enough health we die straight up
else
@@ -73,7 +73,7 @@
death()
/mob/living/simple_animal/hostile/heretic_summon/maid_in_the_mirror/proc/clear_recent_examiner(mob_ref)
/mob/living/basic/heretic_summon/maid_in_the_mirror/proc/clear_recent_examiner(mob_ref)
if(!(mob_ref in recent_examiner_refs))
return
@@ -0,0 +1,87 @@
/// Pretty simple mob which creates areas of rust and has a rust-creating projectile spell
/mob/living/basic/heretic_summon/rust_walker
name = "Rust Walker"
real_name = "Rusty"
desc = "A grinding, clanking construct which leaches life from its surroundings with every armoured step."
icon_state = "rust_walker_s"
base_icon_state = "rust_walker"
icon_living = "rust_walker_s"
maxHealth = 75
health = 75
melee_damage_lower = 15
melee_damage_upper = 20
sight = SEE_TURFS
speed = 1
ai_controller = /datum/ai_controller/basic_controller/rust_walker
/mob/living/basic/heretic_summon/rust_walker/Initialize(mapload)
. = ..()
AddElement(/datum/element/footstep, FOOTSTEP_MOB_RUST)
var/datum/action/cooldown/spell/aoe/rust_conversion/small/conversion = new(src)
conversion.Grant(src)
ai_controller?.set_blackboard_key(BB_GENERIC_ACTION, conversion)
var/datum/action/cooldown/spell/basic_projectile/rust_wave/short/wave = new(src)
wave.Grant(src)
ai_controller?.set_blackboard_key(BB_TARGETTED_ACTION, wave)
/mob/living/basic/heretic_summon/rust_walker/setDir(newdir)
. = ..()
update_appearance(UPDATE_ICON_STATE)
/mob/living/basic/heretic_summon/rust_walker/update_icon_state()
. = ..()
if(stat == DEAD) // We usually delete on death but just in case
return
if(dir & NORTH)
icon_state = "[base_icon_state]_n"
else if(dir & SOUTH)
icon_state = "[base_icon_state]_s"
icon_living = icon_state
/mob/living/basic/heretic_summon/rust_walker/Life(seconds_per_tick = SSMOBS_DT, times_fired)
if(stat == DEAD)
return ..()
var/turf/our_turf = get_turf(src)
if(HAS_TRAIT(our_turf, TRAIT_RUSTY))
adjustBruteLoss(-3 * seconds_per_tick)
return ..()
/// Converts unconverted terrain, sprays pocket sand around
/datum/ai_controller/basic_controller/rust_walker
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
)
ai_movement = /datum/ai_movement/basic_avoidance
idle_behavior = /datum/idle_behavior/idle_random_walk/rust
planning_subtrees = list(
/datum/ai_planning_subtree/use_mob_ability/rust_walker,
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/targeted_mob_ability,
/datum/ai_planning_subtree/attack_obstacle_in_path,
/datum/ai_planning_subtree/basic_melee_attack_subtree,
)
/// Moves a lot if healthy and on rust (to find more tiles to rust) or unhealthy and not on rust (to find healing rust)
/// Still moving in random directions though we're not really seeking it out
/datum/idle_behavior/idle_random_walk/rust
/datum/idle_behavior/idle_random_walk/rust/perform_idle_behavior(seconds_per_tick, datum/ai_controller/controller)
var/mob/living/our_mob = controller.pawn
var/turf/our_turf = get_turf(our_mob)
if (HAS_TRAIT(our_turf, TRAIT_RUSTY))
walk_chance = (our_mob.health < our_mob.maxHealth) ? 10 : 50
else
walk_chance = (our_mob.health < our_mob.maxHealth) ? 50 : 10
return ..()
/// Use if we're not stood on rust right now
/datum/ai_planning_subtree/use_mob_ability/rust_walker
/datum/ai_planning_subtree/use_mob_ability/rust_walker/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/turf/our_turf = get_turf(controller.pawn)
if (HAS_TRAIT(our_turf, TRAIT_RUSTY))
return
return ..()
@@ -1,120 +0,0 @@
/mob/living/simple_animal/hostile/heretic_summon
name = "Eldritch Demon"
real_name = "Eldritch Demon"
desc = "A horror from beyond this realm."
icon = 'icons/mob/nonhuman-player/eldritch_mobs.dmi'
gender = NEUTER
mob_biotypes = NONE
attack_sound = 'sound/weapons/punch1.ogg'
response_help_continuous = "thinks better of touching"
response_help_simple = "think better of touching"
response_disarm_continuous = "flails at"
response_disarm_simple = "flail at"
response_harm_continuous = "reaps"
response_harm_simple = "tears"
speak_emote = list("screams")
speak_chance = 1
speed = 0
combat_mode = TRUE
stop_automated_movement = TRUE
AIStatus = AI_OFF
// Sort of greenish brown, to match the vibeTM
lighting_cutoff_red = 20
lighting_cutoff_green = 25
lighting_cutoff_blue = 5
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
maxbodytemp = INFINITY
movement_type = GROUND
pressure_resistance = 100
del_on_death = TRUE
death_message = "implodes into itself."
loot = list(/obj/effect/gibspawner/human)
faction = list(FACTION_HERETIC)
simple_mob_flags = SILENCE_RANGED_MESSAGE
/// Innate spells that are added when a beast is created.
var/list/actions_to_add
/mob/living/simple_animal/hostile/heretic_summon/Initialize(mapload)
. = ..()
for(var/spell in actions_to_add)
var/datum/action/cooldown/spell/new_spell = new spell(src)
new_spell.Grant(src)
/mob/living/simple_animal/hostile/heretic_summon/rust_spirit
name = "Rust Walker"
real_name = "Rusty"
desc = "An incomprehensible abomination. Everywhere it steps, it appears to be actively seeping life out of its surroundings."
icon_state = "rust_walker_s"
icon_living = "rust_walker_s"
status_flags = CANPUSH
maxHealth = 75
health = 75
melee_damage_lower = 15
melee_damage_upper = 20
sight = SEE_TURFS
actions_to_add = list(
/datum/action/cooldown/spell/aoe/rust_conversion/small,
/datum/action/cooldown/spell/basic_projectile/rust_wave/short,
)
/mob/living/simple_animal/hostile/heretic_summon/rust_spirit/setDir(newdir)
. = ..()
if(newdir == NORTH)
icon_state = "rust_walker_n"
else if(newdir == SOUTH)
icon_state = "rust_walker_s"
update_appearance(UPDATE_ICON_STATE)
/mob/living/simple_animal/hostile/heretic_summon/rust_spirit/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE)
. = ..()
playsound(src, 'sound/effects/footstep/rustystep1.ogg', 100, TRUE)
/mob/living/simple_animal/hostile/heretic_summon/rust_spirit/Life(seconds_per_tick = SSMOBS_DT, times_fired)
if(stat == DEAD)
return ..()
var/turf/our_turf = get_turf(src)
if(HAS_TRAIT(our_turf, TRAIT_RUSTY))
adjustBruteLoss(-1.5 * seconds_per_tick, FALSE)
adjustFireLoss(-1.5 * seconds_per_tick, FALSE)
return ..()
/mob/living/simple_animal/hostile/heretic_summon/ash_spirit
name = "Ash Man"
real_name = "Ashy"
desc = "An incomprehensible abomination. As it moves, a thin trail of ash follows, appearing from seemingly nowhere."
icon_state = "ash_walker"
icon_living = "ash_walker"
status_flags = CANPUSH
maxHealth = 75
health = 75
melee_damage_lower = 15
melee_damage_upper = 20
sight = SEE_TURFS
actions_to_add = list(
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash,
/datum/action/cooldown/spell/pointed/cleave,
/datum/action/cooldown/spell/fire_sworn,
)
/mob/living/simple_animal/hostile/heretic_summon/stalker
name = "Flesh Stalker"
real_name = "Flesh Stalker"
desc = "An abomination made from several limbs and organs. Every moment you stare at it, it appears to shift and change unnaturally."
icon_state = "stalker"
icon_living = "stalker"
status_flags = CANPUSH
maxHealth = 150
health = 150
melee_damage_lower = 15
melee_damage_upper = 20
sight = SEE_MOBS
actions_to_add = list(
/datum/action/cooldown/spell/shapeshift/eldritch,
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash,
/datum/action/cooldown/spell/emp/eldritch,
)
@@ -103,11 +103,6 @@
/mob/living/simple_animal/hostile/guardian/ranged,
/mob/living/simple_animal/hostile/guardian/standard,
/mob/living/simple_animal/hostile/guardian/support,
/mob/living/simple_animal/hostile/heretic_summon,
/mob/living/simple_animal/hostile/heretic_summon/ash_spirit,
/mob/living/simple_animal/hostile/heretic_summon/maid_in_the_mirror,
/mob/living/simple_animal/hostile/heretic_summon/rust_spirit,
/mob/living/simple_animal/hostile/heretic_summon/stalker,
/mob/living/simple_animal/hostile/illusion,
/mob/living/simple_animal/hostile/illusion/escape,
/mob/living/simple_animal/hostile/illusion/mirage,
+5 -2
View File
@@ -827,6 +827,7 @@
#include "code\datums\ai\basic_mobs\basic_subtrees\move_to_cardinal.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\opportunistic_ventcrawler.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\ranged_skirmish.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\shapechange_ambush.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\simple_attack_target.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\simple_find_nearest_target_to_flee.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\simple_find_target.dm"
@@ -2938,7 +2939,6 @@
#include "code\modules\antagonists\heretic\magic\void_phase.dm"
#include "code\modules\antagonists\heretic\magic\void_pull.dm"
#include "code\modules\antagonists\heretic\magic\wave_of_desperation.dm"
#include "code\modules\antagonists\heretic\mobs\maid_in_mirror.dm"
#include "code\modules\antagonists\heretic\status_effects\buffs.dm"
#include "code\modules\antagonists\heretic\status_effects\debuffs.dm"
#include "code\modules\antagonists\heretic\status_effects\ghoul.dm"
@@ -4368,10 +4368,14 @@
#include "code\modules\mob\living\basic\farm_animals\goat\_goat.dm"
#include "code\modules\mob\living\basic\farm_animals\goat\goat_ai.dm"
#include "code\modules\mob\living\basic\farm_animals\goat\goat_subtypes.dm"
#include "code\modules\mob\living\basic\heretic\ash_spirit.dm"
#include "code\modules\mob\living\basic\heretic\fire_shark.dm"
#include "code\modules\mob\living\basic\heretic\flesh_stalker.dm"
#include "code\modules\mob\living\basic\heretic\flesh_worm.dm"
#include "code\modules\mob\living\basic\heretic\heretic_summon.dm"
#include "code\modules\mob\living\basic\heretic\maid_in_the_mirror.dm"
#include "code\modules\mob\living\basic\heretic\raw_prophet.dm"
#include "code\modules\mob\living\basic\heretic\rust_walker.dm"
#include "code\modules\mob\living\basic\heretic\star_gazer.dm"
#include "code\modules\mob\living\basic\icemoon\ice_whelp\ice_whelp.dm"
#include "code\modules\mob\living\basic\icemoon\ice_whelp\ice_whelp_abilities.dm"
@@ -4701,7 +4705,6 @@
#include "code\modules\mob\living\simple_animal\guardian\types\support.dm"
#include "code\modules\mob\living\simple_animal\hostile\alien.dm"
#include "code\modules\mob\living\simple_animal\hostile\dark_wizard.dm"
#include "code\modules\mob\living\simple_animal\hostile\heretic_monsters.dm"
#include "code\modules\mob\living\simple_animal\hostile\hostile.dm"
#include "code\modules\mob\living\simple_animal\hostile\illusion.dm"
#include "code\modules\mob\living\simple_animal\hostile\mimic.dm"
@@ -0,0 +1,4 @@
/mob/living/simple_animal/hostile/heretic_summon/ash_spirit : /mob/living/basic/heretic_summon/ash_spirit{@OLD}
/mob/living/simple_animal/hostile/heretic_summon/maid_in_the_mirror : /mob/living/basic/heretic_summon/maid_in_the_mirror{@OLD}
/mob/living/simple_animal/hostile/heretic_summon/rust_spirit : /mob/living/basic/heretic_summon/rust_walker{@OLD;AIStatus=@SKIP;stop_automated_movement=@SKIP}
/mob/living/simple_animal/hostile/heretic_summon/stalker : /mob/living/basic/heretic_summon/stalker{@OLD}