Skip to content

Commit

Permalink
Xeno structure alert fixes (#16797)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lumipharon authored Dec 14, 2024
1 parent 4e096fb commit 9ef6652
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 169 deletions.
7 changes: 1 addition & 6 deletions code/__DEFINES/mobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -549,14 +549,9 @@ GLOBAL_LIST_INIT(layers_to_offset, list(
#define XENO_HEALTH_ALERT_TRIGGER_PERCENT 0.25 //If a xeno is damaged while its current hit points are less than this percent of its maximum, we send out an alert to the hive
#define XENO_HEALTH_ALERT_TRIGGER_THRESHOLD 50 //If a xeno is damaged while its current hit points are less than this amount, we send out an alert to the hive
#define XENO_HEALTH_ALERT_COOLDOWN 60 SECONDS //The cooldown on these xeno damage alerts
#define XENO_SILO_HEALTH_ALERT_COOLDOWN 30 SECONDS //The cooldown on these xeno damage alerts
#define XENO_HEALTH_ALERT_POINTER_DURATION 6 SECONDS //How long the alert directional pointer lasts.
#define XENO_RALLYING_POINTER_DURATION 15 SECONDS //How long the rally hive pointer lasts
#define XENO_SILO_DAMAGE_POINTER_DURATION 10 SECONDS //How long the alert directional pointer lasts when silos are damaged
#define XENO_SILO_DETECTION_COOLDOWN 1 MINUTES
#define XENO_SILO_DETECTION_RANGE 10//How far silos can detect hostiles
#define XENO_GARGOYLE_DETECTION_COOLDOWN 30 SECONDS
#define XENO_GARGOYLE_DETECTION_RANGE 10//How far gargoyles can detect hostiles

#define XENO_RESTING_COOLDOWN 2 SECONDS
#define XENO_UNRESTING_COOLDOWN 0.5 SECONDS

Expand Down
13 changes: 13 additions & 0 deletions code/__DEFINES/xeno.dm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
#define HAS_OVERLAY (1<<1)
#define CRITICAL_STRUCTURE (1<<2)
#define DEPART_DESTRUCTION_IMMUNE (1<<3)
///Structure will warn when hostiles are nearby
#define XENO_STRUCT_WARNING_RADIUS (1<<4)
///Structure will warn when damaged
#define XENO_STRUCT_DAMAGE_ALERT (1<<5)

//Weeds defines
#define WEED "weed sac"
Expand Down Expand Up @@ -210,3 +214,12 @@ GLOBAL_LIST_INIT(xeno_ai_spawnable, list(

/// Life runs every 2 seconds, but we don't want to multiply all healing by 2 due to seconds_per_tick
#define XENO_PER_SECOND_LIFE_MOD 0.5

//How long the alert directional pointer lasts when structures are damaged
#define XENO_STRUCTURE_DAMAGE_POINTER_DURATION 10 SECONDS
///How frequently the damage alert can go off
#define XENO_STRUCTURE_HEALTH_ALERT_COOLDOWN 30 SECONDS
///How frequently the proximity alert can go off
#define XENO_STRUCTURE_DETECTION_COOLDOWN 30 SECONDS
///Proxy detection radius
#define XENO_STRUCTURE_DETECTION_RANGE 10
4 changes: 2 additions & 2 deletions code/_onclick/hud/screen_objects/screen_objects.dm
Original file line number Diff line number Diff line change
Expand Up @@ -744,12 +744,12 @@
/atom/movable/screen/arrow/silo_damaged_arrow
name = "Hive damaged tracker arrow"
icon_state = "Red_arrow"
duration = XENO_SILO_DAMAGE_POINTER_DURATION
duration = XENO_STRUCTURE_DAMAGE_POINTER_DURATION

/atom/movable/screen/arrow/turret_attacking_arrow
name = "Turret attacking arrow"
icon_state = "Green_arrow"
duration = XENO_SILO_DAMAGE_POINTER_DURATION
duration = XENO_STRUCTURE_DAMAGE_POINTER_DURATION

/atom/movable/screen/arrow/attack_order_arrow
name = "attack order arrow"
Expand Down
80 changes: 80 additions & 0 deletions code/modules/xenomorph/_xeno_structure.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
var/xeno_structure_flags
///Which hive(number) do we belong to?
var/hivenumber = XENO_HIVE_NORMAL
///Is the structure currently detecting a threat
var/threat_warning
///List of turfs we are checking for hostiles in
var/list/prox_warning_turfs = list()
COOLDOWN_DECLARE(proxy_alert_cooldown)
COOLDOWN_DECLARE(damage_alert_cooldown)

/obj/structure/xeno/Initialize(mapload, _hivenumber)
. = ..()
Expand All @@ -16,8 +22,11 @@
LAZYADDASSOC(GLOB.xeno_structures_by_hive, hivenumber, src)
if(xeno_structure_flags & CRITICAL_STRUCTURE)
LAZYADDASSOC(GLOB.xeno_critical_structures_by_hive, hivenumber, src)
if((xeno_structure_flags & XENO_STRUCT_WARNING_RADIUS))
set_proximity_warning()

/obj/structure/xeno/Destroy()
//prox_warning_turfs = null
if(!locate(src) in GLOB.xeno_structures_by_hive[hivenumber]+GLOB.xeno_critical_structures_by_hive[hivenumber]) //The rest of the proc is pointless to look through if its not in the lists
stack_trace("[src] not found in the list of (potentially critical) xeno structures!") //We dont want to CRASH because that'd block deletion completely. Just trace it and continue.
return ..()
Expand Down Expand Up @@ -49,6 +58,11 @@
SIGNAL_HANDLER
obj_destruction(damage_flag = MELEE)

/obj/structure/xeno/take_damage(damage_amount, damage_type = BRUTE, armor_type = null, effects = TRUE, attack_dir, armour_penetration = 0, mob/living/blame_mob)
. = ..()
if(xeno_structure_flags & XENO_STRUCT_DAMAGE_ALERT)
damage_alert()

/obj/structure/xeno/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = xeno_attacker.xeno_caste.melee_ap, isrightclick = FALSE)
if(!(HAS_TRAIT(xeno_attacker, TRAIT_VALHALLA_XENO) && xeno_attacker.a_intent == INTENT_HARM && (tgui_alert(xeno_attacker, "Are you sure you want to tear down [src]?", "Tear down [src]?", list("Yes","No"))) == "Yes"))
return ..()
Expand Down Expand Up @@ -77,3 +91,69 @@
take_damage(max(0, plasmacutter.force * (1 + PLASMACUTTER_RESIN_MULTIPLIER)), plasmacutter.damtype, MELEE)
playsound(src, SFX_ALIEN_RESIN_BREAK, 25)
return TRUE

/obj/structure/xeno/silo/Moved(atom/old_loc, movement_dir, forced, list/old_locs)
. = ..()
if((xeno_structure_flags & XENO_STRUCT_WARNING_RADIUS))
set_proximity_warning()

///Sets the proxy signals for our loc, removing the old ones if any
/obj/structure/xeno/proc/set_proximity_warning()
for(var/old_turf in prox_warning_turfs)
UnregisterSignal(old_turf, COMSIG_ATOM_ENTERED)
prox_warning_turfs.Cut()

for(var/new_turf in RANGE_TURFS(XENO_STRUCTURE_DETECTION_RANGE, src))
RegisterSignal(new_turf, COMSIG_ATOM_ENTERED, PROC_REF(proxy_alert))
prox_warning_turfs += new_turf

///Alerts the Hive when hostiles get too close to this structure
/obj/structure/xeno/proc/proxy_alert(datum/source, atom/movable/hostile)
SIGNAL_HANDLER

if(!COOLDOWN_CHECK(src, proxy_alert_cooldown))
return

if(!iscarbon(hostile) && !isvehicle(hostile))
return

if(iscarbon(hostile))
var/mob/living/carbon/carbon_triggerer = hostile
if(carbon_triggerer.stat == DEAD)
return
if(isxeno(hostile))
var/mob/living/carbon/xenomorph/xeno_triggerer = hostile
if(xeno_triggerer.hive == GLOB.hive_datums[hivenumber]) //Trigger proxy alert only for hostile xenos
return

if(isvehicle(hostile))
var/obj/vehicle/vehicle_triggerer = hostile
if(vehicle_triggerer.trigger_gargoyle == FALSE)
return

threat_warning = TRUE
GLOB.hive_datums[hivenumber].xeno_message("Our [name] has detected a nearby hostile [hostile] at [get_area(hostile)] (X: [hostile.x], Y: [hostile.y]).", "xenoannounce", 5, FALSE, hostile, 'sound/voice/alien/help1.ogg', FALSE, null, /atom/movable/screen/arrow/leader_tracker_arrow)
COOLDOWN_START(src, proxy_alert_cooldown, XENO_STRUCTURE_DETECTION_COOLDOWN)
addtimer(CALLBACK(src, PROC_REF(clear_warning)), XENO_STRUCTURE_DETECTION_COOLDOWN)
update_minimap_icon()
update_appearance(UPDATE_ICON)

///Notifies the hive when we take damage
/obj/structure/xeno/proc/damage_alert()
if(!COOLDOWN_CHECK(src, damage_alert_cooldown))
return
threat_warning = TRUE
update_minimap_icon()
GLOB.hive_datums[hivenumber].xeno_message("Our [name] at [AREACOORD_NO_Z(src)] is under attack! It has [obj_integrity]/[max_integrity] Health remaining.", "xenoannounce", 5, FALSE, src, 'sound/voice/alien/help1.ogg',FALSE, null, /atom/movable/screen/arrow/silo_damaged_arrow)
COOLDOWN_START(src, damage_alert_cooldown, XENO_STRUCTURE_HEALTH_ALERT_COOLDOWN)
addtimer(CALLBACK(src, PROC_REF(clear_warning)), XENO_STRUCTURE_HEALTH_ALERT_COOLDOWN)

///Clears any threat warnings
/obj/structure/xeno/proc/clear_warning()
threat_warning = FALSE
update_minimap_icon()
update_appearance(UPDATE_ICON)

///resets minimap icon for structure
/obj/structure/xeno/proc/update_minimap_icon()
return
53 changes: 4 additions & 49 deletions code/modules/xenomorph/resin_gargoyle.dm
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,21 @@
icon = 'icons/Xeno/2x2building.dmi'
icon_state = "gargoyle"
max_integrity = 100
xeno_structure_flags = CRITICAL_STRUCTURE|IGNORE_WEED_REMOVAL
///Bool if we're currently alerting
var/is_alerting = FALSE
//cd tracking for the alert
COOLDOWN_DECLARE(proxy_alert_cooldown)
xeno_structure_flags = CRITICAL_STRUCTURE|IGNORE_WEED_REMOVAL|XENO_STRUCT_WARNING_RADIUS

/obj/structure/xeno/resin_gargoyle/Initialize(mapload, _hivenumber, mob/living/carbon/xenomorph/creator)
. = ..()
for(var/turfs in RANGE_TURFS(XENO_GARGOYLE_DETECTION_RANGE, src))
RegisterSignal(turfs, COMSIG_ATOM_ENTERED, PROC_REF(gargoyle_alarm))
add_overlay(emissive_appearance(icon, "[icon_state]_emissive"))
INVOKE_ASYNC(src, PROC_REF(set_name), creator)
update_minimap_icon()

/obj/structure/xeno/resin_gargoyle/proc/set_name(mob/living/carbon/xenomorph/creator)
name = initial(name) + " (" + tgui_input_text(creator, "Add a gargoyle name", "Naming") + ")"

/// Checks performed every time an atom moves in a turf watched by the gargoyle
/obj/structure/xeno/resin_gargoyle/proc/gargoyle_alarm(datum/source, atom/movable/hostile, direction)
SIGNAL_HANDLER

if(!COOLDOWN_CHECK(src, proxy_alert_cooldown))
return

if(!iscarbon(hostile) && !isvehicle(hostile))
return

if(iscarbon(hostile))
var/mob/living/carbon/carbon_triggerer = hostile
if(carbon_triggerer.stat == DEAD)
return

if(isxeno(hostile))
var/mob/living/carbon/xenomorph/X = hostile
if(X.hive == GLOB.hive_datums[hivenumber]) //Trigger proxy alert only for hostile xenos
return

if(isvehicle(hostile))
var/obj/vehicle/vehicle_triggerer = hostile
if(vehicle_triggerer.trigger_gargoyle == FALSE)
return

is_alerting = TRUE
GLOB.hive_datums[hivenumber].xeno_message("Our [name] has detected a hostile [hostile] at [get_area(hostile)].", "xenoannounce", 5, FALSE, hostile, 'sound/voice/alien/talk2.ogg', FALSE, null, /atom/movable/screen/arrow/leader_tracker_arrow)
COOLDOWN_START(src, proxy_alert_cooldown, XENO_GARGOYLE_DETECTION_COOLDOWN)
addtimer(CALLBACK(src, PROC_REF(clear_warning)), XENO_GARGOYLE_DETECTION_COOLDOWN, TIMER_STOPPABLE)
update_minimap_icon()
update_appearance()

///resets gargoyle to normal state after yelling
/obj/structure/xeno/resin_gargoyle/proc/clear_warning()
is_alerting = FALSE
update_minimap_icon()
update_appearance()

/obj/structure/xeno/resin_gargoyle/update_icon_state()
. = ..()
icon_state = is_alerting ? "gargoyle_alarm" : "gargoyle"
icon_state = threat_warning ? "gargoyle_alarm" : "gargoyle"

///resets minimap icon for the gargoyle
/obj/structure/xeno/resin_gargoyle/proc/update_minimap_icon()
/obj/structure/xeno/resin_gargoyle/update_minimap_icon()
SSminimaps.remove_marker(src)
SSminimaps.add_marker(src, MINIMAP_FLAG_XENO, image('icons/UI_icons/map_blips.dmi', null, "gargoyle[is_alerting ? "_warn" : "_passive"]", ABOVE_FLOAT_LAYER))
SSminimaps.add_marker(src, MINIMAP_FLAG_XENO, image('icons/UI_icons/map_blips.dmi', null, "gargoyle[threat_warning ? "_warn" : "_passive"]", ABOVE_FLOAT_LAYER))
64 changes: 9 additions & 55 deletions code/modules/xenomorph/silo.dm
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,19 @@
bound_height = 96
max_integrity = 1000
resistance_flags = UNACIDABLE | DROPSHIP_IMMUNE | PLASMACUTTER_IMMUNE
xeno_structure_flags = IGNORE_WEED_REMOVAL|CRITICAL_STRUCTURE
xeno_structure_flags = IGNORE_WEED_REMOVAL|CRITICAL_STRUCTURE|XENO_STRUCT_WARNING_RADIUS|XENO_STRUCT_DAMAGE_ALERT
///How many larva points one silo produce in one minute
var/larva_spawn_rate = 0.5
var/turf/center_turf
var/number_silo
///For minimap icon change if silo takes damage or nearby hostile
var/warning
COOLDOWN_DECLARE(silo_damage_alert_cooldown)
COOLDOWN_DECLARE(silo_proxy_alert_cooldown)

/obj/structure/xeno/silo/Initialize(mapload, _hivenumber)
. = ..()
center_turf = get_step(src, NORTHEAST)
if(!istype(center_turf))
center_turf = loc

if(SSticker.mode?.round_type_flags & MODE_SILO_RESPAWN)
for(var/turfs in RANGE_TURFS(XENO_SILO_DETECTION_RANGE, src))
RegisterSignal(turfs, COMSIG_ATOM_ENTERED, PROC_REF(resin_silo_proxy_alert))

if(SSticker.mode?.round_type_flags & MODE_SILOS_SPAWN_MINIONS)
SSspawning.registerspawner(src, INFINITY, GLOB.xeno_ai_spawnable, 0, 0, CALLBACK(src, PROC_REF(on_spawn)))
SSspawning.spawnerdata[src].required_increment = 2 * max(45 SECONDS, 3 MINUTES - SSmonitor.maximum_connected_players_count * SPAWN_RATE_PER_PLAYER)/SSspawning.wait
Expand All @@ -36,7 +29,6 @@

return INITIALIZE_HINT_LATELOAD


/obj/structure/xeno/silo/LateInitialize()
. = ..()
var/siloprefix = GLOB.hive_datums[hivenumber].name
Expand All @@ -56,6 +48,11 @@
newt.tunnel_desc = "[AREACOORD_NO_Z(newt)]"
newt.name += " [name]"

/obj/structure/xeno/silo/set_proximity_warning()
if(!(SSticker.mode?.round_type_flags & MODE_SILO_RESPAWN))
return
return ..()

/obj/structure/xeno/silo/obj_destruction(damage_amount, damage_type, damage_flag, mob/living/blame_mob)
if(GLOB.hive_datums[hivenumber])
UnregisterSignal(GLOB.hive_datums[hivenumber], list(COMSIG_HIVE_XENO_MOTHER_PRE_CHECK, COMSIG_HIVE_XENO_MOTHER_CHECK))
Expand Down Expand Up @@ -93,51 +90,13 @@

/obj/structure/xeno/silo/take_damage(damage_amount, damage_type = BRUTE, armor_type = null, effects = TRUE, attack_dir, armour_penetration = 0, mob/living/blame_mob)
. = ..()

//We took damage, so it's time to start regenerating if we're not already processing
if(!CHECK_BITFIELD(datum_flags, DF_ISPROCESSING))
START_PROCESSING(SSslowprocess, src)

resin_silo_damage_alert()

/obj/structure/xeno/silo/proc/resin_silo_damage_alert()
if(!COOLDOWN_CHECK(src, silo_damage_alert_cooldown))
return
warning = TRUE
update_minimap_icon()
GLOB.hive_datums[hivenumber].xeno_message("Our [name] at [AREACOORD_NO_Z(src)] is under attack! It has [obj_integrity]/[max_integrity] Health remaining.", "xenoannounce", 5, FALSE, src, 'sound/voice/alien/help1.ogg',FALSE, null, /atom/movable/screen/arrow/silo_damaged_arrow)
COOLDOWN_START(src, silo_damage_alert_cooldown, XENO_SILO_HEALTH_ALERT_COOLDOWN) //set the cooldown.
addtimer(CALLBACK(src, PROC_REF(clear_warning)), XENO_SILO_HEALTH_ALERT_COOLDOWN) //clear warning

///Alerts the Hive when hostiles get too close to their resin silo
/obj/structure/xeno/silo/proc/resin_silo_proxy_alert(datum/source, atom/movable/hostile, direction)
SIGNAL_HANDLER

if(!COOLDOWN_CHECK(src, silo_proxy_alert_cooldown)) //Proxy alert triggered too recently; abort
return

if(!isliving(hostile))
return

var/mob/living/living_triggerer = hostile
if(living_triggerer.stat == DEAD) //We don't care about the dead
return

if(isxeno(hostile))
var/mob/living/carbon/xenomorph/X = hostile
if(X.hive == GLOB.hive_datums[hivenumber]) //Trigger proxy alert only for hostile xenos
return

warning = TRUE
update_minimap_icon()
GLOB.hive_datums[hivenumber].xeno_message("Our [name] has detected a nearby hostile [hostile] at [get_area(hostile)] (X: [hostile.x], Y: [hostile.y]).", "xenoannounce", 5, FALSE, hostile, 'sound/voice/alien/help1.ogg', FALSE, null, /atom/movable/screen/arrow/leader_tracker_arrow)
COOLDOWN_START(src, silo_proxy_alert_cooldown, XENO_SILO_DETECTION_COOLDOWN) //set the cooldown.
addtimer(CALLBACK(src, PROC_REF(clear_warning)), XENO_SILO_DETECTION_COOLDOWN) //clear warning

///Clears the warning for minimap if its warning for hostiles
/obj/structure/xeno/silo/proc/clear_warning()
warning = FALSE
update_minimap_icon()
/obj/structure/xeno/silo/update_minimap_icon()
SSminimaps.remove_marker(src)
SSminimaps.add_marker(src, MINIMAP_FLAG_XENO, image('icons/UI_icons/map_blips.dmi', null, "silo[threat_warning ? "_warn" : "_passive"]", HIGH_FLOAT_LAYER))

/obj/structure/xeno/silo/process()
//Regenerate if we're at less than max integrity
Expand All @@ -149,11 +108,6 @@
if(GLOB.hive_datums[hivenumber])
silos += src

///Change minimap icon if silo is under attack or not
/obj/structure/xeno/silo/proc/update_minimap_icon()
SSminimaps.remove_marker(src)
SSminimaps.add_marker(src, MINIMAP_FLAG_XENO, image('icons/UI_icons/map_blips.dmi', null, "silo[warning ? "_warn" : "_passive"]", HIGH_FLOAT_LAYER))

/// Transfers the spawned minion to the silo's hivenumber.
/obj/structure/xeno/silo/proc/on_spawn(list/newly_spawned_things)
for(var/mob/living/carbon/xenomorph/spawned_minion AS in newly_spawned_things)
Expand Down
Loading

0 comments on commit 9ef6652

Please sign in to comment.