mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-28 07:38:05 +01:00
(IRIS PORT) Black Mesa Basic Mobs (#4632)
## About The Pull Request **_ALL THE CREDIT FOR THIS GOES TO NoNameGiven-05 FROM IRISSTATION FOR https://github.com/IrisSS13/IrisStation/pull/627._** EVERY Black Mesa mob has been refactored into a basic mob. Attached are videos of the new mob AI in action. <details> <summary>Bullsquid</summary> https://github.com/user-attachments/assets/a4e279be-c365-482f-b481-8cd5166d24c6 </details> <details> <summary>Gordon Freeman</summary> https://github.com/user-attachments/assets/b658641c-5bb0-4132-9020-81ded34ade1b </details> <details> <summary>Headcrab</summary> https://github.com/user-attachments/assets/ee6219af-fa56-42b4-ba14-de949f9f463b </details> <details> <summary>Houndeye</summary> https://github.com/user-attachments/assets/5ceea5b5-2f4d-4569-9d89-933f0ba668f2 </details> <details> <summary>Nihilanth</summary> https://github.com/user-attachments/assets/617f1f78-abee-457c-8dba-7d8767892d62 </details> <details> <summary>Vortigaunt</summary> https://github.com/user-attachments/assets/3ae36849-7788-40ff-8e14-036d0bf42301 </details> ## Why It's Good For The Game It makes the Half-Life gateway mobs actually *do* stuff. ## Proof Of Testing See above. ## Changelog 🆑 refactor: Refactored ALL the Black Mesa mobs into basic mobs. /🆑
This commit is contained in:
@@ -324,7 +324,7 @@
|
||||
/turf/open/misc/dirt/planet/xen,
|
||||
/area/awaymission/black_mesa/xen/nihilanth_computer)
|
||||
"adL" = (
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab,
|
||||
/mob/living/basic/blackmesa/xen/headcrab,
|
||||
/turf/open/floor/mineral/titanium/white,
|
||||
/area/awaymission/black_mesa/entrance)
|
||||
"adM" = (
|
||||
@@ -1800,7 +1800,7 @@
|
||||
/area/awaymission/black_mesa/security_outpost)
|
||||
"axm" = (
|
||||
/obj/structure/stone_tile/slab,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/gordon_freeman,
|
||||
/mob/living/basic/blackmesa/xen/gordon_freeman,
|
||||
/turf/open/misc/xen,
|
||||
/area/awaymission/black_mesa/xen/freeman_arena)
|
||||
"axn" = (
|
||||
@@ -2724,7 +2724,7 @@
|
||||
/obj/structure/chair/office{
|
||||
dir = 8
|
||||
},
|
||||
/mob/living/simple_animal/hostile/blackmesa/sec/ranged,
|
||||
/mob/living/basic/blackmesa/human/sec/ranged,
|
||||
/turf/open/floor/iron,
|
||||
/area/awaymission/black_mesa/entrance_lobby)
|
||||
"aJd" = (
|
||||
@@ -3609,7 +3609,7 @@
|
||||
/turf/open/floor/mineral/titanium/white,
|
||||
/area/awaymission/black_mesa/tram_room)
|
||||
"aUu" = (
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/nihilanth,
|
||||
/mob/living/basic/blackmesa/xen/nihilanth,
|
||||
/obj/structure/marker_beacon/green,
|
||||
/turf/open/floor/vault/alien,
|
||||
/area/awaymission/black_mesa/xen/nihilanth_arena)
|
||||
@@ -6126,7 +6126,7 @@
|
||||
/turf/open/misc/xen,
|
||||
/area/awaymission/black_mesa/xen/acid_lake_hallway)
|
||||
"eXf" = (
|
||||
/mob/living/simple_animal/hostile/blackmesa/sec,
|
||||
/mob/living/basic/blackmesa/human/sec,
|
||||
/turf/open/floor/iron/smooth_large,
|
||||
/area/awaymission/black_mesa/high_security_armory)
|
||||
"eXU" = (
|
||||
@@ -6449,7 +6449,7 @@
|
||||
/turf/open/floor/iron,
|
||||
/area/awaymission/black_mesa/entrance_internal_hall)
|
||||
"fwW" = (
|
||||
/mob/living/simple_animal/hostile/blackmesa/blackops/ranged,
|
||||
/mob/living/basic/blackmesa/human/blackops/ranged,
|
||||
/turf/open/floor/iron/smooth,
|
||||
/area/awaymission/black_mesa/black_ops_button)
|
||||
"fxF" = (
|
||||
@@ -7477,7 +7477,7 @@
|
||||
/turf/open/misc/ironsand/black_mesa,
|
||||
/area/awaymission/black_mesa/hecu_zone_towards_facility)
|
||||
"hBp" = (
|
||||
/mob/living/simple_animal/hostile/blackmesa/sec/ranged,
|
||||
/mob/living/basic/blackmesa/human/sec/ranged,
|
||||
/turf/open/floor/iron/textured,
|
||||
/area/awaymission/black_mesa/high_security_sec_point)
|
||||
"hBz" = (
|
||||
@@ -9140,7 +9140,7 @@
|
||||
},
|
||||
/area/awaymission/black_mesa/black_ops_downstairs_atrium)
|
||||
"kMw" = (
|
||||
/mob/living/simple_animal/hostile/blackmesa/sec/ranged,
|
||||
/mob/living/basic/blackmesa/human/sec/ranged,
|
||||
/turf/open/floor/iron/smooth_large,
|
||||
/area/awaymission/black_mesa/high_security_servers)
|
||||
"kNj" = (
|
||||
@@ -9254,7 +9254,7 @@
|
||||
/turf/closed/wall/r_wall,
|
||||
/area/awaymission/black_mesa/genetics_sec)
|
||||
"kWX" = (
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/bullsquid,
|
||||
/mob/living/basic/blackmesa/xen/bullsquid,
|
||||
/turf/open/misc/xen,
|
||||
/area/awaymission/black_mesa/xen/acid_lake)
|
||||
"kXt" = (
|
||||
@@ -9946,7 +9946,7 @@
|
||||
"mnn" = (
|
||||
/obj/structure/alien/weeds/xen,
|
||||
/obj/structure/cable,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/hev,
|
||||
/mob/living/basic/blackmesa/xen/headcrab_zombie/hev,
|
||||
/turf/open/floor/plating,
|
||||
/area/awaymission/black_mesa/resonant_chamber)
|
||||
"mnS" = (
|
||||
@@ -13886,7 +13886,7 @@
|
||||
/area/awaymission/black_mesa/xen/acid_lake_building)
|
||||
"uaK" = (
|
||||
/obj/machinery/light/cold,
|
||||
/mob/living/simple_animal/hostile/blackmesa/blackops/ranged,
|
||||
/mob/living/basic/blackmesa/human/blackops/ranged,
|
||||
/turf/open/floor/iron/textured_large,
|
||||
/area/awaymission/black_mesa/black_ops_downstairs_atrium)
|
||||
"ubi" = (
|
||||
@@ -14279,7 +14279,7 @@
|
||||
/obj/structure/deployable_barricade/metal{
|
||||
dir = 8
|
||||
},
|
||||
/mob/living/simple_animal/hostile/blackmesa/blackops/ranged,
|
||||
/mob/living/basic/blackmesa/human/blackops/ranged,
|
||||
/turf/open/misc/ironsand/black_mesa,
|
||||
/area/awaymission/black_mesa/hecu_zone_towards_facility)
|
||||
"uSX" = (
|
||||
@@ -14351,7 +14351,7 @@
|
||||
/area/awaymission/black_mesa/xen/acid_lake_hallway)
|
||||
"uWN" = (
|
||||
/obj/structure/alien/weeds/xen,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/scientist,
|
||||
/mob/living/basic/blackmesa/xen/headcrab_zombie/scientist,
|
||||
/turf/open/floor/iron/textured,
|
||||
/area/awaymission/black_mesa/science_labs)
|
||||
"uWO" = (
|
||||
@@ -15401,7 +15401,7 @@
|
||||
dir = 8
|
||||
},
|
||||
/obj/structure/alien/weeds/xen,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/scientist,
|
||||
/mob/living/basic/blackmesa/xen/headcrab_zombie/scientist,
|
||||
/turf/open/floor/iron/textured,
|
||||
/area/awaymission/black_mesa/science_labs)
|
||||
"wUw" = (
|
||||
@@ -15450,7 +15450,7 @@
|
||||
/turf/open/floor/iron/smooth,
|
||||
/area/awaymission/black_mesa/genetics_elevator)
|
||||
"wYo" = (
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/bullsquid,
|
||||
/mob/living/basic/blackmesa/xen/bullsquid,
|
||||
/turf/open/water/xen_acid,
|
||||
/area/awaymission/black_mesa/xen/acid_lake)
|
||||
"wYs" = (
|
||||
|
||||
@@ -59106,7 +59106,7 @@
|
||||
/obj/effect/decal/cleanable/dirt{
|
||||
icon_state = "dirt-flat-1"
|
||||
},
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/bullsquid,
|
||||
/mob/living/basic/blackmesa/xen/bullsquid,
|
||||
/obj/structure/alien/weeds/xen,
|
||||
/turf/open/misc/asteroid/airless,
|
||||
/area/space/nearstation)
|
||||
@@ -77459,7 +77459,7 @@
|
||||
icon_state = "dirt-flat-1"
|
||||
},
|
||||
/obj/structure/alien/weeds/xen,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/houndeye,
|
||||
/mob/living/basic/blackmesa/xen/houndeye,
|
||||
/turf/open/misc/asteroid/airless,
|
||||
/area/space/nearstation)
|
||||
"oMZ" = (
|
||||
@@ -90929,7 +90929,7 @@
|
||||
icon_state = "dirt-flat-1"
|
||||
},
|
||||
/obj/structure/alien/weeds/xen,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab,
|
||||
/mob/living/basic/blackmesa/xen/headcrab,
|
||||
/turf/open/misc/asteroid/airless,
|
||||
/area/space/nearstation)
|
||||
"rpJ" = (
|
||||
|
||||
@@ -36,4 +36,4 @@
|
||||
#define isavian(A) (isteshari(A) || isvox(A) || isvoxprimalis(A) || HAS_TRAIT(A, TRAIT_AVIAN))
|
||||
|
||||
// Xen mobs
|
||||
#define isxenmob(A) (istype(A, /mob/living/simple_animal/hostile/blackmesa/xen))
|
||||
#define isxenmob(A) (istype(A, /mob/living/basic/blackmesa/xen))
|
||||
|
||||
@@ -62,28 +62,6 @@
|
||||
// MODULAR SKYRAT ENTRIES
|
||||
// PLEASE REFACTOR THESE AS YOU CAN
|
||||
/mob/living/simple_animal/hostile/bigcrab,
|
||||
/mob/living/simple_animal/hostile/blackmesa,
|
||||
/mob/living/simple_animal/hostile/blackmesa/blackops,
|
||||
/mob/living/simple_animal/hostile/blackmesa/blackops/ranged,
|
||||
/mob/living/simple_animal/hostile/blackmesa/hecu,
|
||||
/mob/living/simple_animal/hostile/blackmesa/hecu/ranged,
|
||||
/mob/living/simple_animal/hostile/blackmesa/hecu/ranged/smg,
|
||||
/mob/living/simple_animal/hostile/blackmesa/sec,
|
||||
/mob/living/simple_animal/hostile/blackmesa/sec/ranged,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/bullsquid,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/fast,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/gordon_freeman,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/guard,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/hecu,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/hev,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/scientist,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/houndeye,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/nihilanth,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/vortigaunt,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/vortigaunt/slave,
|
||||
/mob/living/simple_animal/hostile/cazador,
|
||||
/mob/living/simple_animal/hostile/cult,
|
||||
/mob/living/simple_animal/hostile/cult/assassin,
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/bullsquid
|
||||
name = "bullsquid"
|
||||
desc = "Some highly aggressive alien creature. Thrives in toxic environments."
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "bullsquid"
|
||||
icon_living = "bullsquid"
|
||||
icon_dead = "bullsquid_dead"
|
||||
icon_gib = null
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BEAST
|
||||
environment_smash = ENVIRONMENT_SMASH_STRUCTURES
|
||||
speak_chance = 1
|
||||
speak_emote = list("growls")
|
||||
emote_taunt = list("growls", "snarls", "grumbles")
|
||||
taunt_chance = 100
|
||||
turns_per_move = 7
|
||||
maxHealth = 110
|
||||
health = 110
|
||||
obj_damage = 50
|
||||
harm_intent_damage = 15
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
ranged = TRUE
|
||||
retreat_distance = 4
|
||||
minimum_distance = 4
|
||||
dodging = TRUE
|
||||
projectiletype = /obj/projectile/bullsquid
|
||||
projectilesound = 'modular_skyrat/modules/black_mesa/sound/mobs/bullsquid/goo_attack3.ogg'
|
||||
melee_damage_upper = 18
|
||||
attack_sound = 'modular_skyrat/modules/black_mesa/sound/mobs/bullsquid/attack1.ogg'
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/bullsquid/detect1.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/bullsquid/detect2.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/bullsquid/detect3.ogg'
|
||||
)
|
||||
|
||||
/obj/projectile/bullsquid
|
||||
name = "nasty ball of ooze"
|
||||
icon_state = "neurotoxin"
|
||||
damage = 5
|
||||
damage_type = BURN
|
||||
knockdown = 20
|
||||
armor_flag = BIO
|
||||
impact_effect_type = /obj/effect/temp_visual/impact_effect/neurotoxin
|
||||
hitsound = 'modular_skyrat/modules/black_mesa/sound/mobs/bullsquid/splat1.ogg'
|
||||
hitsound_wall = 'modular_skyrat/modules/black_mesa/sound/mobs/bullsquid/splat1.ogg'
|
||||
|
||||
/obj/projectile/bullsquid/on_hit(atom/target, blocked = 0, pierce_hit)
|
||||
new /obj/effect/decal/cleanable/greenglow(target.loc)
|
||||
return ..()
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Bullsquid (/mob/living/basic/blackmesa/xen/bullsquid)
|
||||
* An aggressive alien creature from Xen that uses both melee and ranged attacks.
|
||||
*
|
||||
* A hostile mob that switches between biting nearby targets and spitting acid at distant ones.
|
||||
* Uses standard melee attacks when adjacent and acid spit when at range.
|
||||
* Each bullsquid is hostile to other bullsquids, creating organic free-for-all combat.
|
||||
*/
|
||||
/mob/living/basic/blackmesa/xen/bullsquid
|
||||
name = "bullsquid"
|
||||
desc = "Some highly aggressive alien creature. Thrives in toxic environments."
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "bullsquid"
|
||||
icon_living = "bullsquid"
|
||||
icon_dead = "bullsquid_dead"
|
||||
|
||||
// Health and combat
|
||||
maxHealth = 110
|
||||
health = 110
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 18
|
||||
obj_damage = 50
|
||||
combat_mode = TRUE
|
||||
attack_verb_continuous = "bites"
|
||||
attack_verb_simple = "bite"
|
||||
attack_sound = 'modular_skyrat/modules/black_mesa/sound/mobs/bullsquid/attack1.ogg'
|
||||
attack_vis_effect = ATTACK_EFFECT_BITE
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 1, OXY = 1)
|
||||
|
||||
// Mob traits
|
||||
mob_biotypes = MOB_ORGANIC | MOB_BEAST
|
||||
environment_smash = ENVIRONMENT_SMASH_STRUCTURES
|
||||
basic_mob_flags = FLAMMABLE_MOB
|
||||
unsuitable_cold_damage = 15
|
||||
unsuitable_heat_damage = 15
|
||||
speak_emote = list("growls")
|
||||
|
||||
// AI and behavior
|
||||
ai_controller = /datum/ai_controller/basic_controller/bullsquid
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/bullsquid/detect1.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/bullsquid/detect2.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/bullsquid/detect3.ogg'
|
||||
)
|
||||
|
||||
/mob/living/basic/blackmesa/xen/bullsquid/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/ai_listen_to_weather)
|
||||
// Add ranged attack component with proper targeting
|
||||
AddComponent(/datum/component/ranged_attacks, projectile_type = /obj/projectile/bullsquid, projectile_sound = 'modular_skyrat/modules/black_mesa/sound/mobs/bullsquid/goo_attack3.ogg', cooldown_time = 3 SECONDS)
|
||||
|
||||
/obj/item/ammo_casing/bullsquid
|
||||
name = "nasty ball of ooze"
|
||||
projectile_type = /obj/projectile/bullsquid
|
||||
|
||||
/obj/projectile/bullsquid
|
||||
name = "nasty ball of ooze"
|
||||
icon_state = "neurotoxin"
|
||||
damage = 5
|
||||
damage_type = BURN
|
||||
knockdown = 20
|
||||
armor_flag = BIO
|
||||
impact_effect_type = /obj/effect/temp_visual/impact_effect/neurotoxin
|
||||
hitsound = 'modular_skyrat/modules/black_mesa/sound/mobs/bullsquid/splat1.ogg'
|
||||
hitsound_wall = 'modular_skyrat/modules/black_mesa/sound/mobs/bullsquid/splat1.ogg'
|
||||
pass_flags = PASSTABLE
|
||||
speed = 0.8
|
||||
|
||||
/// Creates toxic residue where the projectile hits
|
||||
/obj/projectile/bullsquid/on_hit(atom/target, blocked = 0, pierce_hit)
|
||||
new /obj/effect/decal/cleanable/greenglow(target.loc)
|
||||
return ..()
|
||||
@@ -0,0 +1,46 @@
|
||||
/datum/ai_controller/basic_controller/bullsquid
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_BASIC_MOB_MELEE_ATTACK_RANGE = 1,
|
||||
BB_BASIC_MOB_CURRENT_TARGET = null,
|
||||
)
|
||||
|
||||
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/bullsquid_attack,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree,
|
||||
)
|
||||
|
||||
/// Handles the bullsquid's acid spit attack based on distance.
|
||||
/// Works alongside basic_melee_attack_subtree which handles biting.
|
||||
/datum/ai_planning_subtree/bullsquid_attack
|
||||
COOLDOWN_DECLARE(acid_cooldown)
|
||||
/// Time between acid spit attacks
|
||||
var/acid_cooldown_time = 3 SECONDS
|
||||
/// Minimum range before we'll try to spit acid
|
||||
var/min_spit_range = 2
|
||||
/// Maximum range at which we can spit acid
|
||||
var/max_spit_range = 6
|
||||
|
||||
/datum/ai_planning_subtree/bullsquid_attack/SelectBehaviors(datum/ai_controller/controller, delta_time)
|
||||
. = ..()
|
||||
var/atom/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
if(!target)
|
||||
return
|
||||
|
||||
var/mob/living/basic/blackmesa/xen/bullsquid/pawn = controller.pawn
|
||||
if(QDELETED(pawn))
|
||||
return
|
||||
|
||||
var/distance = get_dist(pawn, target)
|
||||
|
||||
// Let basic_melee_attack_subtree handle melee range combat
|
||||
if(distance <= 1)
|
||||
return
|
||||
|
||||
// Try acid spit if in valid range and attack is ready
|
||||
if(distance >= min_spit_range && distance <= max_spit_range && COOLDOWN_FINISHED(src, acid_cooldown))
|
||||
controller.queue_behavior(/datum/ai_behavior/basic_ranged_attack, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY)
|
||||
COOLDOWN_START(src, acid_cooldown, acid_cooldown_time)
|
||||
@@ -0,0 +1,105 @@
|
||||
// Corpse definitions for Black Mesa NPCs
|
||||
|
||||
/obj/effect/mob_spawn/corpse/human/hecu
|
||||
name = "HECU Corpse"
|
||||
hairstyle = "Bald"
|
||||
facial_hairstyle = "Shaved"
|
||||
outfit = /datum/outfit/hecu_corpse
|
||||
|
||||
/obj/effect/mob_spawn/corpse/human/hecu_ranged
|
||||
name = "HECU Ranged Corpse"
|
||||
hairstyle = "Bald"
|
||||
facial_hairstyle = "Shaved"
|
||||
outfit = /datum/outfit/hecu_ranged_corpse
|
||||
|
||||
/obj/effect/mob_spawn/corpse/human/hecu_smg
|
||||
name = "HECU SMG Corpse"
|
||||
hairstyle = "Bald"
|
||||
facial_hairstyle = "Shaved"
|
||||
outfit = /datum/outfit/hecu_smg_corpse
|
||||
|
||||
/obj/effect/mob_spawn/corpse/human/security_guard
|
||||
name = "Security Guard Corpse"
|
||||
hairstyle = "Bald"
|
||||
facial_hairstyle = "Shaved"
|
||||
outfit = /datum/outfit/security_guard_corpse
|
||||
|
||||
/obj/effect/mob_spawn/corpse/human/security_guard/ranged
|
||||
name = "Armed Security Guard Corpse"
|
||||
outfit = /datum/outfit/security_guard_ranged_corpse
|
||||
|
||||
/obj/effect/mob_spawn/corpse/human/black_ops
|
||||
name = "Black Ops Corpse"
|
||||
hairstyle = "Bald"
|
||||
facial_hairstyle = "Shaved"
|
||||
outfit = /datum/outfit/black_ops_corpse
|
||||
|
||||
/obj/effect/mob_spawn/corpse/human/black_ops/ranged
|
||||
name = "Armed Black Ops Corpse"
|
||||
outfit = /datum/outfit/black_ops_ranged_corpse
|
||||
|
||||
// Outfits for corpses
|
||||
/datum/outfit/hecu_corpse
|
||||
name = "HECU Grunt"
|
||||
uniform = /obj/item/clothing/under/rank/security/officer/hecu
|
||||
suit = /obj/item/clothing/suit/armor/vest/hecu
|
||||
shoes = /obj/item/clothing/shoes/combat
|
||||
gloves = /obj/item/clothing/gloves/combat
|
||||
mask = /obj/item/clothing/mask/gas
|
||||
head = /obj/item/clothing/head/helmet/hecu
|
||||
|
||||
/datum/outfit/hecu_ranged_corpse
|
||||
name = "HECU Ranged"
|
||||
uniform = /obj/item/clothing/under/rank/security/officer/hecu
|
||||
suit = /obj/item/clothing/suit/armor/vest/hecu
|
||||
shoes = /obj/item/clothing/shoes/combat
|
||||
gloves = /obj/item/clothing/gloves/combat
|
||||
mask = /obj/item/clothing/mask/gas
|
||||
head = /obj/item/clothing/head/helmet/hecu
|
||||
l_pocket = /obj/item/ammo_box/magazine/m50
|
||||
|
||||
/datum/outfit/hecu_smg_corpse
|
||||
name = "HECU SMG"
|
||||
uniform = /obj/item/clothing/under/rank/security/officer/hecu
|
||||
suit = /obj/item/clothing/suit/armor/vest/hecu
|
||||
shoes = /obj/item/clothing/shoes/combat
|
||||
gloves = /obj/item/clothing/gloves/combat
|
||||
mask = /obj/item/clothing/mask/gas
|
||||
head = /obj/item/clothing/head/helmet/hecu
|
||||
l_pocket = /obj/item/ammo_box/magazine/smgm45
|
||||
|
||||
/datum/outfit/security_guard_corpse
|
||||
name = "Black Mesa Security"
|
||||
uniform = /obj/item/clothing/under/rank/security/officer/blueshirt
|
||||
suit = /obj/item/clothing/suit/armor/vest/blueshirt
|
||||
shoes = /obj/item/clothing/shoes/jackboots
|
||||
head = /obj/item/clothing/head/helmet/blueshirt
|
||||
|
||||
/datum/outfit/security_guard_ranged_corpse
|
||||
name = "Armed Black Mesa Security"
|
||||
uniform = /obj/item/clothing/under/rank/security/officer/blueshirt
|
||||
suit = /obj/item/clothing/suit/armor/vest/blueshirt
|
||||
shoes = /obj/item/clothing/shoes/jackboots
|
||||
head = /obj/item/clothing/head/helmet/blueshirt
|
||||
l_pocket = /obj/item/ammo_box/magazine/c35sol_pistol
|
||||
|
||||
/datum/outfit/black_ops_corpse
|
||||
name = "Black Ops"
|
||||
uniform = /obj/item/clothing/under/syndicate/combat
|
||||
suit = /obj/item/clothing/suit/armor/vest/alt
|
||||
shoes = /obj/item/clothing/shoes/combat
|
||||
gloves = /obj/item/clothing/gloves/combat
|
||||
mask = /obj/item/clothing/mask/gas/sechailer
|
||||
head = /obj/item/clothing/head/helmet/swat
|
||||
back = /obj/item/storage/backpack/security
|
||||
|
||||
/datum/outfit/black_ops_ranged_corpse
|
||||
name = "Armed Black Ops"
|
||||
uniform = /obj/item/clothing/under/syndicate/combat
|
||||
suit = /obj/item/clothing/suit/armor/vest/alt
|
||||
shoes = /obj/item/clothing/shoes/combat
|
||||
gloves = /obj/item/clothing/gloves/combat
|
||||
mask = /obj/item/clothing/mask/gas/sechailer
|
||||
head = /obj/item/clothing/head/helmet/swat
|
||||
back = /obj/item/storage/backpack/security
|
||||
l_pocket = /obj/item/ammo_box/magazine/c40sol_rifle
|
||||
+82
-12
@@ -6,39 +6,109 @@
|
||||
* Once destroyed, the shield falls, and the mob can be killed.
|
||||
*/
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/gordon_freeman
|
||||
/mob/living/basic/blackmesa/xen/gordon_freeman
|
||||
name = "\improper Gordon Freeman"
|
||||
desc = "Gordon Freeman in the flesh. Or in the zombified form, it seems."
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "gordon_freeman"
|
||||
speed = -2
|
||||
environment_smash = ENVIRONMENT_SMASH_RWALLS
|
||||
health = 1000
|
||||
base_icon_state = "gordon_freeman"
|
||||
icon_living = "gordon_freeman"
|
||||
|
||||
// Stats
|
||||
maxHealth = 1000
|
||||
health = 1000
|
||||
melee_damage_lower = 45
|
||||
melee_damage_upper = 45
|
||||
wander = FALSE
|
||||
attack_sound = 'modular_skyrat/master_files/sound/weapons/crowbar2.ogg'
|
||||
loot = list(/obj/item/crowbar/freeman/ultimate, /obj/item/keycard/freeman_boss_exit)
|
||||
attack_verb_continuous = "smashes"
|
||||
attack_verb_simple = "smash"
|
||||
|
||||
// Movement
|
||||
speed = -2
|
||||
ai_controller = /datum/ai_controller/basic_controller/gordon_freeman
|
||||
basic_mob_flags = DEL_ON_DEATH
|
||||
|
||||
// Boss properties
|
||||
environment_smash = ENVIRONMENT_SMASH_RWALLS
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
|
||||
// Death drops
|
||||
butcher_results = list(
|
||||
/obj/item/crowbar/freeman/ultimate = 1,
|
||||
/obj/item/keycard/freeman_boss_exit = 1
|
||||
)
|
||||
|
||||
/mob/living/basic/blackmesa/xen/gordon_freeman/Initialize(mapload)
|
||||
. = ..()
|
||||
if(mapload)
|
||||
find_and_register_pylons()
|
||||
|
||||
/// Finds all pylons in range and registers with them
|
||||
/mob/living/basic/blackmesa/xen/gordon_freeman/proc/find_and_register_pylons()
|
||||
var/found_pylons = 0
|
||||
for(var/obj/structure/xen_pylon/freeman/pylon in orange(30, src))
|
||||
if(pylon.register_mob(src))
|
||||
found_pylons++
|
||||
if(!found_pylons)
|
||||
stack_trace("[src] failed to find any pylons on initialization")
|
||||
|
||||
/// Update our appearance when shield status changes
|
||||
/mob/living/basic/blackmesa/xen/gordon_freeman/update_overlays()
|
||||
. = ..()
|
||||
if(!shielded)
|
||||
return
|
||||
. += mutable_appearance(icon, "gordon_freeman_shield", layer = ABOVE_MOB_LAYER)
|
||||
|
||||
/mob/living/basic/blackmesa/xen/gordon_freeman/death(gibbed)
|
||||
// Cleanup shield effects and beams
|
||||
shielded = FALSE
|
||||
shield_count = 0
|
||||
|
||||
// Handle death drops
|
||||
var/turf/T = get_turf(src)
|
||||
if(T)
|
||||
for(var/item_type in butcher_results)
|
||||
var/amount = butcher_results[item_type]
|
||||
for(var/i in 1 to amount)
|
||||
new item_type(T)
|
||||
|
||||
// Create death effect
|
||||
T.visible_message(span_warning("[src] violently dissolves into a pile of flesh!"))
|
||||
new /obj/effect/gibspawner/generic(T)
|
||||
|
||||
// Clean up the mob
|
||||
qdel(src)
|
||||
return ..(TRUE) // Force gibbed to true
|
||||
|
||||
/obj/structure/xen_pylon/freeman
|
||||
shield_range = 30
|
||||
max_integrity = 300
|
||||
|
||||
/obj/structure/xen_pylon/freeman/register_mob(mob/living/simple_animal/hostile/blackmesa/xen/mob_to_register)
|
||||
if(!istype(mob_to_register, /mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/gordon_freeman))
|
||||
return
|
||||
/obj/structure/xen_pylon/freeman/register_mob(mob/living/basic/blackmesa/xen/mob_to_register)
|
||||
if(!istype(mob_to_register, /mob/living/basic/blackmesa/xen/gordon_freeman))
|
||||
return FALSE
|
||||
if(mob_to_register in shielded_mobs)
|
||||
return
|
||||
return FALSE
|
||||
if(QDELETED(mob_to_register))
|
||||
return FALSE
|
||||
|
||||
shielded_mobs += mob_to_register
|
||||
mob_to_register.shielded = TRUE
|
||||
mob_to_register.shield_count++
|
||||
mob_to_register.update_appearance()
|
||||
|
||||
var/datum/beam/created_beam = Beam(mob_to_register, icon_state = "red_lightning", time = 10 MINUTES, maxdistance = shield_range)
|
||||
if(!created_beam) // Beam creation failed
|
||||
shielded_mobs -= mob_to_register
|
||||
mob_to_register.shielded = FALSE
|
||||
mob_to_register.shield_count--
|
||||
mob_to_register.update_appearance()
|
||||
return FALSE
|
||||
|
||||
shielded_mobs[mob_to_register] = created_beam
|
||||
RegisterSignal(created_beam, COMSIG_QDELETING, PROC_REF(beam_died))
|
||||
RegisterSignal(mob_to_register, COMSIG_QDELETING, PROC_REF(mob_died))
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/door/puzzle/keycard/xen/freeman_boss_entry
|
||||
name = "entry door"
|
||||
@@ -73,7 +143,7 @@
|
||||
|
||||
/obj/effect/freeman_blocker/CanPass(atom/blocker, movement_dir, blocker_opinion)
|
||||
. = ..()
|
||||
if(istype(blocker, /mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/gordon_freeman))
|
||||
if(istype(blocker, /mob/living/basic/blackmesa/xen/gordon_freeman))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* AI Controllers
|
||||
*/
|
||||
|
||||
/// AI controller for Gordon Freeman boss
|
||||
/datum/ai_controller/basic_controller/gordon_freeman
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
|
||||
)
|
||||
|
||||
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/basic_melee_attack_subtree,
|
||||
/datum/ai_planning_subtree/target_retaliate
|
||||
)
|
||||
@@ -1,136 +0,0 @@
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab
|
||||
name = "headcrab"
|
||||
desc = "Don't let it latch onto your hea-... hey, that's kinda cool."
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "headcrab"
|
||||
icon_living = "headcrab"
|
||||
icon_dead = "headcrab_dead"
|
||||
icon_gib = null
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BEAST
|
||||
speak_chance = 1
|
||||
speak_emote = list("growls")
|
||||
speed = 1
|
||||
emote_taunt = list("growls", "snarls", "grumbles")
|
||||
ranged_message = "jumps"
|
||||
taunt_chance = 100
|
||||
turns_per_move = 7
|
||||
maxHealth = 50
|
||||
health = 50
|
||||
speed = 3
|
||||
ranged = TRUE
|
||||
dodging = TRUE
|
||||
ranged_cooldown_time = 4 SECONDS
|
||||
harm_intent_damage = 15
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 5
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
attack_sound = 'sound/items/weapons/bite.ogg'
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
loot = list(/obj/item/stack/sheet/bone)
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/headcrab/alert1.ogg'
|
||||
)
|
||||
var/is_zombie = FALSE
|
||||
var/mob/living/carbon/human/oldguy
|
||||
/// Charging ability
|
||||
var/datum/action/cooldown/mob_cooldown/charge/basic_charge/charge
|
||||
var/throw_at_range = 10
|
||||
var/throw_at_speed = 2
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/Initialize(mapload)
|
||||
. = ..()
|
||||
charge = new(src)
|
||||
charge.Grant(src)
|
||||
charge.cooldown_time = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/Shoot(atom/targeted_atom)
|
||||
throw_at(targeted_atom, throw_at_range, throw_at_speed)
|
||||
playsound(
|
||||
src,
|
||||
pick('modular_skyrat/modules/black_mesa/sound/mobs/headcrab/attack1.ogg', 'modular_skyrat/modules/black_mesa/sound/mobs/headcrab/attack2.ogg', 'modular_skyrat/modules/black_mesa/sound/mobs/headcrab/attack3.ogg'),
|
||||
100
|
||||
)
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/death(gibbed)
|
||||
. = ..()
|
||||
playsound(src, pick(list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/headcrab/die1.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/headcrab/die2.ogg'
|
||||
)), 100)
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
|
||||
. = ..()
|
||||
if(!hit_atom || stat == DEAD)
|
||||
return
|
||||
if(!isliving(hit_atom))
|
||||
return
|
||||
playsound(src, 'modular_skyrat/modules/black_mesa/sound/mobs/headcrab/headbite.ogg', 100)
|
||||
var/mob/living/hit_mob = hit_atom
|
||||
hit_mob.apply_damage(melee_damage_upper, BRUTE)
|
||||
if(!ishuman(hit_atom))
|
||||
return
|
||||
var/mob/living/carbon/human/human_to_dunk = hit_atom
|
||||
if(!human_to_dunk.get_item_by_slot(ITEM_SLOT_HEAD) && prob(50) && zombify(human_to_dunk))
|
||||
to_chat(human_to_dunk, span_userdanger("[src] latches onto your head as it pierces your skull, instantly killing you!"))
|
||||
human_to_dunk.investigate_log("was headcrab latched by [src].", INVESTIGATE_DEATHS)
|
||||
human_to_dunk.death(FALSE)
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/proc/zombify(mob/living/carbon/human/zombified_human)
|
||||
if(is_zombie)
|
||||
return FALSE
|
||||
is_zombie = TRUE
|
||||
if(zombified_human.wear_suit)
|
||||
var/obj/item/clothing/suit/armor/zombie_suit = zombified_human.wear_suit
|
||||
maxHealth += zombie_suit.get_armor_rating(MELEE) //That zombie's got armor, I want armor!
|
||||
maxHealth += 40
|
||||
health = maxHealth
|
||||
name = "zombie"
|
||||
desc = "A shambling corpse animated by a headcrab!"
|
||||
mob_biotypes |= MOB_HUMANOID
|
||||
melee_damage_lower += 8
|
||||
melee_damage_upper += 11
|
||||
obj_damage = 21 //now that it has a corpse to puppet, it can properly attack structures
|
||||
ranged = FALSE
|
||||
dodging = FALSE
|
||||
retreat_distance = 0
|
||||
minimum_distance = 0
|
||||
AddElement(/datum/element/wall_smasher, strength_flag = ENVIRONMENT_SMASH_STRUCTURES)
|
||||
movement_type = GROUND
|
||||
icon_state = ""
|
||||
zombified_human.set_hairstyle(null, update = FALSE)
|
||||
zombified_human.update_body_parts()
|
||||
zombified_human.forceMove(src)
|
||||
oldguy = zombified_human
|
||||
update_appearance()
|
||||
visible_message(span_warning("The corpse of [zombified_human.name] suddenly rises!"))
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/Destroy()
|
||||
if(oldguy)
|
||||
oldguy.forceMove(get_turf(src))
|
||||
oldguy = null
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/death(gibbed)
|
||||
. = ..()
|
||||
if(oldguy)
|
||||
oldguy.forceMove(loc)
|
||||
oldguy = null
|
||||
if(is_zombie)
|
||||
if(prob(30))
|
||||
new /mob/living/simple_animal/hostile/blackmesa/xen/headcrab(loc) //OOOO it unlached!
|
||||
qdel(src)
|
||||
return
|
||||
cut_overlays()
|
||||
update_appearance()
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/update_overlays()
|
||||
. = ..()
|
||||
if(is_zombie)
|
||||
copy_overlays(oldguy, TRUE)
|
||||
var/mutable_appearance/blob_head_overlay = mutable_appearance('modular_skyrat/modules/black_mesa/icons/mobs.dmi', "headcrab_zombie")
|
||||
add_overlay(blob_head_overlay)
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab/fast
|
||||
speed = -2
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* Headcrab (/mob/living/basic/blackmesa/xen/headcrab)
|
||||
* Parasitic alien that jumps at targets and can zombify humans.
|
||||
*
|
||||
* A classic Half-Life enemy that uses jumping attacks and can turn humans into zombies.
|
||||
* - Jumps at targets from range
|
||||
* - Can zombify unprotected humans on headshot
|
||||
* - Detaches from zombies on death with a chance to survive
|
||||
*/
|
||||
/mob/living/basic/blackmesa/xen/headcrab
|
||||
name = "headcrab"
|
||||
desc = "Don't let it latch onto your hea-... hey, that's kinda cool."
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "headcrab"
|
||||
icon_living = "headcrab"
|
||||
icon_dead = "headcrab_dead"
|
||||
base_icon_state = "headcrab"
|
||||
|
||||
// Health and combat
|
||||
maxHealth = 50
|
||||
health = 50
|
||||
melee_damage_lower = 0 // No melee attacks, only jump attacks
|
||||
melee_damage_upper = 0
|
||||
combat_mode = TRUE
|
||||
|
||||
// Mob traits
|
||||
mob_biotypes = MOB_ORGANIC | MOB_BEAST
|
||||
basic_mob_flags = NONE
|
||||
ai_controller = /datum/ai_controller/basic_controller/headcrab
|
||||
|
||||
// Movement
|
||||
speed = 3
|
||||
move_force = MOVE_FORCE_WEAK
|
||||
move_resist = MOVE_FORCE_WEAK
|
||||
pull_force = MOVE_FORCE_WEAK
|
||||
pixel_x = -8
|
||||
base_pixel_x = -8
|
||||
faction = list(FACTION_XEN) // Friendly to other Xen creatures
|
||||
can_be_shielded = FALSE // Headcrabs don't use shield pylons
|
||||
|
||||
// Spawning and loot
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
butcher_results = list(
|
||||
/obj/item/stack/sheet/bone = 1
|
||||
)
|
||||
|
||||
/// Maximum distance this headcrab can jump in tiles
|
||||
var/throw_at_range = 10
|
||||
|
||||
/// Base speed at which this headcrab jumps (actual speed varies with distance)
|
||||
var/throw_at_speed = 2
|
||||
|
||||
/// Track if we've attached to a human, to prevent multiple zombifications
|
||||
var/is_zombie = FALSE
|
||||
|
||||
/mob/living/basic/blackmesa/xen/headcrab
|
||||
alert_sounds = list('modular_skyrat/modules/black_mesa/sound/mobs/headcrab/alert1.ogg')
|
||||
|
||||
/mob/living/basic/blackmesa/xen/headcrab/Initialize(mapload)
|
||||
. = ..()
|
||||
RegisterSignal(src, COMSIG_MOVABLE_IMPACT, PROC_REF(handle_impact))
|
||||
ai_controller.set_blackboard_key(BB_TARGET_MINIMUM_STAT, HARD_CRIT) // Allow targeting unconscious people
|
||||
|
||||
/// Execute the jump after the telegraph
|
||||
/datum/ai_planning_subtree/headcrab_hunt/proc/execute_jump(mob/living/basic/blackmesa/xen/headcrab/jumper, atom/target, distance, speed)
|
||||
if(QDELETED(jumper) || QDELETED(target) || jumper.stat == DEAD)
|
||||
return
|
||||
|
||||
// Make it spin during the jump! The faster the jump, the faster the spin
|
||||
var/spin_speed = speed * 2
|
||||
jumper.throw_at(target, distance, speed, jumper, TRUE, TRUE, null, 0.1, FALSE, spin_speed)
|
||||
|
||||
/// Handle leap impacts
|
||||
/mob/living/basic/blackmesa/xen/headcrab/proc/handle_impact(datum/source, atom/hit_atom, datum/thrownthing/throwingdatum)
|
||||
SIGNAL_HANDLER
|
||||
if(!hit_atom || stat == DEAD)
|
||||
return
|
||||
if(!isliving(hit_atom))
|
||||
return
|
||||
|
||||
playsound(src, 'modular_skyrat/modules/black_mesa/sound/mobs/headcrab/attack1.ogg', 100, FALSE)
|
||||
var/mob/living/hit_mob = hit_atom
|
||||
|
||||
// More damage if we hit them at high speed
|
||||
var/damage = 8
|
||||
if(throwingdatum.speed >= 3)
|
||||
damage = 12
|
||||
|
||||
hit_mob.apply_damage(damage, BRUTE)
|
||||
|
||||
if(!ishuman(hit_atom))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/human_target = hit_atom
|
||||
|
||||
// Regular damage if the target is conscious
|
||||
if(human_target.stat < UNCONSCIOUS)
|
||||
human_target.apply_damage(damage, BRUTE, BODY_ZONE_HEAD)
|
||||
return
|
||||
|
||||
// Check for head protection on unconscious targets
|
||||
var/obj/item/clothing/head/head_protection = human_target.get_item_by_slot(ITEM_SLOT_HEAD)
|
||||
if(head_protection)
|
||||
head_protection.take_damage(15)
|
||||
return
|
||||
|
||||
// Zombify unprotected unconscious targets
|
||||
if(zombify(human_target))
|
||||
// Visual and sound feedback
|
||||
playsound(src, 'modular_skyrat/modules/black_mesa/sound/mobs/headcrab/attack1.ogg', 100, FALSE)
|
||||
do_sparks(3, TRUE, human_target)
|
||||
|
||||
// Log the zombification
|
||||
human_target.investigate_log("was zombified by [src] while unconscious.", INVESTIGATE_DEATHS)
|
||||
human_target.death(FALSE)
|
||||
|
||||
/mob/living/basic/blackmesa/xen/headcrab/death(gibbed)
|
||||
// Handle death sound if not gibbed
|
||||
if(!gibbed)
|
||||
playsound(src, pick(list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/headcrab/die1.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/headcrab/die2.ogg'
|
||||
)), 100)
|
||||
return ..()
|
||||
|
||||
/// Transforms a human into a headcrab zombie
|
||||
/mob/living/basic/blackmesa/xen/headcrab/proc/zombify(mob/living/carbon/human/target_human)
|
||||
// Sanity checks
|
||||
if(is_zombie || !target_human)
|
||||
return FALSE
|
||||
|
||||
// Create the zombie at our location
|
||||
var/mob/living/basic/blackmesa/xen/headcrab_zombie/new_zombie = new(get_turf(src))
|
||||
new_zombie.name = "[target_human.name] zombie"
|
||||
|
||||
// Copy the human's appearance
|
||||
target_human.set_hairstyle(null, update = FALSE)
|
||||
target_human.update_body_parts()
|
||||
new_zombie.copy_overlays(target_human)
|
||||
|
||||
// Add the headcrab overlay
|
||||
var/mutable_appearance/blob_head_overlay = mutable_appearance('modular_skyrat/modules/black_mesa/icons/mobs.dmi', "headcrab_zombie")
|
||||
new_zombie.add_overlay(blob_head_overlay)
|
||||
|
||||
// Store the human inside the zombie
|
||||
target_human.forceMove(new_zombie)
|
||||
new_zombie.zombified_human = target_human
|
||||
|
||||
// If they have armor, apply it to the zombie
|
||||
var/obj/item/clothing/suit/armor/zombie_suit = target_human.wear_suit
|
||||
if(istype(zombie_suit))
|
||||
new_zombie.maxHealth += zombie_suit.get_armor_rating(MELEE) //That zombie's got armor, I want armor!
|
||||
new_zombie.health = new_zombie.maxHealth
|
||||
|
||||
// Visual and sound feedback for zombie creation
|
||||
playsound(new_zombie, 'modular_skyrat/modules/black_mesa/sound/mobs/headcrab/attack1.ogg', 100, FALSE)
|
||||
visible_message(span_warning("The corpse of [target_human.name] suddenly rises, a headcrab controlling its lifeless body!"))
|
||||
|
||||
// Delete the original headcrab
|
||||
qdel(src)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Fast Headcrab (/mob/living/basic/blackmesa/xen/headcrab/fast)
|
||||
* A variant of the standard headcrab that moves significantly faster.
|
||||
*
|
||||
* This version appears in later stages of Half-Life and represents a more dangerous variant.
|
||||
* - Moves much quicker than standard headcrabs
|
||||
* - Same jumping and zombification mechanics
|
||||
* - More dangerous due to increased mobility
|
||||
*/
|
||||
/mob/living/basic/blackmesa/xen/headcrab/fast
|
||||
speed = -2
|
||||
desc = "Don't let it latch onto your hea-... hey, that's kinda cool. This one looks faster than usual."
|
||||
@@ -0,0 +1,64 @@
|
||||
/datum/ai_controller/basic_controller/headcrab
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items,
|
||||
BB_BASIC_MOB_CURRENT_TARGET = null,
|
||||
BB_BASIC_MOB_MELEE_ATTACK_RANGE = 0, // No melee attacks
|
||||
BB_BASIC_MOB_CURRENT_TARGET_HIDING = FALSE,
|
||||
BB_TARGET_MINIMUM_STAT = HARD_CRIT // Allow targeting of unconscious people
|
||||
)
|
||||
|
||||
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/headcrab_hunt
|
||||
)
|
||||
|
||||
/// Handles the headcrab's hunting behavior, trying to leap at targets when in range
|
||||
/datum/ai_planning_subtree/headcrab_hunt
|
||||
/// Time between jump attempts
|
||||
var/jump_cooldown_time = 1 SECONDS // Reduced cooldown for more frequent jumps
|
||||
COOLDOWN_DECLARE(jump_cooldown)
|
||||
|
||||
/// Preferred range to start jumping
|
||||
var/preferred_jump_range = 4
|
||||
/// Maximum range at which we can leap
|
||||
var/max_jump_range = 10 // Increased range for better mobility
|
||||
|
||||
/datum/ai_planning_subtree/headcrab_hunt/SelectBehaviors(datum/ai_controller/controller, delta_time)
|
||||
. = ..()
|
||||
var/mob/living/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
if(!target)
|
||||
return
|
||||
|
||||
var/mob/living/living_pawn = controller.pawn
|
||||
if(QDELETED(living_pawn))
|
||||
return
|
||||
|
||||
if(!COOLDOWN_FINISHED(src, jump_cooldown))
|
||||
return
|
||||
|
||||
var/distance = get_dist(living_pawn, target)
|
||||
|
||||
// Step back to avoid attacking from standing on the corpse.
|
||||
if(target.stat >= HARD_CRIT && distance == 0)
|
||||
var/turf/away = get_step_away(living_pawn, target)
|
||||
if(away)
|
||||
living_pawn.Move(away)
|
||||
distance = get_dist(living_pawn, target)
|
||||
|
||||
// Always jump at target if in range
|
||||
if(distance <= max_jump_range)
|
||||
COOLDOWN_START(src, jump_cooldown, jump_cooldown_time)
|
||||
// Telegraph the jump with sound
|
||||
playsound(living_pawn, 'modular_skyrat/modules/black_mesa/sound/mobs/headcrab/attack2.ogg', 50, TRUE)
|
||||
|
||||
// Calculate jump speed based on distance - faster at close range for better accuracy
|
||||
var/jump_speed = 3
|
||||
if(distance <= 3)
|
||||
jump_speed = 4 // Faster at close range
|
||||
else if(distance >= 7)
|
||||
jump_speed = 2 // Slower at long range
|
||||
|
||||
addtimer(CALLBACK(src, PROC_REF(execute_jump), living_pawn, target, distance, jump_speed), 0.3 SECONDS)
|
||||
@@ -1,89 +0,0 @@
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie
|
||||
name = "headcrab zombie"
|
||||
desc = "This unlucky person has had a headcrab latch onto their head. Ouch."
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "zombie"
|
||||
icon_living = "zombie"
|
||||
maxHealth = 110
|
||||
health = 110
|
||||
icon_gib = null
|
||||
icon_dead = "zombie_dead"
|
||||
speak_chance = 1
|
||||
speak_emote = list("growls")
|
||||
speed = 1
|
||||
emote_taunt = list("growls", "snarls", "grumbles")
|
||||
taunt_chance = 100
|
||||
melee_damage_lower = 21
|
||||
melee_damage_upper = 21
|
||||
attack_sound = 'modular_skyrat/modules/black_mesa/sound/mobs/zombies/claw_strike.ogg'
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
alert_cooldown_time = 8 SECONDS
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/alert1.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/alert2.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/alert3.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/alert4.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/alert5.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/alert6.ogg',
|
||||
)
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/death(gibbed)
|
||||
new /obj/effect/gibspawner/human(get_turf(src))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/scientist
|
||||
name = "zombified scientist"
|
||||
desc = "Even after death, I still have to wear this horrible tie!"
|
||||
icon_state = "scientist_zombie"
|
||||
icon_living = "scientist_zombie"
|
||||
loot = list(/obj/effect/mob_spawn/corpse/human/scientist_zombie)
|
||||
del_on_death = 1
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/guard
|
||||
name = "zombified guard"
|
||||
desc = "About that brain I owed ya!"
|
||||
icon_state = "security_zombie"
|
||||
icon_living = "security_zombie"
|
||||
maxHealth = 140 // Armor!
|
||||
health = 140
|
||||
loot = list(/obj/effect/mob_spawn/corpse/human/guard_zombie)
|
||||
del_on_death = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/hecu
|
||||
name = "zombified marine"
|
||||
desc = "MY. ASS. IS. DEAD."
|
||||
icon_state = "hecu_zombie"
|
||||
icon_living = "hecu_zombie"
|
||||
maxHealth = 190 // More armor!
|
||||
health = 190
|
||||
loot = list(/obj/effect/mob_spawn/corpse/human/hecu_zombie)
|
||||
del_on_death = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/hev
|
||||
name = "zombified hazardous environment specialist"
|
||||
desc = "User death... surpassed."
|
||||
icon_state = "hev_zombie"
|
||||
icon_living = "hev_zombie"
|
||||
maxHealth = 250
|
||||
health = 250
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv1.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv2.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv3.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv4.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv5.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv6.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv7.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv8.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv9.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv10.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv11.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv12.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv13.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv14.ogg',
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* Headcrab Zombies
|
||||
* Various types of zombies created by headcrabs latching onto different personnel.
|
||||
*
|
||||
* Base zombie type with common behaviors and properties.
|
||||
* Each variant (scientist, guard, HECU, HEV) has different health values and corpses.
|
||||
*/
|
||||
/mob/living/basic/blackmesa/xen/headcrab_zombie
|
||||
name = "headcrab zombie"
|
||||
desc = "This unlucky person has had a headcrab latch onto their head. Ouch."
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "zombie"
|
||||
base_icon_state = "zombie"
|
||||
icon_dead = "zombie_dead"
|
||||
|
||||
// Health and combat
|
||||
maxHealth = 110
|
||||
health = 110
|
||||
melee_damage_lower = 21
|
||||
melee_damage_upper = 21
|
||||
attack_sound = 'modular_skyrat/modules/black_mesa/sound/mobs/zombies/claw_strike.ogg'
|
||||
obj_damage = 21
|
||||
combat_mode = TRUE
|
||||
|
||||
// Movement and behavior
|
||||
speed = 1
|
||||
move_force = MOVE_FORCE_STRONG
|
||||
move_resist = MOVE_FORCE_STRONG
|
||||
pull_force = MOVE_FORCE_STRONG
|
||||
|
||||
// Mob traits
|
||||
mob_biotypes = MOB_ORGANIC | MOB_HUMANOID
|
||||
basic_mob_flags = NONE
|
||||
faction = list(FACTION_XEN)
|
||||
ai_controller = /datum/ai_controller/basic_controller/headcrab_zombie
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
can_be_shielded = FALSE // Zombies are corrupted humans, not true Xen allies
|
||||
|
||||
/// What type of corpse to spawn when this zombie dies
|
||||
var/corpse_type = null
|
||||
/// The human that was zombified (for freeing on death)
|
||||
var/mob/living/carbon/human/zombified_human = null
|
||||
// Alert Sound System - Inherited from /mob/living/basic/blackmesa
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/alert1.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/alert2.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/alert3.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/alert4.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/alert5.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/alert6.ogg'
|
||||
)
|
||||
|
||||
/mob/living/basic/blackmesa/xen/headcrab_zombie/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/wall_smasher, strength_flag = ENVIRONMENT_SMASH_STRUCTURES)
|
||||
|
||||
/mob/living/basic/blackmesa/xen/headcrab_zombie/death(gibbed)
|
||||
if(!gibbed && prob(30))
|
||||
new /mob/living/basic/blackmesa/xen/headcrab(loc) // Headcrab detaches and survives!
|
||||
if(zombified_human)
|
||||
zombified_human.forceMove(get_turf(src))
|
||||
zombified_human = null
|
||||
qdel(src) // To ensure the non-player body gets deleted instead of there being two.
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/blackmesa/xen/headcrab_zombie/Destroy()
|
||||
if(zombified_human)
|
||||
zombified_human.forceMove(get_turf(src))
|
||||
zombified_human = null
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Zombie Variants
|
||||
* Different types of zombies with varying stats and corpses.
|
||||
*/
|
||||
|
||||
/// Scientist zombie - baseline zombie with standard stats
|
||||
/mob/living/basic/blackmesa/xen/headcrab_zombie/scientist
|
||||
name = "zombified scientist"
|
||||
desc = "Even after death, I still have to wear this horrible tie!"
|
||||
icon_state = "scientist_zombie"
|
||||
base_icon_state = "scientist_zombie"
|
||||
corpse_type = /obj/effect/mob_spawn/corpse/human/scientist_zombie
|
||||
|
||||
/// Security guard zombie - medium armor
|
||||
/mob/living/basic/blackmesa/xen/headcrab_zombie/guard
|
||||
name = "zombified guard"
|
||||
desc = "About that brain I owed ya!"
|
||||
icon_state = "security_zombie"
|
||||
base_icon_state = "security_zombie"
|
||||
maxHealth = 140
|
||||
health = 140
|
||||
corpse_type = /obj/effect/mob_spawn/corpse/human/guard_zombie
|
||||
|
||||
/// HECU Marine zombie - heavy armor
|
||||
/mob/living/basic/blackmesa/xen/headcrab_zombie/hecu
|
||||
name = "zombified marine"
|
||||
desc = "MY. ASS. IS. DEAD."
|
||||
icon_state = "hecu_zombie"
|
||||
base_icon_state = "hecu_zombie"
|
||||
maxHealth = 190
|
||||
health = 190
|
||||
corpse_type = /obj/effect/mob_spawn/corpse/human/hecu_zombie
|
||||
|
||||
/// HEV zombie - extremely tough due to the HEV suit
|
||||
/mob/living/basic/blackmesa/xen/headcrab_zombie/hev
|
||||
name = "zombified hazardous environment specialist"
|
||||
desc = "User death... surpassed."
|
||||
icon_state = "hev_zombie"
|
||||
base_icon_state = "hev_zombie"
|
||||
maxHealth = 250
|
||||
health = 250
|
||||
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv1.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv2.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv3.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv4.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv5.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv6.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv7.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv8.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv9.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv10.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv11.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv12.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv13.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/zombies/hzv14.ogg'
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* AI Controller
|
||||
* Handles the zombie's behavior and targeting
|
||||
*/
|
||||
/datum/ai_controller/basic_controller/headcrab_zombie
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_BASIC_MOB_CURRENT_TARGET = null,
|
||||
BB_BASIC_MOB_CURRENT_TARGET_HIDING = FALSE,
|
||||
BB_TARGET_MINIMUM_STAT = HARD_CRIT
|
||||
)
|
||||
|
||||
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/basic_melee_attack_subtree,
|
||||
/datum/ai_planning_subtree/target_retaliate
|
||||
)
|
||||
@@ -1,52 +0,0 @@
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/houndeye
|
||||
name = "houndeye"
|
||||
desc = "Some highly aggressive alien creature. Thrives in toxic environments."
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "houndeye"
|
||||
icon_living = "houndeye"
|
||||
icon_dead = "houndeye_dead"
|
||||
icon_gib = null
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BEAST
|
||||
environment_smash = ENVIRONMENT_SMASH_STRUCTURES
|
||||
speak_chance = 1
|
||||
speak_emote = list("growls")
|
||||
speed = 1
|
||||
emote_taunt = list("growls", "snarls", "grumbles")
|
||||
taunt_chance = 100
|
||||
turns_per_move = 7
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
obj_damage = 50
|
||||
harm_intent_damage = 10
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
attack_sound = 'sound/items/weapons/bite.ogg'
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
//Since those can survive on Xen, I'm pretty sure they can thrive on any atmosphere
|
||||
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 1500
|
||||
loot = list(/obj/item/stack/sheet/bluespace_crystal)
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/houndeye/he_alert1.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/houndeye/he_alert2.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/houndeye/he_alert3.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/houndeye/he_alert4.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/houndeye/he_alert5.ogg'
|
||||
)
|
||||
/// Charging ability
|
||||
var/datum/action/cooldown/mob_cooldown/charge/basic_charge/charge
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/houndeye/Initialize(mapload)
|
||||
. = ..()
|
||||
charge = new(src)
|
||||
charge.Grant(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/houndeye/Destroy()
|
||||
charge = null
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/houndeye/OpenFire()
|
||||
if(client)
|
||||
return
|
||||
charge.Trigger(target)
|
||||
@@ -0,0 +1,85 @@
|
||||
/mob/living/basic/blackmesa/xen/houndeye
|
||||
name = "houndeye"
|
||||
desc = "Some highly aggressive alien creature that attacks using sonic waves."
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "houndeye"
|
||||
base_icon_state = "houndeye"
|
||||
icon_living = "houndeye"
|
||||
icon_dead = "houndeye_dead"
|
||||
|
||||
// Stats
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
obj_damage = 50
|
||||
attack_sound = 'sound/items/tools/welder.ogg'
|
||||
attack_verb_continuous = "headbutts"
|
||||
attack_verb_simple = "headbutt"
|
||||
|
||||
// Sonic blast vars
|
||||
/// Whether we're currently charging up a sonic blast
|
||||
var/charging_sonic = FALSE
|
||||
/// World time when we can next use sonic blast
|
||||
var/next_sonic_blast = 0
|
||||
/// Sounds to play when charging sonic blast
|
||||
var/static/list/charge_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/houndeye/charge1.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/houndeye/charge2.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/houndeye/charge3.ogg'
|
||||
)
|
||||
|
||||
// Movement
|
||||
speed = 1
|
||||
ai_controller = /datum/ai_controller/basic_controller/houndeye
|
||||
basic_mob_flags = NONE
|
||||
|
||||
// Mob properties
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
|
||||
environment_smash = ENVIRONMENT_SMASH_STRUCTURES
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
|
||||
// Environmental resistances
|
||||
minimum_survivable_temperature = 0
|
||||
maximum_survivable_temperature = 1500
|
||||
|
||||
// Alert sounds from parent type will be used
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/houndeye/he_alert1.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/houndeye/he_alert2.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/houndeye/he_alert3.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/houndeye/he_alert4.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/houndeye/he_alert5.ogg'
|
||||
)
|
||||
|
||||
/**
|
||||
* Visual effect for sonic blast charging
|
||||
*
|
||||
* Creates a charging effect that follows the houndeye
|
||||
*/
|
||||
/obj/effect/temp_visual/spirit_hound_charge
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "lightning"
|
||||
duration = 1.5 SECONDS
|
||||
randomdir = FALSE
|
||||
layer = BELOW_MOB_LAYER
|
||||
plane = GAME_PLANE
|
||||
/// The mob we're attached to for following
|
||||
var/mob/attached_mob
|
||||
|
||||
/obj/effect/temp_visual/spirit_hound_charge/Initialize(mapload)
|
||||
. = ..()
|
||||
if(attached_mob)
|
||||
loc = attached_mob.loc
|
||||
|
||||
/**
|
||||
* Visual effect for the sonic blast wave
|
||||
*
|
||||
* Creates a visible indicator of the sonic blast's area of effect
|
||||
*/
|
||||
/obj/effect/temp_visual/sonicblast
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "shieldsparkles"
|
||||
duration = 5
|
||||
layer = ABOVE_MOB_LAYER
|
||||
plane = GAME_PLANE
|
||||
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* AI controller for houndeye basic mob
|
||||
* Handles charging behavior and basic targeting
|
||||
*/
|
||||
/datum/ai_controller/basic_controller/houndeye
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
|
||||
BB_LOW_PRIORITY_HUNTING_TARGET = null,
|
||||
)
|
||||
|
||||
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/basic_melee_attack_subtree/houndeye,
|
||||
/datum/ai_planning_subtree/target_retaliate
|
||||
)
|
||||
|
||||
/**
|
||||
* Custom melee attack subtree for houndeye that includes charging
|
||||
*/
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree/houndeye
|
||||
melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/houndeye
|
||||
|
||||
/**
|
||||
* Custom melee attack behavior that includes sonic blast
|
||||
*/
|
||||
/datum/ai_behavior/basic_melee_attack/houndeye
|
||||
action_cooldown = 50 // Longer cooldown between sonic blasts
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT
|
||||
required_distance = 5
|
||||
|
||||
/datum/ai_behavior/basic_melee_attack/houndeye/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
|
||||
var/mob/living/basic/blackmesa/xen/houndeye/living_pawn = controller.pawn
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
|
||||
if(QDELETED(target))
|
||||
finish_action(controller, FALSE)
|
||||
return
|
||||
|
||||
if(living_pawn.charging_sonic || world.time < living_pawn.next_sonic_blast)
|
||||
return
|
||||
|
||||
// Attempt to use sonic blast if possible
|
||||
if(can_sonic_blast(living_pawn, target))
|
||||
living_pawn.charging_sonic = TRUE
|
||||
living_pawn.next_sonic_blast = world.time + action_cooldown
|
||||
do_sonic_blast(living_pawn, target)
|
||||
finish_action(controller, TRUE)
|
||||
return
|
||||
|
||||
return ..() // Otherwise do normal melee attack
|
||||
|
||||
/**
|
||||
* Check if we can use sonic blast on the target
|
||||
*/
|
||||
/datum/ai_behavior/basic_melee_attack/houndeye/proc/can_sonic_blast(mob/living/basic/blackmesa/xen/houndeye/living_pawn, atom/target)
|
||||
if(!isliving(target))
|
||||
return FALSE
|
||||
|
||||
var/dist = get_dist(living_pawn, target)
|
||||
if(dist <= 5 && dist > 1) // Use sonic blast at medium range
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Perform the sonic blast attack
|
||||
*/
|
||||
/datum/ai_behavior/basic_melee_attack/houndeye/proc/do_sonic_blast(mob/living/basic/blackmesa/xen/houndeye/living_pawn, atom/target)
|
||||
// Start charging and prevent movement
|
||||
living_pawn.face_atom(target)
|
||||
living_pawn.set_anchored(TRUE)
|
||||
|
||||
living_pawn.visible_message(span_warning("[living_pawn] begins to charge up energy!"))
|
||||
playsound(living_pawn, pick(living_pawn.charge_sounds), 100, TRUE)
|
||||
|
||||
// Visual effect for charging
|
||||
var/obj/effect/temp_visual/spirit_hound_charge/charge_effect = new(living_pawn.loc)
|
||||
charge_effect.attached_mob = living_pawn
|
||||
|
||||
// After a delay, release the blast
|
||||
addtimer(CALLBACK(src, PROC_REF(release_sonic_blast), living_pawn, target), 1.5 SECONDS)
|
||||
|
||||
// Reset anchoring and state after the blast
|
||||
addtimer(CALLBACK(src, PROC_REF(reset_movement), living_pawn), 1.5 SECONDS)
|
||||
|
||||
/**
|
||||
* Helper proc to reset movement restrictions
|
||||
*/
|
||||
/datum/ai_behavior/basic_melee_attack/houndeye/proc/reset_movement(mob/living/basic/blackmesa/xen/houndeye/living_pawn)
|
||||
if(QDELETED(living_pawn))
|
||||
return
|
||||
living_pawn.set_anchored(FALSE)
|
||||
living_pawn.charging_sonic = FALSE
|
||||
|
||||
/**
|
||||
* Release the charged up sonic blast
|
||||
*/
|
||||
/datum/ai_behavior/basic_melee_attack/houndeye/proc/release_sonic_blast(mob/living/basic/blackmesa/xen/houndeye/living_pawn, atom/target)
|
||||
if(QDELETED(living_pawn) || QDELETED(target))
|
||||
return
|
||||
|
||||
// Create the blast effect
|
||||
var/list/turfs_to_hit = list()
|
||||
|
||||
// Get turfs in a cone shape in front of the houndeye
|
||||
for(var/turf/T in view(4, living_pawn))
|
||||
if(get_dist(living_pawn, T) > 4)
|
||||
continue
|
||||
if(angle2dir_cardinal(get_angle(living_pawn, T)) != living_pawn.dir)
|
||||
continue
|
||||
turfs_to_hit += T
|
||||
new /obj/effect/temp_visual/sonicblast(T)
|
||||
|
||||
// Deal damage to everything in the blast
|
||||
for(var/turf/T in turfs_to_hit)
|
||||
for(var/mob/living/L in T)
|
||||
if(L == living_pawn)
|
||||
continue
|
||||
var/dist_mod = 1 - (get_dist(living_pawn, L) / 5) // Less damage at max range
|
||||
var/damage = round(15 * dist_mod) // Base 15 damage, reduced by distance
|
||||
L.apply_damage(damage, BRUTE)
|
||||
L.apply_damage(damage, STAMINA) // Add stamina damage
|
||||
if(prob(50))
|
||||
L.Knockdown(10) // Shorter knockdown, 50% chance
|
||||
to_chat(L, span_warning("You're hit by [living_pawn]'s sonic blast!"))
|
||||
|
||||
// Break windows and weak objects, but less severely
|
||||
for(var/obj/O in T)
|
||||
if(istype(O, /obj/structure/window))
|
||||
O.take_damage(30)
|
||||
else if(istype(O, /obj/structure/table) || istype(O, /obj/structure/rack))
|
||||
O.take_damage(10)
|
||||
|
||||
// Play the blast sound
|
||||
playsound(living_pawn, 'sound/effects/explosion/explosioncreak2.ogg', 100, TRUE)
|
||||
living_pawn.visible_message(span_danger("[living_pawn] releases a powerful sonic blast!"))
|
||||
@@ -1,226 +0,0 @@
|
||||
/*
|
||||
* HECU
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/hecu
|
||||
name = "HECU Grunt"
|
||||
desc = "I didn't sign on for this shit. Monsters, sure, but civilians? Who ordered this operation anyway?"
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "hecu_melee"
|
||||
icon_living = "hecu_melee"
|
||||
icon_dead = "hecu_dead"
|
||||
icon_gib = "syndicate_gib"
|
||||
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
|
||||
sentience_type = SENTIENCE_HUMANOID
|
||||
speak_chance = 10
|
||||
speak = list("Stop right there!")
|
||||
turns_per_move = 5
|
||||
speed = 0
|
||||
stat_attack = HARD_CRIT
|
||||
robust_searching = 1
|
||||
maxHealth = 150
|
||||
health = 150
|
||||
harm_intent_damage = 5
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 10
|
||||
attack_verb_continuous = "punches"
|
||||
attack_verb_simple = "punch"
|
||||
attack_sound = 'sound/items/weapons/punch1.ogg'
|
||||
combat_mode = TRUE
|
||||
loot = list(/obj/effect/gibspawner/human, /obj/item/melee/baton)
|
||||
atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0)
|
||||
unsuitable_atmos_damage = 7.5
|
||||
faction = list(FACTION_HECU)
|
||||
check_friendly_fire = 1
|
||||
status_flags = CANPUSH
|
||||
del_on_death = 1
|
||||
dodging = TRUE
|
||||
rapid_melee = 2
|
||||
footstep_type = FOOTSTEP_MOB_SHOE
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert03.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert04.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert05.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert06.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert07.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert08.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert10.ogg'
|
||||
)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/hecu/ranged
|
||||
ranged = TRUE
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
icon_state = "hecu_ranged"
|
||||
icon_living = "hecu_ranged"
|
||||
casingtype = /obj/item/ammo_casing/a50ae
|
||||
projectilesound = 'sound/items/weapons/gun/pistol/shot.ogg'
|
||||
loot = list(/obj/effect/gibspawner/human, /obj/effect/spawner/random/hecu_deagle)
|
||||
dodging = TRUE
|
||||
rapid_melee = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/hecu/ranged/smg
|
||||
rapid = 3
|
||||
icon_state = "hecu_ranged_smg"
|
||||
icon_living = "hecu_ranged_smg"
|
||||
casingtype = /obj/item/ammo_casing/c34
|
||||
projectilesound = 'sound/items/weapons/gun/smg/shot.ogg'
|
||||
loot = list(/obj/effect/gibspawner/human, /obj/effect/spawner/random/hecu_smg)
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/sec
|
||||
name = "Security Guard"
|
||||
desc = "About that beer I owe'd ya!"
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "security_guard_melee"
|
||||
icon_living = "security_guard_melee"
|
||||
icon_dead = "security_guard_dead"
|
||||
icon_gib = "syndicate_gib"
|
||||
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
|
||||
sentience_type = SENTIENCE_HUMANOID
|
||||
turns_per_move = 5
|
||||
speed = 0
|
||||
stat_attack = HARD_CRIT
|
||||
robust_searching = 1
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
harm_intent_damage = 5
|
||||
melee_damage_lower = 7
|
||||
melee_damage_upper = 7
|
||||
attack_verb_continuous = "punches"
|
||||
attack_verb_simple = "punch"
|
||||
attack_sound = 'sound/items/weapons/punch1.ogg'
|
||||
loot = list(/obj/effect/gibspawner/human, /obj/item/clothing/suit/armor/vest/blueshirt)
|
||||
atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0)
|
||||
unsuitable_atmos_damage = 7.5
|
||||
faction = list(FACTION_STATION, FACTION_NEUTRAL)
|
||||
check_friendly_fire = 1
|
||||
status_flags = CANPUSH
|
||||
del_on_death = TRUE
|
||||
combat_mode = TRUE
|
||||
dodging = TRUE
|
||||
rapid_melee = 2
|
||||
footstep_type = FOOTSTEP_MOB_SHOE
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance02.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance02.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance03.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance04.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance05.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance06.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance07.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance08.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance09.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance10.ogg'
|
||||
)
|
||||
var/list/follow_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/leadon01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/leadon02.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/leadon03.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/leadtheway01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/leadtheway02.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/leadtheway03.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/leadtheway04.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/leadtheway05.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/leadtheway06.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/leadtheway07.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/leadtheway08.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/letsgo01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/letsgo02.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/letsgo03.ogg',
|
||||
)
|
||||
var/list/unfollow_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/holddownspot01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/holddownspot02.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/holddownspot03.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/holddownspot04.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/holddownspot05.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/illstayhere01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/illstayhere02.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/illstayhere03.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/imstickinghere01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/imstickinghere02.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/imstickinghere03.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/imstickinghere04.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/imstickinghere05.ogg',
|
||||
)
|
||||
var/follow_speed = 2
|
||||
var/follow_distance = 2
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/sec/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/follow, follow_sounds, unfollow_sounds, follow_distance, follow_speed)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/sec/ranged
|
||||
ranged = TRUE
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
icon_state = "security_guard_ranged"
|
||||
icon_living = "security_guard_ranged"
|
||||
casingtype = /obj/item/ammo_casing/c9mm
|
||||
projectilesound = 'sound/items/weapons/gun/pistol/shot.ogg'
|
||||
loot = list(/obj/effect/gibspawner/human, /obj/item/clothing/suit/armor/vest/blueshirt, /obj/item/gun/ballistic/automatic/pistol/sol)
|
||||
rapid_melee = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/blackops
|
||||
name = "black operative"
|
||||
desc = "Why do we always have to clean up a mess the grunts can't handle?"
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "blackops"
|
||||
icon_living = "blackops"
|
||||
icon_dead = "blackops"
|
||||
icon_gib = "syndicate_gib"
|
||||
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
|
||||
sentience_type = SENTIENCE_HUMANOID
|
||||
speak_chance = 10
|
||||
speak = list("Got a visual!")
|
||||
turns_per_move = 5
|
||||
speed = 0
|
||||
stat_attack = HARD_CRIT
|
||||
robust_searching = 1
|
||||
maxHealth = 200
|
||||
health = 200
|
||||
harm_intent_damage = 25
|
||||
melee_damage_lower = 30
|
||||
melee_damage_upper = 30
|
||||
attack_verb_continuous = "strikes"
|
||||
attack_verb_simple = "strikes"
|
||||
attack_sound = 'sound/effects/woodhit.ogg'
|
||||
combat_mode = TRUE
|
||||
loot = list(/obj/effect/gibspawner/human)
|
||||
atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0)
|
||||
unsuitable_atmos_damage = 7.5
|
||||
faction = list(FACTION_BLACKOPS)
|
||||
check_friendly_fire = 1
|
||||
status_flags = CANPUSH
|
||||
del_on_death = 1
|
||||
dodging = TRUE
|
||||
rapid_melee = 2
|
||||
footstep_type = FOOTSTEP_MOB_SHOE
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert02.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert03.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert04.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert05.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert06.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert07.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert08.ogg'
|
||||
)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/blackops/ranged
|
||||
ranged = TRUE
|
||||
rapid = 2
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
icon_state = "blackops_ranged"
|
||||
icon_living = "blackops_ranged"
|
||||
casingtype = /obj/item/ammo_casing/c40sol
|
||||
projectilesound = 'modular_skyrat/modules/modular_weapons/sounds/rifle_heavy.ogg'
|
||||
attack_sound = 'sound/items/weapons/punch1.ogg'
|
||||
loot = list(/obj/effect/gibspawner/human, /obj/item/ammo_box/magazine/c40sol_rifle/standard)
|
||||
rapid_melee = 1
|
||||
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* Black Mesa Human NPCs
|
||||
* Various human NPCs from Black Mesa including HECU, Security, and Black Ops.
|
||||
*/
|
||||
|
||||
/// Base type for all Black Mesa human NPCs
|
||||
/mob/living/basic/blackmesa/human
|
||||
// Mob traits
|
||||
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
|
||||
sentience_type = SENTIENCE_HUMANOID
|
||||
basic_mob_flags = DEL_ON_DEATH // Handle death manually for corpse spawning
|
||||
status_flags = CANPUSH
|
||||
|
||||
// Combat stats
|
||||
speed = 0
|
||||
combat_mode = TRUE
|
||||
attack_verb_continuous = "punches"
|
||||
attack_verb_simple = "punch"
|
||||
attack_sound = 'sound/items/weapons/punch1.ogg'
|
||||
|
||||
// Environmental resistances
|
||||
unsuitable_atmos_damage = 7.5
|
||||
habitable_atmos = list(
|
||||
"min_oxy" = 5, "max_oxy" = 0,
|
||||
"min_tox" = 0, "max_tox" = 1,
|
||||
"min_co2" = 0, "max_co2" = 5,
|
||||
"min_n2" = 0, "max_n2" = 0
|
||||
)
|
||||
minimum_survivable_temperature = T0C - 50
|
||||
maximum_survivable_temperature = T0C + 50
|
||||
|
||||
// AI behavior
|
||||
ai_controller = /datum/ai_controller/basic_controller
|
||||
|
||||
// Death handling
|
||||
/// The chance (0-100) to spawn a corpse instead of gibbing
|
||||
var/corpse_chance = 20
|
||||
/// The type of corpse to spawn on death
|
||||
var/obj/effect/mob_spawn/corpse/human/corpse
|
||||
/// The item to hold in the right hand
|
||||
var/obj/item/r_hand
|
||||
|
||||
|
||||
/mob/living/basic/blackmesa/human/death(gibbed)
|
||||
if(!gibbed)
|
||||
var/turf/T = get_turf(src)
|
||||
if(T)
|
||||
// Clean up any components with active timers first
|
||||
new /obj/effect/gibspawner/human(T)
|
||||
|
||||
if(prob(corpse_chance) && corpse)
|
||||
new corpse(T)
|
||||
|
||||
// Clean up any casings at our feet
|
||||
for(var/obj/item/ammo_casing/casing in T)
|
||||
qdel(casing)
|
||||
|
||||
qdel(src)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/blackmesa/human/hecu
|
||||
name = "HECU Grunt"
|
||||
desc = "I didn't sign on for this shit. Monsters, sure, but civilians? Who ordered this operation anyway?"
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "hecu_melee"
|
||||
icon_living = "hecu_melee"
|
||||
icon_dead = "hecu_dead"
|
||||
icon_gib = "syndicate_gib"
|
||||
maxHealth = 150
|
||||
health = 150
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 10
|
||||
faction = list(FACTION_HECU)
|
||||
ai_controller = /datum/ai_controller/basic_controller/hecu
|
||||
corpse = /obj/effect/mob_spawn/corpse/human/hecu
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert03.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert04.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert05.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert06.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert07.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert08.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/hecu/hg_alert10.ogg'
|
||||
)
|
||||
|
||||
|
||||
/mob/living/basic/blackmesa/human/hecu/ranged
|
||||
icon_state = "hecu_ranged"
|
||||
icon_living = "hecu_ranged"
|
||||
ai_controller = /datum/ai_controller/basic_controller/hecu/ranged
|
||||
corpse = /obj/effect/mob_spawn/corpse/human/hecu_ranged
|
||||
r_hand = /obj/item/gun/ballistic/automatic/pistol/deagle
|
||||
|
||||
/mob/living/basic/blackmesa/human/hecu/ranged/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(\
|
||||
/datum/component/ranged_attacks,\
|
||||
casing_type = /obj/item/ammo_casing/a50ae,\
|
||||
projectile_sound = 'sound/items/weapons/gun/pistol/shot.ogg',\
|
||||
cooldown_time = 5 SECONDS,\
|
||||
burst_shots = 1\
|
||||
)
|
||||
|
||||
/mob/living/basic/blackmesa/human/hecu/ranged/smg
|
||||
icon_state = "hecu_ranged_smg"
|
||||
icon_living = "hecu_ranged_smg"
|
||||
ai_controller = /datum/ai_controller/basic_controller/hecu/ranged
|
||||
corpse = /obj/effect/mob_spawn/corpse/human/hecu_smg
|
||||
r_hand = /obj/item/gun/ballistic/automatic/c20r
|
||||
|
||||
/mob/living/basic/blackmesa/human/hecu/ranged/smg/Initialize(mapload)
|
||||
. = ..()
|
||||
// Override parent's pistol component with SMG settings
|
||||
qdel(GetComponent(/datum/component/ranged_attacks))
|
||||
AddComponent(\
|
||||
/datum/component/ranged_attacks,\
|
||||
casing_type = /obj/item/ammo_casing/c45,\
|
||||
projectile_sound = 'sound/items/weapons/gun/smg/shot.ogg',\
|
||||
cooldown_time = 3 SECONDS,\
|
||||
burst_shots = 3\
|
||||
)
|
||||
|
||||
/mob/living/basic/blackmesa/human/sec
|
||||
name = "Security Guard"
|
||||
desc = "About that beer I owe'd ya!"
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "security_guard_melee"
|
||||
icon_living = "security_guard_melee"
|
||||
icon_dead = "security_guard_dead"
|
||||
icon_gib = "syndicate_gib"
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
melee_damage_lower = 7
|
||||
melee_damage_upper = 7
|
||||
faction = list(FACTION_STATION, FACTION_NEUTRAL)
|
||||
ai_controller = /datum/ai_controller/basic_controller/sec
|
||||
corpse = /obj/effect/mob_spawn/corpse/human/security_guard
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance02.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance03.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance04.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance05.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance06.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance07.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance08.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance09.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/security_guard/annoyance10.ogg'
|
||||
)
|
||||
|
||||
/mob/living/basic/blackmesa/human/sec/ranged
|
||||
icon_state = "security_guard_ranged"
|
||||
icon_living = "security_guard_ranged"
|
||||
ai_controller = /datum/ai_controller/basic_controller/sec/ranged
|
||||
corpse = /obj/effect/mob_spawn/corpse/human/security_guard/ranged
|
||||
r_hand = /obj/item/gun/ballistic/automatic/pistol/sol
|
||||
|
||||
/mob/living/basic/blackmesa/human/sec/ranged/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(\
|
||||
/datum/component/ranged_attacks,\
|
||||
casing_type = /obj/item/ammo_casing/c35sol,\
|
||||
projectile_sound = 'sound/items/weapons/gun/pistol/shot.ogg',\
|
||||
cooldown_time = 5 SECONDS,\
|
||||
burst_shots = 1\
|
||||
)
|
||||
|
||||
/mob/living/basic/blackmesa/human/blackops
|
||||
name = "black operative"
|
||||
desc = "Why do we always have to clean up a mess the grunts can't handle?"
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "blackops"
|
||||
icon_living = "blackops"
|
||||
icon_dead = "blackops"
|
||||
icon_gib = "syndicate_gib"
|
||||
maxHealth = 200
|
||||
health = 200
|
||||
melee_damage_lower = 30
|
||||
melee_damage_upper = 30
|
||||
attack_verb_continuous = "strikes"
|
||||
attack_verb_simple = "strikes"
|
||||
attack_sound = 'sound/effects/woodhit.ogg'
|
||||
faction = list(FACTION_BLACKOPS)
|
||||
ai_controller = /datum/ai_controller/basic_controller/blackops
|
||||
corpse = /obj/effect/mob_spawn/corpse/human/black_ops
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert02.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert03.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert04.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert05.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert06.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert07.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/blackops/bo_alert08.ogg'
|
||||
)
|
||||
|
||||
|
||||
/mob/living/basic/blackmesa/human/blackops/ranged
|
||||
icon_state = "blackops_ranged"
|
||||
icon_living = "blackops_ranged"
|
||||
ai_controller = /datum/ai_controller/basic_controller/blackops/ranged
|
||||
attack_sound = 'sound/items/weapons/punch1.ogg'
|
||||
corpse = /obj/effect/mob_spawn/corpse/human/black_ops/ranged
|
||||
r_hand = /obj/item/gun/ballistic/automatic/sol_rifle
|
||||
|
||||
/mob/living/basic/blackmesa/human/blackops/ranged/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(\
|
||||
/datum/component/ranged_attacks,\
|
||||
casing_type = /obj/item/ammo_casing/c40sol,\
|
||||
projectile_sound = 'sound/items/weapons/gun/rifle/shot.ogg',\
|
||||
cooldown_time = 4 SECONDS,\
|
||||
burst_shots = 3\
|
||||
)
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* AI Controllers
|
||||
*/
|
||||
|
||||
/// AI controller for HECU melee troops
|
||||
/datum/ai_controller/basic_controller/hecu
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_TARGET_MINIMUM_STAT = HARD_CRIT
|
||||
)
|
||||
|
||||
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/basic_melee_attack_subtree,
|
||||
/datum/ai_planning_subtree/target_retaliate
|
||||
)
|
||||
|
||||
/// AI controller for HECU ranged troops
|
||||
/datum/ai_controller/basic_controller/hecu/ranged
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/trooper,
|
||||
/datum/ai_planning_subtree/target_retaliate
|
||||
)
|
||||
|
||||
/// AI controller for security guards
|
||||
/datum/ai_controller/basic_controller/sec
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
|
||||
BB_BASIC_MOB_HATED_FACTIONS = list(FACTION_HECU, FACTION_BLACKOPS)
|
||||
)
|
||||
|
||||
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/basic_melee_attack_subtree,
|
||||
/datum/ai_planning_subtree/target_retaliate
|
||||
)
|
||||
|
||||
/// AI controller for ranged security guards
|
||||
/datum/ai_controller/basic_controller/sec/ranged
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/trooper,
|
||||
/datum/ai_planning_subtree/target_retaliate
|
||||
)
|
||||
|
||||
/// AI controller for black ops
|
||||
/datum/ai_controller/basic_controller/blackops
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_TARGET_MINIMUM_STAT = HARD_CRIT
|
||||
)
|
||||
|
||||
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/basic_melee_attack_subtree,
|
||||
/datum/ai_planning_subtree/target_retaliate
|
||||
)
|
||||
|
||||
/// AI controller for ranged black ops
|
||||
/datum/ai_controller/basic_controller/blackops/ranged
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/trooper,
|
||||
/datum/ai_planning_subtree/target_retaliate
|
||||
)
|
||||
|
||||
@@ -1,20 +1,40 @@
|
||||
/mob/living/simple_animal/hostile/blackmesa
|
||||
/mob/living/basic/blackmesa
|
||||
/// List of sounds to play when spotting enemies
|
||||
var/list/alert_sounds
|
||||
/// Time between alert sounds
|
||||
var/alert_cooldown = 3 SECONDS
|
||||
/// World time when we can make an alert sound again
|
||||
var/alert_cooldown_time
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen
|
||||
faction = list(FACTION_XEN)
|
||||
atmos_requirements = null
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 1500
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/Aggro()
|
||||
/mob/living/basic/blackmesa/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/ai_retaliate)
|
||||
if(alert_sounds)
|
||||
if(!(world.time <= alert_cooldown_time))
|
||||
playsound(src, pick(alert_sounds), 70)
|
||||
alert_cooldown_time = world.time + alert_cooldown
|
||||
RegisterSignal(src, COMSIG_AI_BLACKBOARD_KEY_SET(BB_BASIC_MOB_CURRENT_TARGET), PROC_REF(handle_alert))
|
||||
|
||||
/// Play a sound when spotting an enemy
|
||||
/mob/living/basic/blackmesa/proc/handle_alert(datum/source, key, value)
|
||||
SIGNAL_HANDLER
|
||||
if(world.time <= alert_cooldown_time)
|
||||
return
|
||||
if(prob(75)) // Don't always make noise
|
||||
playsound(src, pick(alert_sounds), 70)
|
||||
alert_cooldown_time = world.time + alert_cooldown
|
||||
|
||||
/mob/living/basic/blackmesa/xen
|
||||
faction = list(FACTION_XEN)
|
||||
minimum_survivable_temperature = 0
|
||||
maximum_survivable_temperature = 1500
|
||||
unsuitable_cold_damage = 15
|
||||
unsuitable_heat_damage = 15
|
||||
habitable_atmos = null // Can survive in any atmos
|
||||
|
||||
/// Can we be shielded by pylons?
|
||||
var/can_be_shielded = TRUE
|
||||
/// If we have support pylons, this is true.
|
||||
var/shielded = FALSE
|
||||
/// How many shields we have protecting us
|
||||
var/shield_count = 0
|
||||
|
||||
#define MOB_PLACER_RANGE 16 // One more tile than the biggest viewrange we have.
|
||||
|
||||
@@ -22,7 +42,7 @@
|
||||
name = "mob placer"
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mapping_helpers.dmi'
|
||||
icon_state = "mobspawner"
|
||||
var/list/possible_mobs = list(/mob/living/simple_animal/hostile/blackmesa/xen/headcrab)
|
||||
var/list/possible_mobs = list(/mob/living/basic/blackmesa/xen/headcrab)
|
||||
|
||||
/obj/effect/random_mob_placer/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -47,49 +67,49 @@
|
||||
/obj/effect/random_mob_placer/xen
|
||||
icon_state = "spawn_xen"
|
||||
possible_mobs = list(
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/houndeye,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/bullsquid,
|
||||
/mob/living/basic/blackmesa/xen/headcrab,
|
||||
/mob/living/basic/blackmesa/xen/houndeye,
|
||||
/mob/living/basic/blackmesa/xen/bullsquid,
|
||||
)
|
||||
|
||||
/obj/effect/random_mob_placer/xen/zombie
|
||||
icon_state = "spawn_zombie"
|
||||
possible_mobs = list(
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/scientist,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/guard,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/hecu,
|
||||
/mob/living/basic/blackmesa/xen/headcrab_zombie/scientist,
|
||||
/mob/living/basic/blackmesa/xen/headcrab_zombie/guard,
|
||||
/mob/living/basic/blackmesa/xen/headcrab_zombie/hecu,
|
||||
)
|
||||
|
||||
/obj/effect/random_mob_placer/blackops
|
||||
icon_state = "spawn_blackops"
|
||||
possible_mobs = list(
|
||||
/mob/living/simple_animal/hostile/blackmesa/blackops,
|
||||
/mob/living/simple_animal/hostile/blackmesa/blackops/ranged,
|
||||
/mob/living/basic/blackmesa/human/blackops,
|
||||
/mob/living/basic/blackmesa/human/blackops/ranged,
|
||||
)
|
||||
|
||||
/obj/effect/random_mob_placer/hev_zombie
|
||||
icon_state = "spawn_hev"
|
||||
possible_mobs = list(/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/hev)
|
||||
possible_mobs = list(/mob/living/basic/blackmesa/xen/headcrab_zombie/hev)
|
||||
|
||||
/obj/effect/random_mob_placer/scientist_zombie
|
||||
icon_state = "spawn_zombiescientist"
|
||||
possible_mobs = list(/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/scientist)
|
||||
possible_mobs = list(/mob/living/basic/blackmesa/xen/headcrab_zombie/scientist)
|
||||
|
||||
/obj/effect/random_mob_placer/scientist_zombie
|
||||
/obj/effect/random_mob_placer/guard_zombie
|
||||
icon_state = "spawn_zombiesec"
|
||||
possible_mobs = list(/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/guard)
|
||||
possible_mobs = list(/mob/living/basic/blackmesa/xen/headcrab_zombie/guard)
|
||||
|
||||
/obj/effect/random_mob_placer/security_guard
|
||||
icon_state = "spawn_guard"
|
||||
possible_mobs = list(/mob/living/simple_animal/hostile/blackmesa/sec, /mob/living/simple_animal/hostile/blackmesa/sec/ranged)
|
||||
possible_mobs = list(/mob/living/basic/blackmesa/human/sec, /mob/living/basic/blackmesa/human/sec/ranged,)
|
||||
|
||||
/obj/effect/random_mob_placer/vortigaunt_hostile
|
||||
icon_state = "spawn_vortigaunt_slave"
|
||||
possible_mobs = list(/mob/living/simple_animal/hostile/blackmesa/xen/vortigaunt/slave)
|
||||
possible_mobs = list(/mob/living/basic/blackmesa/xen/vortigaunt/slave)
|
||||
|
||||
/obj/effect/random_mob_placer/vortigaunt
|
||||
icon_state = "spawn_vortigaunt"
|
||||
possible_mobs = list(/mob/living/simple_animal/hostile/blackmesa/xen/vortigaunt)
|
||||
possible_mobs = list(/mob/living/basic/blackmesa/xen/vortigaunt)
|
||||
|
||||
/obj/effect/mob_spawn/corpse/human/hecu_zombie
|
||||
name = "HECU"
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/nihilanth
|
||||
name = "nihilanth"
|
||||
desc = "Holy shit."
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/nihilanth.dmi'
|
||||
icon_state = "nihilanth"
|
||||
icon_living = "nihilanth"
|
||||
SET_BASE_PIXEL(-32, -32)
|
||||
speed = 3
|
||||
bound_height = 64
|
||||
bound_width = 64
|
||||
icon_dead = "bullsquid_dead"
|
||||
maxHealth = 3000
|
||||
health = 3000
|
||||
atmos_requirements = null
|
||||
projectilesound = 'sound/items/weapons/lasercannonfire.ogg'
|
||||
projectiletype = /obj/projectile/nihilanth
|
||||
ranged = TRUE
|
||||
rapid = 3
|
||||
alert_cooldown = 2 MINUTES
|
||||
harm_intent_damage = 50
|
||||
melee_damage_lower = 30
|
||||
melee_damage_upper = 40
|
||||
attack_verb_continuous = "lathes"
|
||||
attack_verb_simple = "lathe"
|
||||
attack_sound = 'sound/items/weapons/punch1.ogg'
|
||||
status_flags = NONE
|
||||
del_on_death = TRUE
|
||||
wander = TRUE
|
||||
loot = list(/obj/effect/gibspawner/xeno, /obj/item/stack/sheet/bluespace_crystal/fifty, /obj/item/key/gateway, /obj/item/uber_teleporter)
|
||||
movement_type = FLYING
|
||||
|
||||
/obj/item/stack/sheet/bluespace_crystal/fifty
|
||||
amount = 50
|
||||
|
||||
/obj/projectile/nihilanth
|
||||
name = "portal energy"
|
||||
icon_state = "seedling"
|
||||
damage = 20
|
||||
damage_type = BURN
|
||||
light_range = 2
|
||||
armor_flag = ENERGY
|
||||
light_color = LIGHT_COLOR_BRIGHT_YELLOW
|
||||
hitsound = 'sound/items/weapons/sear.ogg'
|
||||
hitsound_wall = 'sound/items/weapons/effects/searwall.ogg'
|
||||
nondirectional_sprite = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/nihilanth/Aggro()
|
||||
. = ..()
|
||||
if(!(world.time <= alert_cooldown_time))
|
||||
alert_cooldown_time = world.time + alert_cooldown
|
||||
switch(health)
|
||||
if(0 to 999)
|
||||
playsound(src, pick(list('modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_pain01.ogg', 'modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_freeeemmaan01.ogg')), 100)
|
||||
if(1000 to 2999)
|
||||
playsound(src, pick(list('modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_youalldie01.ogg', 'modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_foryouhewaits01.ogg')), 100)
|
||||
if(3000 to 6000)
|
||||
playsound(src, pick(list('modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_whathavedone01.ogg', 'modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_deceiveyou01.ogg')), 100)
|
||||
else
|
||||
playsound(src, pick(list('modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_thetruth01.ogg', 'modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_iamthelast01.ogg')), 100)
|
||||
set_combat_mode(TRUE)
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/nihilanth/death(gibbed)
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/nihilanth/LoseAggro()
|
||||
. = ..()
|
||||
set_combat_mode(FALSE)
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Nihilanth - The final boss of Black Mesa
|
||||
*
|
||||
* A massive floating entity that serves as the master of the Xen forces.
|
||||
* Uses powerful ranged attacks and becomes more desperate as its health decreases.
|
||||
*/
|
||||
/mob/living/basic/blackmesa/xen/nihilanth
|
||||
name = "nihilanth"
|
||||
desc = "Holy shit."
|
||||
COOLDOWN_DECLARE(voice_cooldown)
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/nihilanth.dmi'
|
||||
icon_state = "nihilanth"
|
||||
icon_living = "nihilanth"
|
||||
pixel_x = -32
|
||||
base_pixel_x = -32
|
||||
pixel_y = -16 // Adjusted to move hitbox to bottom
|
||||
base_pixel_y = -16 // Adjusted to move hitbox to bottom
|
||||
density = TRUE
|
||||
move_force = MOVE_FORCE_OVERPOWERING
|
||||
move_resist = MOVE_FORCE_OVERPOWERING
|
||||
pull_force = MOVE_FORCE_OVERPOWERING
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
layer = LARGE_MOB_LAYER
|
||||
maptext_height = 96
|
||||
maptext_width = 96 //Keeps it above walls and structures
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE // Easier to click on
|
||||
icon_dead = "bullsquid_dead"
|
||||
appearance_flags = TILE_BOUND | PIXEL_SCALE | KEEP_TOGETHER
|
||||
maxHealth = 3000
|
||||
health = 3000
|
||||
obj_damage = 400
|
||||
melee_damage_lower = 30
|
||||
melee_damage_upper = 40
|
||||
armour_penetration = 40
|
||||
attack_verb_continuous = "lathes"
|
||||
attack_verb_simple = "lathe"
|
||||
attack_sound = 'sound/items/weapons/punch1.ogg'
|
||||
status_flags = NONE
|
||||
lighting_cutoff_red = 25
|
||||
lighting_cutoff_green = 15
|
||||
lighting_cutoff_blue = 35
|
||||
mob_biotypes = MOB_ORGANIC|MOB_SPECIAL|MOB_MINING
|
||||
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
|
||||
basic_mob_flags = DEL_ON_DEATH
|
||||
ai_controller = /datum/ai_controller/basic_controller/nihilanth
|
||||
|
||||
/// Items to drop on death
|
||||
var/static/list/death_loot = list(
|
||||
/obj/effect/gibspawner/xeno = 1,
|
||||
/obj/item/stack/sheet/bluespace_crystal/fifty = 1,
|
||||
/obj/item/key/gateway = 1,
|
||||
/obj/item/uber_teleporter = 1
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/bluespace_crystal/fifty
|
||||
amount = 50
|
||||
|
||||
/obj/projectile/nihilanth
|
||||
name = "portal energy"
|
||||
icon_state = "seedling"
|
||||
damage = 20
|
||||
damage_type = BURN
|
||||
light_range = 2
|
||||
armor_flag = ENERGY
|
||||
light_color = LIGHT_COLOR_BRIGHT_YELLOW
|
||||
hitsound = 'sound/items/weapons/sear.ogg'
|
||||
hitsound_wall = 'sound/items/weapons/effects/searwall.ogg'
|
||||
nondirectional_sprite = TRUE
|
||||
|
||||
/mob/living/basic/blackmesa/xen/nihilanth/Initialize(mapload)
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_IMMOBILIZED, INNATE_TRAIT) // Prevent unnecessary movement processing
|
||||
ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, INNATE_TRAIT) // Prevent unnecessary animation processing
|
||||
AddElement(/datum/element/death_drops, death_loot)
|
||||
AddElement(/datum/element/simple_flying)
|
||||
RegisterSignal(src, COMSIG_LIVING_DEATH, PROC_REF(on_death), override = TRUE)
|
||||
AddComponent(\
|
||||
/datum/component/ranged_attacks,\
|
||||
projectile_type = /obj/projectile/nihilanth,\
|
||||
projectile_sound = 'sound/items/weapons/lasercannonfire.ogg',\
|
||||
cooldown_time = 3 SECONDS,\
|
||||
burst_shots = 3\
|
||||
)
|
||||
update_appearance(UPDATE_ICON)
|
||||
|
||||
/// Called when nihilanth dies - play death sound
|
||||
/mob/living/basic/blackmesa/xen/nihilanth/proc/on_death(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
playsound(src, pick(list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_pain01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_freeeemmaan01.ogg'
|
||||
)), 100)
|
||||
|
||||
/mob/living/basic/blackmesa/xen/nihilanth/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE, required_bodytype)
|
||||
. = ..()
|
||||
if(amount <= 0 || !COOLDOWN_FINISHED(src, voice_cooldown)) // Don't play sounds for healing or during cooldown
|
||||
return
|
||||
var/list/sound_options
|
||||
switch(maxHealth - health) // Use remaining health instead of current health
|
||||
if(2001 to INFINITY) // 0-33% health remaining
|
||||
sound_options = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_pain01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_freeeemmaan01.ogg'
|
||||
)
|
||||
if(1001 to 2000) // 33-66% health remaining
|
||||
sound_options = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_youalldie01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_foryouhewaits01.ogg'
|
||||
)
|
||||
if(1 to 1000) // 66-99% health remaining
|
||||
sound_options = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_whathavedone01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_deceiveyou01.ogg'
|
||||
)
|
||||
else // Full health
|
||||
sound_options = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_thetruth01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/nihilanth/nihilanth_iamthelast01.ogg'
|
||||
)
|
||||
var/sound_to_play = pick(sound_options)
|
||||
var/sound_length = SSsounds.get_sound_length(sound_to_play)
|
||||
playsound(src, sound_to_play, 100)
|
||||
COOLDOWN_START(src, voice_cooldown, sound_length + 1 SECONDS)
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* AI controller for the Nihilanth boss mob
|
||||
*
|
||||
* Handles ranged combat behavior and targeting
|
||||
*/
|
||||
/datum/ai_controller/basic_controller/nihilanth
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
|
||||
BB_RANGED_SKIRMISH_MIN_DISTANCE = 3,
|
||||
BB_RANGED_SKIRMISH_MAX_DISTANCE = 5,
|
||||
BB_MAX_PATHING_ATTEMPTS = 2,
|
||||
BB_TARGETING_TIMEOUT = 30 SECONDS // Don't waste time searching if no targets found
|
||||
)
|
||||
|
||||
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/ranged_skirmish,
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/trooper,
|
||||
/datum/ai_planning_subtree/target_retaliate
|
||||
)
|
||||
@@ -1,64 +0,0 @@
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/vortigaunt
|
||||
name = "vortigaunt"
|
||||
desc = "There is no distance between us. No false veils of time or space may intervene."
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "vortigaunt"
|
||||
icon_living = "vortigaunt"
|
||||
icon_dead = "vortigaunt_dead"
|
||||
icon_gib = null
|
||||
gender = MALE
|
||||
faction = list(FACTION_STATION, FACTION_NEUTRAL)
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BEAST
|
||||
speak_chance = 1
|
||||
speak_emote = list("galungs")
|
||||
speed = 1
|
||||
emote_taunt = list("galalungas", "galungas", "gungs")
|
||||
projectiletype = /obj/projectile/beam/emitter/hitscan
|
||||
projectilesound = 'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/attack_shoot4.ogg'
|
||||
ranged_cooldown_time = 5 SECONDS
|
||||
ranged_message = "fires"
|
||||
taunt_chance = 100
|
||||
turns_per_move = 7
|
||||
maxHealth = 130
|
||||
health = 130
|
||||
speed = 3
|
||||
ranged = TRUE
|
||||
dodging = TRUE
|
||||
harm_intent_damage = 15
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 10
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
attack_sound = 'sound/items/weapons/bite.ogg'
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
loot = list(/obj/item/stack/sheet/bone)
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/alert01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/alert01b.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/alert02.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/alert03.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/alert04.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/alert05.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/alert06.ogg',
|
||||
)
|
||||
/// SOunds we play when asked to follow/unfollow.
|
||||
var/list/follow_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/village_argue01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/village_argue02.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/village_argue03.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/village_argue04.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/village_argue05.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/village_argue05a.ogg',
|
||||
)
|
||||
var/follow_speed = 1
|
||||
var/follow_distance = 2
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/vortigaunt/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/follow, follow_sounds, follow_sounds, follow_distance, follow_speed)
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/vortigaunt/slave
|
||||
name = "slave vortigaunt"
|
||||
desc = "Bound by the shackles of a sinister force. He does not want to hurt you."
|
||||
icon_state = "vortigaunt_slave"
|
||||
faction = list(FACTION_XEN)
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Vortigaunt - Allied alien being capable of ranged attacks
|
||||
*
|
||||
* A friendly alien that uses beam attacks and maintains distance from enemies.
|
||||
* Uses ranged skirmish AI to maintain optimal distance while attacking.
|
||||
*/
|
||||
/mob/living/basic/blackmesa/xen/vortigaunt
|
||||
name = "vortigaunt"
|
||||
desc = "There is no distance between us. No false veils of time or space may intervene."
|
||||
icon = 'modular_skyrat/modules/black_mesa/icons/mobs.dmi'
|
||||
icon_state = "vortigaunt"
|
||||
icon_living = "vortigaunt"
|
||||
icon_dead = "vortigaunt_dead"
|
||||
gender = MALE
|
||||
faction = list(FACTION_STATION, FACTION_NEUTRAL)
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
|
||||
|
||||
maxHealth = 130
|
||||
health = 130
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 10
|
||||
attack_sound = 'sound/items/weapons/bite.ogg'
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
|
||||
|
||||
ai_controller = /datum/ai_controller/basic_controller/vortigaunt
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
|
||||
/// Sounds played when spotting enemies
|
||||
alert_sounds = list(
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/alert01.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/alert01b.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/alert02.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/alert03.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/alert04.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/alert05.ogg',
|
||||
'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/alert06.ogg',
|
||||
)
|
||||
|
||||
/**
|
||||
* Initialize the vortigaunt with ranged attack capabilities
|
||||
*/
|
||||
/mob/living/basic/blackmesa/xen/vortigaunt/Initialize(mapload)
|
||||
. = ..()
|
||||
// Add ranged attack component
|
||||
AddComponent(\
|
||||
/datum/component/ranged_attacks,\
|
||||
projectile_type = /obj/projectile/beam/emitter/hitscan,\
|
||||
projectile_sound = 'modular_skyrat/modules/black_mesa/sound/mobs/vortigaunt/attack_shoot4.ogg',\
|
||||
cooldown_time = 5 SECONDS,\
|
||||
burst_shots = 1\
|
||||
)
|
||||
|
||||
/**
|
||||
* Slave Vortigaunt - Hostile variant that fights for the Xen forces
|
||||
*/
|
||||
/mob/living/basic/blackmesa/xen/vortigaunt/slave
|
||||
name = "slave vortigaunt"
|
||||
desc = "Bound by the shackles of a sinister force. He does not want to hurt you."
|
||||
icon_state = "vortigaunt_slave"
|
||||
faction = list(FACTION_XEN)
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* AI controller for vortigaunt mobs
|
||||
*
|
||||
* Handles ranged combat behavior and targeting
|
||||
*/
|
||||
/datum/ai_controller/basic_controller/vortigaunt
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
|
||||
BB_RANGED_SKIRMISH_MIN_DISTANCE = 3,
|
||||
BB_RANGED_SKIRMISH_MAX_DISTANCE = 6
|
||||
)
|
||||
|
||||
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/ranged_skirmish,
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/trooper,
|
||||
/datum/ai_planning_subtree/target_retaliate
|
||||
)
|
||||
@@ -1,23 +1,28 @@
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen
|
||||
/// Can we be shielded by pylons?
|
||||
var/can_be_shielded = TRUE
|
||||
/// If we have support pylons, this is true.
|
||||
var/shielded = FALSE
|
||||
/// How many shields we have protecting us
|
||||
var/shield_count = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/update_overlays()
|
||||
/mob/living/basic/blackmesa/xen/update_overlays()
|
||||
. = ..()
|
||||
if(shielded)
|
||||
. += mutable_appearance('icons/effects/effects.dmi', "shield-yellow", MOB_SHIELD_LAYER)
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/proc/lose_shield()
|
||||
/mob/living/basic/blackmesa/xen/proc/lose_shield()
|
||||
shield_count--
|
||||
if(shield_count <= 0)
|
||||
shielded = FALSE
|
||||
update_appearance()
|
||||
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, exposed_wound_bonus = 0, sharpness = NONE, attack_direction = null, attacking_item)
|
||||
/mob/living/basic/blackmesa/xen/apply_damage(
|
||||
damage = 0,
|
||||
damagetype = BRUTE,
|
||||
def_zone = null,
|
||||
blocked = 0,
|
||||
forced = FALSE,
|
||||
spread_damage = FALSE,
|
||||
wound_bonus = 0,
|
||||
exposed_wound_bonus = 0,
|
||||
sharpness = NONE,
|
||||
attack_direction = null,
|
||||
attacking_item,
|
||||
wound_clothing = TRUE,
|
||||
)
|
||||
if(shielded)
|
||||
balloon_alert_to_viewers("ineffective!")
|
||||
return FALSE
|
||||
@@ -38,7 +43,7 @@
|
||||
|
||||
/obj/structure/xen_pylon/Initialize(mapload)
|
||||
. = ..()
|
||||
for(var/mob/living/simple_animal/hostile/blackmesa/xen/iterating_mob in range(shield_range, src))
|
||||
for(var/mob/living/basic/blackmesa/xen/iterating_mob in range(shield_range, src))
|
||||
if(!iterating_mob.can_be_shielded)
|
||||
continue
|
||||
register_mob(iterating_mob)
|
||||
@@ -49,12 +54,12 @@
|
||||
SIGNAL_HANDLER
|
||||
if(!isxenmob(entered_atom))
|
||||
return
|
||||
var/mob/living/simple_animal/hostile/blackmesa/xen/entered_xen_mob = entered_atom
|
||||
var/mob/living/basic/blackmesa/xen/entered_xen_mob = entered_atom
|
||||
if(!entered_xen_mob.can_be_shielded)
|
||||
return
|
||||
register_mob(entered_xen_mob)
|
||||
|
||||
/obj/structure/xen_pylon/proc/register_mob(mob/living/simple_animal/hostile/blackmesa/xen/mob_to_register)
|
||||
/obj/structure/xen_pylon/proc/register_mob(mob/living/basic/blackmesa/xen/mob_to_register)
|
||||
if(mob_to_register in shielded_mobs)
|
||||
return
|
||||
if(!istype(mob_to_register))
|
||||
@@ -77,14 +82,14 @@
|
||||
|
||||
/obj/structure/xen_pylon/proc/beam_died(datum/beam/beam_to_kill)
|
||||
SIGNAL_HANDLER
|
||||
for(var/mob/living/simple_animal/hostile/blackmesa/xen/iterating_mob as anything in shielded_mobs)
|
||||
for(var/mob/living/basic/blackmesa/xen/iterating_mob as anything in shielded_mobs)
|
||||
if(shielded_mobs[iterating_mob] == beam_to_kill)
|
||||
iterating_mob.lose_shield()
|
||||
shielded_mobs[iterating_mob] = null
|
||||
shielded_mobs -= iterating_mob
|
||||
|
||||
/obj/structure/xen_pylon/Destroy()
|
||||
for(var/mob/living/simple_animal/hostile/blackmesa/xen/iterating_mob as anything in shielded_mobs)
|
||||
for(var/mob/living/basic/blackmesa/xen/iterating_mob as anything in shielded_mobs)
|
||||
iterating_mob.lose_shield()
|
||||
var/datum/beam/beam = shielded_mobs[iterating_mob]
|
||||
QDEL_NULL(beam)
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
|
||||
/turf/open/water/xen_acid/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
|
||||
. = ..()
|
||||
if(isliving(arrived) && !istype(arrived, /mob/living/simple_animal/hostile/blackmesa/xen/bullsquid)) // Bull squid territory!
|
||||
if(isliving(arrived) && !istype(arrived, /mob/living/basic/blackmesa/xen/bullsquid)) // Bull squid territory!
|
||||
var/mob/living/unlucky_mob = arrived
|
||||
unlucky_mob.adjustFireLoss(acid_damage)
|
||||
playsound(unlucky_mob, 'sound/items/weapons/sear.ogg', 100, TRUE)
|
||||
|
||||
@@ -52,8 +52,8 @@
|
||||
var/factions = list(FACTION_STATION, "neutral")
|
||||
/// Mobs in this list will not be affected by this grenade.
|
||||
var/list/blacklisted_mobs = list(
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/headcrab_zombie/gordon_freeman,
|
||||
/mob/living/simple_animal/hostile/blackmesa/xen/nihilanth,
|
||||
/mob/living/basic/blackmesa/xen/gordon_freeman,
|
||||
/mob/living/basic/blackmesa/xen/nihilanth,
|
||||
)
|
||||
|
||||
/obj/item/grenade/xen_crystal/detonate(mob/living/lanced_by)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
faction = list(NEST_FACTION)
|
||||
var/spawn_delay = 0
|
||||
/// What mob to spawn
|
||||
var/list/monster_types = list(/mob/living/simple_animal/hostile/blackmesa/xen/headcrab)
|
||||
var/list/monster_types = list(/mob/living/basic/blackmesa/xen/headcrab)
|
||||
/// How many mobs can we spawn?
|
||||
var/max_mobs = 3
|
||||
var/spawned_mobs = 0
|
||||
|
||||
+17
-8
@@ -7469,15 +7469,24 @@
|
||||
#include "modular_skyrat\modules\black_mesa\code\armaments\armament_miscellaneous.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\armaments\armament_utility.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\armaments\hecu_armament_station.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\bullsquid.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\gordon_freeman.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\headcrab.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\headcrab_zombie.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\houndeye.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\human_mobs.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\corpse_spawns.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\mob_spawners.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\nihilanth.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\vortigaunt.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\bullsquid\bullsquid.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\bullsquid\bullsquid_ai.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\gordon_freeman\gordon_freeman.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\gordon_freeman\gordon_freeman_ai.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\headcrab\headcrab.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\headcrab\headcrab_ai.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\headcrab_zombie\headcrab_zombie.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\headcrab_zombie\headcrab_zombie_ai.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\houndeye\houndeye.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\houndeye\houndeye_ai.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\human_mobs\human_mobs.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\human_mobs\human_mobs_ai.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\nihilanth\nihilanth.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\nihilanth\nihilanth_ai.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\vortigaunt\vortigaunt.dm"
|
||||
#include "modular_skyrat\modules\black_mesa\code\mobs\vortigaunt\vortigaunt_ai.dm"
|
||||
#include "modular_skyrat\modules\blastwave_outfits\code\cargo_packs.dm"
|
||||
#include "modular_skyrat\modules\blastwave_outfits\code\clothing\blastwave_head.dm"
|
||||
#include "modular_skyrat\modules\blastwave_outfits\code\clothing\blastwave_mask.dm"
|
||||
|
||||
Reference in New Issue
Block a user