[MIRROR] Refactors SM Delaminations to be strategies [MDB IGNORE] (#15370)

* Refactors SM Delaminations to be strategies

* wew

Co-authored-by: vincentiusvin <54709710+vincentiusvin@users.noreply.github.com>
Co-authored-by: Gandalf <9026500+Gandalf2k15@users.noreply.github.com>
This commit is contained in:
SkyratBot
2022-08-04 15:48:48 +01:00
committed by GitHub
co-authored by vincentiusvin Gandalf
parent 6823589e7a
commit c0d6df89e4
13 changed files with 706 additions and 642 deletions
-10
View File
@@ -110,16 +110,6 @@
#define DETOMATIX_RESIST_MINOR 1
#define DETOMATIX_RESIST_MAJOR 2
// These are used by supermatter and supermatter monitor program, mostly for UI updating purposes. Higher should always be worse!
#define SUPERMATTER_ERROR -1 // Unknown status, shouldn't happen but just in case.
#define SUPERMATTER_INACTIVE 0 // No or minimal energy
#define SUPERMATTER_NORMAL 1 // Normal operation
#define SUPERMATTER_NOTIFY 2 // Ambient temp > 80% of CRITICAL_TEMPERATURE
#define SUPERMATTER_WARNING 3 // Ambient temp > CRITICAL_TEMPERATURE OR integrity damaged
#define SUPERMATTER_DANGER 4 // Integrity < 50%
#define SUPERMATTER_EMERGENCY 5 // Integrity < 25%
#define SUPERMATTER_DELAMINATING 6 // Pretty obvious.
#define HYPERTORUS_INACTIVE 0 // No or minimal energy
#define HYPERTORUS_NOMINAL 1 // Normal operation
#define HYPERTORUS_WARNING 2 // Integrity damaged
+30 -8
View File
@@ -90,7 +90,7 @@
/// All humans within this range will be irradiated
#define DETONATION_RADIATION_RANGE 20
#define WARNING_DELAY 60
#define SUPERMATTER_WARNING_DELAY 60 SECONDS
#define HALLUCINATION_RANGE(P) (min(7, round(P ** 0.25)))
@@ -102,13 +102,6 @@
#define HALLUCINATION_ANOMALY "hallucination_anomaly"
#define VORTEX_ANOMALY "vortex_anomaly"
//If integrity percent remaining is less than these values, the monitor sets off the relevant alarm.
#define SUPERMATTER_DELAM_PERCENT 5
#define SUPERMATTER_EMERGENCY_PERCENT 25
#define SUPERMATTER_DANGER_PERCENT 50
#define SUPERMATTER_WARNING_PERCENT 100
#define CRITICAL_TEMPERATURE 10000
#define SUPERMATTER_COUNTDOWN_TIME 30 SECONDS
///to prevent accent sounds from layering
@@ -128,3 +121,32 @@
#define POWERLOSS_LINEAR_RATE 0.83
/// How much a psychologist can reduce power loss.
#define PSYCHOLOGIST_POWERLOSS_REDUCTION 0.2
/// Means it's not forced, sm decides itself by checking the [/datum/sm_delam/proc/can_select]
#define SM_DELAM_PRIO_NONE 0
/// In-game factors like the destabilizing crystal [/obj/item/destabilizing_crystal].
/// Purged when SM heals to 100
#define SM_DELAM_PRIO_IN_GAME 1
/// Purge the current forced delam and make it zero again (back to normal).
/// Needs to be higher priority than current forced_delam though.
#define SM_DELAM_STRATEGY_PURGE null
// These are used by supermatter and supermatter monitor program, mostly for UI updating purposes. Higher should always be worse!
// [/obj/machinery/power/supermatter_crystal/proc/get_status]
/// Unknown status, shouldn't happen but just in case.
#define SUPERMATTER_ERROR -1
/// No or minimal energy
#define SUPERMATTER_INACTIVE 0
/// Normal operation
#define SUPERMATTER_NORMAL 1
/// Ambient temp 80% of the default temp for SM to take damage.
#define SUPERMATTER_NOTIFY 2
/// Integrity below [/obj/machinery/power/supermatter_crystal/var/warning_point]. Start complaining on comms.
#define SUPERMATTER_WARNING 3
/// Integrity below [/obj/machinery/power/supermatter_crystal/var/danger_point]. Start spawning anomalies.
#define SUPERMATTER_DANGER 4
/// Integrity below [/obj/machinery/power/supermatter_crystal/var/emergency_point]. Start complaining to more people.
#define SUPERMATTER_EMERGENCY 5
/// Currently counting down to delamination. True [/obj/machinery/power/supermatter_crystal/var/final_countdown]
#define SUPERMATTER_DELAMINATING 6
@@ -46,8 +46,8 @@
desc = "Your benefactors conveinently neglected to mention it's already assembled."
anchored = TRUE
radio_key = /obj/item/encryptionkey/syndicate
engineering_channel = "Syndicate"
common_channel = "Syndicate"
emergency_channel = "Syndicate"
warning_channel = "Syndicate"
include_in_cims = FALSE
/obj/machinery/power/supermatter_crystal/shard/syndicate/attackby(obj/item/item, mob/living/user, params)
+97 -161
View File
@@ -12,10 +12,6 @@
#define OBJECT (LOWEST + 1)
#define LOWEST (1)
#define CASCADING_ADMIN "Admin"
#define CASCADING_CRITICAL_GAS "Critical gas point"
#define CASCADING_DESTAB_CRYSTAL "Destabilizing crystal"
GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
/obj/machinery/power/supermatter_crystal
@@ -38,30 +34,27 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
var/static/gl_uid = 1
///Tracks the bolt color we are using
var/zap_icon = DEFAULT_ZAP_ICON_STATE
///The portion of the gasmix we're on that we should remove
var/gasefficency = 0.15
///Are we exploding?
var/final_countdown = FALSE
///The amount of damage we have currently
var/damage = 0
///The damage we had before this cycle. Used to limit the damage we can take each cycle, and for safe_alert
/// The damage we had before this cycle.
/// Used to limit the damage we can take each cycle, and to check if we are currently taking damage or healing.
var/damage_archived = 0
///Our "Shit is no longer fucked" message. We send it when damage is less then damage_archived
var/safe_alert = "Crystalline hyperstructure returning to safe operating parameters."
///The point at which we should start sending messeges about the damage to the engi channels.
///The point at which we consider the supermatter to be [SUPERMATTER_STATUS_WARNING]
var/warning_point = 50
///The alert we send when we've reached warning_point
var/warning_alert = "Danger! Crystal hyperstructure integrity faltering!"
///The point at which we start sending messages to the common channel
var/emergency_point = 700
///The alert we send when we've reached emergency_point
var/emergency_alert = "CRYSTAL DELAMINATION IMMINENT."
///The point at which we delam
var/warning_channel = RADIO_CHANNEL_ENGINEERING
///The point at which we consider the supermatter to be [SUPERMATTER_STATUS_DANGER]
///Spawns anomalies when more damaged than this too.
var/danger_point = 550
///The point at which we consider the supermatter to be [SUPERMATTER_STATUS_EMERGENCY]
var/emergency_point = 675
var/emergency_channel = null // Need null to actually broadcast, lol.
///The point at which we delam [SUPERMATTER_STATUS_DELAMINATING]
var/explosion_point = 900
///When we pass this amount of damage we start shooting bolts
var/damage_penalty_point = 550
///A scaling value that affects the severity of explosions.
var/explosion_power = 35
@@ -220,20 +213,14 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
var/obj/item/radio/radio
///The key our internal radio uses
var/radio_key = /obj/item/encryptionkey/headset_eng
///The engineering channel
var/engineering_channel = "Engineering"
///The common channel
var/common_channel = null
///Boolean used for logging if we've been powered
var/has_been_powered = FALSE
///Boolean used for logging if we've passed the emergency point
var/has_reached_emergency = FALSE
///An effect we show to admins and ghosts the percentage of delam we're at
var/obj/effect/countdown/supermatter/countdown
///Used along with a global var to track if we can give out the sm sliver stealing objective
///Only main engines can have their sliver stolen, can trigger cascades, and can spawn stationwide anomalies.
var/is_main_engine = FALSE
///Our soundloop
var/datum/looping_sound/supermatter/soundloop
@@ -264,16 +251,8 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
var/include_in_cims = TRUE
var/freonbonus = 0
///Can the crystal trigger the station wide anomaly spawn?
var/anomaly_event = TRUE
///Hue shift of the zaps color based on the power of the crystal
var/hue_angle_shift = 0
///If an admin wants a sure cascade with the delamination just set this to true (don't be a badmin)
var/admin_cascade = FALSE
///Do we have a destabilizing crystal attached?
var/has_destabilizing_crystal = FALSE
///Has the cascade been triggered?
var/cascade_initiated = FALSE
///Reference to the warp effect
var/atom/movable/supermatter_warp_effect/warp
///The power threshold required to transform the powerloss function into a linear function from a cubic function.
@@ -281,9 +260,21 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
///The offset of the linear powerloss function set so the transition is differentiable.
var/powerloss_linear_offset = 0
///The portion of the gasmix we're on that we should remove
var/absorption_ratio = 0.15
/// The gasmix we just recently absorbed. Tile's air multiplied by absorption_ratio
var/datum/gas_mixture/absorbed_gasmix
/// How we are delaminating.
var/datum/sm_delam/delamination_strategy
/// Whether the sm is forced in a specific delamination_strategy or not. All truthy values means it's forced.
/// Only values greater or equal to the current one can change the strat.
var/delam_priority = SM_DELAM_PRIO_NONE
/obj/machinery/power/supermatter_crystal/Initialize(mapload)
. = ..()
uid = gl_uid++
set_delam(SM_DELAM_PRIO_NONE, /datum/sm_delam/explosive)
SSair.start_processing_machine(src)
countdown = new(src)
countdown.start()
@@ -297,7 +288,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
GLOB.main_supermatter_engine = src
AddElement(/datum/element/bsa_blocker)
RegisterSignal(src, COMSIG_ATOM_BSA_BEAM, .proc/call_delamination_event)
RegisterSignal(src, COMSIG_ATOM_BSA_BEAM, .proc/force_delam)
var/static/list/loc_connections = list(
COMSIG_TURF_INDUSTRIAL_LIFT_ENTER = .proc/tram_contents_consume,
@@ -344,8 +335,8 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
var/immune = HAS_TRAIT(user, TRAIT_MADNESS_IMMUNE) || (user.mind && HAS_TRAIT(user.mind, TRAIT_MADNESS_IMMUNE))
if(isliving(user) && !immune && (get_dist(user, src) < HALLUCINATION_RANGE(power)))
. += span_danger("You get headaches just from looking at it.")
if(cascade_initiated)
. += span_bolddanger("The crystal is vibrating at immense speeds, warping space around it!")
. += delamination_strategy.examine(src)
return .
// SupermatterMonitor UI for ghosts only. Inherited attack_ghost will call this.
/obj/machinery/power/supermatter_crystal/ui_interact(mob/user, datum/tgui/ui)
@@ -371,7 +362,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
data["SM_power"] = power
data["SM_ambienttemp"] = air.temperature
data["SM_ambientpressure"] = air.return_pressure()
data["SM_bad_moles_amount"] = MOLE_PENALTY_THRESHOLD / gasefficency
data["SM_bad_moles_amount"] = MOLE_PENALTY_THRESHOLD / absorption_ratio
data["SM_moles"] = 0
data["SM_uid"] = uid
var/area/active_supermatter_area = get_area(src)
@@ -396,6 +387,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
return data
/// Encodes the current state of the supermatter.
/obj/machinery/power/supermatter_crystal/proc/get_status()
var/turf/local_turf = get_turf(src)
if(!local_turf)
@@ -403,46 +395,20 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
var/datum/gas_mixture/air = local_turf.return_air()
if(!air)
return SUPERMATTER_ERROR
var/integrity = get_integrity_percent()
if(integrity < SUPERMATTER_DELAM_PERCENT)
if(final_countdown)
return SUPERMATTER_DELAMINATING
if(integrity < SUPERMATTER_EMERGENCY_PERCENT)
if(damage >= emergency_point)
return SUPERMATTER_EMERGENCY
if(integrity < SUPERMATTER_DANGER_PERCENT)
if(damage >= danger_point)
return SUPERMATTER_DANGER
if((integrity < SUPERMATTER_WARNING_PERCENT) || (air.temperature > CRITICAL_TEMPERATURE))
if(damage >= warning_point)
return SUPERMATTER_WARNING
if(air.temperature > (CRITICAL_TEMPERATURE * 0.8))
if(absorbed_gasmix.temperature > (T0C + HEAT_PENALTY_THRESHOLD) * 0.8)
return SUPERMATTER_NOTIFY
if(power > 5)
if(power)
return SUPERMATTER_NORMAL
return SUPERMATTER_INACTIVE
/obj/machinery/power/supermatter_crystal/proc/alarm()
switch(get_status())
if(SUPERMATTER_DELAMINATING)
playsound(src, 'sound/misc/bloblarm.ogg', 100, FALSE, 40, 30, falloff_distance = 10)
// SKYRAT EDIT ADDITION
alert_sound_to_playing('modular_skyrat/master_files/sound/effects/reactor/meltdown.ogg', override_volume = TRUE)
alert_sound_to_playing('modular_skyrat/modules/alerts/sound/alerts/alert1.ogg', override_volume = TRUE)
// SKYRAT EDIT END
if(SUPERMATTER_EMERGENCY)
// SKYRAT EDIT ADDITION
alert_sound_to_playing('modular_skyrat/master_files/sound/effects/reactor/core_overheating.ogg', override_volume = TRUE)
alert_sound_to_playing('modular_skyrat/modules/alerts/sound/alerts/alert1.ogg', override_volume = TRUE)
// SKYRAT EDIT END
playsound(src, 'sound/machines/engine_alert1.ogg', 100, FALSE, 30, 30, falloff_distance = 10)
if(SUPERMATTER_DANGER)
playsound(src, 'sound/machines/engine_alert2.ogg', 100, FALSE, 30, 30, falloff_distance = 10)
if(SUPERMATTER_WARNING)
playsound(src, 'sound/machines/terminal_alert.ogg', 75)
/obj/machinery/power/supermatter_crystal/proc/get_integrity_percent()
var/integrity = damage / explosion_point
integrity = round(100 - integrity * 100, 0.01)
@@ -451,93 +417,13 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
/obj/machinery/power/supermatter_crystal/update_overlays()
. = ..()
if(final_countdown && !cascade_initiated)
. += "casuality_field"
. += delamination_strategy.overlays(src)
return .
/obj/machinery/power/supermatter_crystal/proc/countdown()
set waitfor = FALSE
if(final_countdown) // We're already doing it go away
return
final_countdown = TRUE
update_appearance()
var/cascading = cascade_initiated
var/speaking = "[emergency_alert] The supermatter has reached critical integrity failure."
if(cascading)
speaking += " Harmonic frequency limits exceeded. Causality destabilization field could not be engaged."
else
speaking += " Emergency causality destabilization field has been activated."
radio.talk_into(src, speaking, common_channel, language = get_selected_language())
for(var/i in SUPERMATTER_COUNTDOWN_TIME to 0 step -10)
if(damage < explosion_point) // Cutting it a bit close there engineers
if(cascading)
radio.talk_into(src, "[safe_alert] Harmonic frequency restored within emergency bounds. Anti-resonance filter initiated.", common_channel)
else
radio.talk_into(src, "[safe_alert] Failsafe has been disengaged.", common_channel)
final_countdown = FALSE
update_appearance()
return
else if((i % 50) != 0 && i > 50) // A message once every 5 seconds until the final 5 seconds which count down individualy
sleep(10)
continue
else if(i > 50)
if(cascading)
speaking = "[DisplayTimeText(i, TRUE)] remain before resonance-induced stabilization."
else
speaking = "[DisplayTimeText(i, TRUE)] remain before causality stabilization."
else
speaking = "[i*0.1]..."
radio.talk_into(src, speaking, common_channel)
sleep(1 SECONDS)
delamination_event()
/obj/machinery/power/supermatter_crystal/proc/delamination_event()
var/can_spawn_anomalies = is_station_level(loc.z) && is_main_engine && anomaly_event
var/is_cascading = cascade_initiated
new /datum/supermatter_delamination(power, combined_gas, get_turf(src), explosion_power, gasmix_power_ratio, can_spawn_anomalies, is_cascading)
qdel(src)
//this is here to eat arguments
/obj/machinery/power/supermatter_crystal/proc/call_delamination_event()
/obj/machinery/power/supermatter_crystal/proc/force_delam()
SIGNAL_HANDLER
delamination_event()
/**
* Checks if and why the supermatter is in a state where it can cascade
*
* Returns: cause of the cascade, for logging
*/
/obj/machinery/power/supermatter_crystal/proc/check_cascade_requirements()
if(admin_cascade)
return CASCADING_ADMIN
if(!anomaly_event)
return FALSE
if(has_destabilizing_crystal)
return CASCADING_DESTAB_CRYSTAL
var/critical_gas_exceeded = TRUE
var/list/required_gases = list(/datum/gas/hypernoblium, /datum/gas/antinoblium)
if(environment_total_moles < MOLE_PENALTY_THRESHOLD)
critical_gas_exceeded = FALSE
else
for(var/gas_path in required_gases)
if(gas_comp[gas_path] < 0.4)
critical_gas_exceeded = FALSE
break
if(critical_gas_exceeded)
return CASCADING_CRITICAL_GAS
return FALSE
investigate_log("was forcefully delaminated", INVESTIGATE_ENGINE)
INVOKE_ASYNC(delamination_strategy, /datum/sm_delam/proc/delaminate, src)
/obj/machinery/power/supermatter_crystal/proc/supermatter_pull(turf/center, pull_range = 3)
playsound(center, 'sound/weapons/marauder.ogg', 100, TRUE, extrarange = pull_range - world.view)
@@ -553,6 +439,61 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
continue //You can't pull someone nailed to the deck
step_towards(movable_atom,center)
/**
* Count down, spout some messages, and then execute the delam itself.
* We guard for last second delam strat changes here, mostly because some have diff messages.
*
* By last second changes, we mean that it's possible for say, a tesla delam to
* just explode normally if at the absolute last second it loses power and switches to default one.
* Even after countdown is already in progress.
*/
/obj/machinery/power/supermatter_crystal/proc/count_down()
set waitfor = FALSE
if(final_countdown) // We're already doing it go away
stack_trace("[src] told to delaminate again while it's already delaminating.")
return
final_countdown = TRUE
update_appearance()
var/datum/sm_delam/last_delamination_strategy = delamination_strategy
var/list/count_down_messages = delamination_strategy.count_down_messages()
radio.talk_into(
src,
count_down_messages[1],
emergency_channel
)
for(var/i in SUPERMATTER_COUNTDOWN_TIME to 0 step -10)
if(last_delamination_strategy != delamination_strategy)
count_down_messages = delamination_strategy.count_down_messages()
var/message
var/healed = FALSE
if(damage < explosion_point) // Cutting it a bit close there engineers
message = count_down_messages[2]
healed = TRUE
else if((i % 50) != 0 && i > 50) // A message once every 5 seconds until the final 5 seconds which count down individualy
sleep(1 SECONDS)
continue
else if(i > 50)
message = "[DisplayTimeText(i, TRUE)] [count_down_messages[3]]"
else
message = "[i*0.1]..."
radio.talk_into(src, message, emergency_channel)
if(healed)
final_countdown = FALSE
update_appearance()
return // delam averted
sleep(1 SECONDS)
delamination_strategy.delaminate(src)
/proc/supermatter_anomaly_gen(turf/anomalycenter, type = FLUX_ANOMALY, anomalyrange = 5, has_changed_lifespan = TRUE)
var/turf/local_turf = pick(orange(anomalyrange, anomalycenter))
if(!local_turf)
@@ -721,13 +662,12 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
base_icon_state = "darkmatter_shard"
icon_state = "darkmatter_shard"
anchored = FALSE
gasefficency = 0.125
absorption_ratio = 0.125
explosion_power = 12
layer = ABOVE_MOB_LAYER
plane = GAME_PLANE_UPPER
moveable = TRUE
psyOverlay = /obj/overlay/psy/shard
anomaly_event = FALSE
/obj/machinery/power/supermatter_crystal/shard/engine
name = "anchored supermatter shard"
@@ -767,10 +707,6 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
pixel_x = -176
pixel_y = -176
#undef CASCADING_ADMIN
#undef CASCADING_CRITICAL_GAS
#undef CASCADING_DESTAB_CRYSTAL
#undef BIKE
#undef COIL
#undef ROD
@@ -1,349 +0,0 @@
///Minimum distance that a crystal mass must have from the rift
#define MIN_RIFT_SAFE_DIST 30
/datum/supermatter_delamination
///Power amount of the SM at the moment of death
var/supermatter_power = 0
///Amount of total gases interacting with the SM
var/supermatter_gas_amount = 0
///Base number of anomalies to spawn (can go up or down with a random small amount)
var/anomalies_to_spawn = 10
///Can we spawn anomalies after dealing with the delamination type?
var/should_spawn_anomalies = TRUE
///Reference to the supermatter turf
var/turf/supermatter_turf
///Baseline strenght of the explosion caused by the SM
var/supermatter_explosion_power = 0
///Amount the gasmix will affect the explosion size
var/supermatter_gasmix_power_ratio = 0
///Are we triggering a supermatter cascade?
var/supermatter_cascade = FALSE
///The rift in space that will be created by the cascade
var/obj/cascade_portal/cascade_rift
/datum/supermatter_delamination/New(supermatter_power, supermatter_gas_amount, turf/supermatter_turf, supermatter_explosion_power, supermatter_gasmix_power_ratio, can_spawn_anomalies, supermatter_cascade)
. = ..()
src.supermatter_power = supermatter_power
src.supermatter_gas_amount = supermatter_gas_amount
src.supermatter_turf = supermatter_turf
src.supermatter_explosion_power = supermatter_explosion_power
src.supermatter_gasmix_power_ratio = supermatter_gasmix_power_ratio
if(supermatter_cascade)
start_supermatter_cascade()
return
setup_mob_interaction()
setup_delamination_type()
if(!should_spawn_anomalies || !can_spawn_anomalies)
qdel(src)
return
setup_anomalies()
/**
* What the mobs should deal with when a delamination happens
*/
/datum/supermatter_delamination/proc/setup_mob_interaction()
for(var/mob/living/victim as anything in GLOB.alive_mob_list)
if(!istype(victim) || victim.z != supermatter_turf.z)
continue
if(ishuman(victim))
//Hilariously enough, running into a closet should make you get hit the hardest.
var/mob/living/carbon/human/human = victim
human.hallucination += max(50, min(300, DETONATION_HALLUCINATION * sqrt(1 / (get_dist(victim, src) + 1)) ) )
if (get_dist(victim, src) <= DETONATION_RADIATION_RANGE)
SSradiation.irradiate(victim)
for(var/mob/victim as anything in GLOB.player_list)
var/turf/mob_turf = get_turf(victim)
if(supermatter_turf.z != mob_turf.z)
continue
SEND_SOUND(victim, 'sound/magic/charge.ogg')
if (victim.z != supermatter_turf.z)
to_chat(victim, span_boldannounce("You hold onto \the [victim.loc] as hard as you can, as reality distorts around you. You feel safe."))
continue
to_chat(victim, span_boldannounce("You feel reality distort for a moment..."))
SEND_SIGNAL(victim, COMSIG_ADD_MOOD_EVENT, "delam", /datum/mood_event/delam)
/**
* Setup for the types of possible delaminations and their effects (singulo, tesla or normal)
*/
/datum/supermatter_delamination/proc/setup_delamination_type()
if(supermatter_gas_amount > MOLE_PENALTY_THRESHOLD)
call_singulo()
return
if(supermatter_power > POWER_PENALTY_THRESHOLD)
call_tesla()
return
call_explosion()
/**
* Spawns the singularity
*/
/datum/supermatter_delamination/proc/call_singulo()
if(!supermatter_turf) //If something fucks up we blow anyhow. This fix is 4 years old and none ever said why it's here. help.
call_explosion()
return
var/obj/singularity/created_singularity = new(supermatter_turf)
created_singularity.energy = 800
created_singularity.consume(src)
should_spawn_anomalies = FALSE
/**
* Spawns the tesla
*/
/datum/supermatter_delamination/proc/call_tesla()
if(supermatter_turf)
var/obj/energy_ball/created_tesla = new(supermatter_turf)
created_tesla.energy = 200 //Gets us about 9 balls
call_explosion()
should_spawn_anomalies = FALSE
/**
* Spawns the explosion
*/
/datum/supermatter_delamination/proc/call_explosion()
//Dear mappers, balance the sm max explosion radius to 17.5, 37, 39, 41
explosion(origin = supermatter_turf,
devastation_range = supermatter_explosion_power * max(supermatter_gasmix_power_ratio, 0.205) * 0.5,
heavy_impact_range = supermatter_explosion_power * max(supermatter_gasmix_power_ratio, 0.205) + 2,
light_impact_range = supermatter_explosion_power * max(supermatter_gasmix_power_ratio, 0.205) + 4,
flash_range = supermatter_explosion_power * max(supermatter_gasmix_power_ratio, 0.205) + 6,
adminlog = TRUE,
ignorecap = TRUE
)
/**
* Setups how many anomalies to spawn
*/
/datum/supermatter_delamination/proc/setup_anomalies()
anomalies_to_spawn = max(round(0.004 * supermatter_power, 1) + rand(-2, 2), 1)
spawn_anomalies()
/**
* Spawns the first half anomalies instantly and calls the second half
*/
/datum/supermatter_delamination/proc/spawn_anomalies()
var/list/anomaly_types = list(GRAVITATIONAL_ANOMALY = 55, HALLUCINATION_ANOMALY = 45, BIOSCRAMBLER_ANOMALY = 35, FLUX_ANOMALY = 25, PYRO_ANOMALY = 5, VORTEX_ANOMALY = 1)
var/list/anomaly_places = GLOB.generic_event_spawns
var/currently_spawning_anomalies = round(anomalies_to_spawn * 0.5, 1)
anomalies_to_spawn -= currently_spawning_anomalies
for(var/i in 1 to currently_spawning_anomalies)
var/anomaly_to_spawn = pick_weight(anomaly_types)
var/anomaly_location = pick_n_take(anomaly_places)
supermatter_anomaly_gen(anomaly_location, anomaly_to_spawn, has_changed_lifespan = FALSE)
spawn_overtime()
/**
* Spawns the second half anomalies after a delay
*/
/datum/supermatter_delamination/proc/spawn_overtime()
var/list/anomaly_types = list(GRAVITATIONAL_ANOMALY = 55, HALLUCINATION_ANOMALY = 45, BIOSCRAMBLER_ANOMALY = 35, FLUX_ANOMALY = 25, PYRO_ANOMALY = 5, VORTEX_ANOMALY = 1)
var/list/anomaly_places = GLOB.generic_event_spawns
var/current_spawn = rand(5 SECONDS, 10 SECONDS)
for(var/i in 1 to anomalies_to_spawn)
var/anomaly_to_spawn = pick_weight(anomaly_types)
var/anomaly_location = pick_n_take(anomaly_places)
var/next_spawn = rand(5 SECONDS, 10 SECONDS)
var/extended_spawn = 0
if(DT_PROB(1, next_spawn))
extended_spawn = rand(5 MINUTES, 15 MINUTES)
addtimer(CALLBACK(src, .proc/spawn_anomaly, anomaly_location, anomaly_to_spawn), current_spawn + extended_spawn)
current_spawn += next_spawn
/**
* Callback for the anomalies to spawn after some time
*/
/datum/supermatter_delamination/proc/spawn_anomaly(location, type)
supermatter_anomaly_gen(location, type, has_changed_lifespan = FALSE)
/**
* Setup for the cascade delamination
*/
/datum/supermatter_delamination/proc/start_supermatter_cascade()
// buncha shuttle manipulation incoming
// set timer to infinity, so shuttle never arrives
SSshuttle.emergency.setTimer(INFINITY)
// disallow shuttle recalls, so people cannot cheese the timer
SSshuttle.emergency_no_recall = TRUE
// set supermatter cascade to true, to prevent auto evacuation due to no way of calling the shuttle
SSshuttle.supermatter_cascade = TRUE
// This logic is to keep uncalled shuttles uncalled
// In SSshuttle, there is not much of a way to prevent shuttle calls, unless we mess with admin panel vars
// SHUTTLE_STRANDED is different here, because it *can* block the shuttle from being called, however if we don't register a hostile
// environment, it gets unset immediately. Internally, it checks if the count of HEs is zero
// and that the shuttle is in stranded mode, then frees it with an announcement.
// This is a botched solution to a problem that could be solved with a small change in shuttle code, however-
if(SSshuttle.emergency.mode == SHUTTLE_IDLE)
SSshuttle.emergency.mode = SHUTTLE_STRANDED
SSshuttle.registerHostileEnvironment(src)
// set hijack completion timer to infinity, so that you cant prematurely end the round with a hijack
for(var/obj/machinery/computer/emergency_shuttle/console in GLOB.machines)
console.hijack_completion_flight_time_set = INFINITY
for(var/mob/player as anything in GLOB.player_list)
if(!isdead(player))
to_chat(player, span_boldannounce("Everything around you is resonating with a powerful energy. This can't be good."))
SEND_SIGNAL(player, COMSIG_ADD_MOOD_EVENT, "cascade", /datum/mood_event/cascade)
SEND_SOUND(player, 'sound/magic/charge.ogg')
call_explosion()
create_cascade_ambience()
warn_crew()
var/rift_loc = pick_rift_location()
new /obj/crystal_mass(supermatter_turf)
var/list/mass_loc_candidates = GLOB.generic_event_spawns.Copy()
mass_loc_candidates.Remove(rift_loc) // this should now actually get rid of stalemates
for(var/i in 1 to rand(4,6))
var/list/loc_list = mass_loc_candidates.Copy()
var/mass_loc
do
mass_loc = pick_n_take(loc_list)
while(get_dist(mass_loc, rift_loc) < MIN_RIFT_SAFE_DIST)
new /obj/crystal_mass(get_turf(mass_loc))
SSsupermatter_cascade.cascade_initiated = TRUE
/**
* Adds a bit of spiciness to the cascade by breaking lights and turning emergency maint access on
*/
/datum/supermatter_delamination/proc/create_cascade_ambience()
if(SSsecurity_level.get_current_level_as_number() != SEC_LEVEL_DELTA)
SSsecurity_level.set_level(SEC_LEVEL_DELTA) // skip the announcement and shuttle timer adjustment in set_security_level()
make_maint_all_access()
break_lights_on_station()
/**
* Picks a random location for the rift
* Returns: ref to rift location
*/
/datum/supermatter_delamination/proc/pick_rift_location()
var/rift_spawn = pick(GLOB.generic_event_spawns)
var/turf/rift_turf = get_turf(rift_spawn)
cascade_rift = new /obj/cascade_portal(rift_turf)
message_admins("Exit rift created at [get_area_name(rift_turf)]. [ADMIN_JMP(cascade_rift)]")
log_game("Bluespace Exit Rift was created at [get_area_name(rift_turf)].")
cascade_rift.investigate_log("created at [get_area_name(rift_turf)].", INVESTIGATE_ENGINE)
RegisterSignal(cascade_rift, COMSIG_PARENT_QDELETING, .proc/deleted_portal)
return rift_spawn
/**
* Warns the crew about the cascade start and the rift location
*/
/datum/supermatter_delamination/proc/warn_crew()
priority_announce("A Type-C resonance shift event has occurred in your sector. Scans indicate local oscillation flux affecting spatial and gravitational substructure. \
Multiple resonance hotspots have formed. Please standby.", "Nanotrasen Star Observation Association", ANNOUNCER_SPANOMALIES)
if(SSshuttle.emergency.mode != SHUTTLE_STRANDED)
addtimer(CALLBACK(src, .proc/announce_shuttle_gone), 2 SECONDS)
addtimer(CALLBACK(src, .proc/announce_beginning), 5 SECONDS)
/**
* Logs the deletion of the bluespace rift, and starts countdown to the end of the round.
*/
/datum/supermatter_delamination/proc/deleted_portal()
SIGNAL_HANDLER
message_admins("[cascade_rift] deleted at [get_area_name(cascade_rift.loc)]. [ADMIN_JMP(cascade_rift.loc)]")
log_game("[cascade_rift] was deleted.")
cascade_rift.investigate_log("was deleted.", INVESTIGATE_ENGINE)
priority_announce("[Gibberish("The rift has been destroyed, we can no longer help you.", FALSE, 5)]")
addtimer(CALLBACK(src, .proc/announce_gravitation_shift), 25 SECONDS)
addtimer(CALLBACK(src, .proc/last_message), 50 SECONDS)
if(SSshuttle.emergency.mode != SHUTTLE_ESCAPE) // if the shuttle is enroute to centcom, we let the shuttle end the round
addtimer(CALLBACK(src, .proc/the_end), 1 MINUTES)
/**
* Announces the halfway point to the end.
*/
/datum/supermatter_delamination/proc/announce_gravitation_shift()
priority_announce("Reports indicate formation of crystalline seeds following resonance shift event. \
Rapid expansion of crystal mass proportional to rising gravitational force. \
Matter collapse due to gravitational pull foreseeable.",
"Nanotrasen Star Observation Association")
/**
* This proc manipulates the shuttle if it's enroute to centcom, to remain in hyperspace. Otherwise, it just plays an announcement if
* the shuttle was in any other state except stranded (idle)
*/
/datum/supermatter_delamination/proc/announce_shuttle_gone()
// say goodbye to that shuttle of yours
if(SSshuttle.emergency.mode != SHUTTLE_ESCAPE)
priority_announce("Fatal error occurred in emergency shuttle uplink during transit. Unable to reestablish connection.",
"Emergency Shuttle Uplink Alert", 'sound/misc/announce_dig.ogg')
else
// except if you are on it already, then you are safe c:
minor_announce("ERROR: Corruption detected in navigation protocols. Connection with Transponder #XCC-P5831-ES13 lost. \
Backup exit route protocol decrypted. Calibrating route...",
"Emergency Shuttle", TRUE) // wait out until the rift on the station gets destroyed and the final message plays
var/list/mobs = mobs_in_area_type(list(/area/shuttle/escape))
for(var/mob/living/mob as anything in mobs) // emulate mob/living/lateShuttleMove() behaviour
if(mob.buckled)
continue
if(mob.client)
shake_camera(mob, 3 SECONDS * 0.25, 1)
mob.Paralyze(3 SECONDS, TRUE)
/**
* Announces the last message to the station, frees the shuttle from purgatory if applicable
*/
/datum/supermatter_delamination/proc/last_message()
priority_announce("[Gibberish("All attempts at evacuation have now ceased, and all assets have been retrieved from your sector.\n \
To the remaining survivors of [station_name()], farewell.", FALSE, 5)]")
if(SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
// special message for hijacks
var/shuttle_msg = "Navigation protocol set to [SSshuttle.emergency.is_hijacked() ? "\[ERROR\]" : "backup route"]. \
Reorienting bluespace vessel to exit vector. ETA 15 seconds."
// garble the special message
if(SSshuttle.emergency.is_hijacked())
shuttle_msg = Gibberish(shuttle_msg, TRUE, 15)
minor_announce(shuttle_msg, "Emergency Shuttle", TRUE)
SSshuttle.emergency.setTimer(15 SECONDS)
/**
* Announce detail about the event, as well as rift location
*/
/datum/supermatter_delamination/proc/announce_beginning()
priority_announce("We have been hit by a sector-wide electromagnetic pulse. All of our systems are heavily damaged, including those \
required for shuttle navigation. We can only reasonably conclude that a supermatter cascade is occurring on or near your station.\n\n\
Evacuation is no longer possible by conventional means; however, we managed to open a rift near the [get_area_name(cascade_rift)]. \
All personnel are hereby required to enter the rift by any means available.\n\n\
[Gibberish("Retrieval of survivors will be conducted upon recovery of necessary facilities.", FALSE, 5)] \
[Gibberish("Good luck--", FALSE, 25)]")
/**
* Ends the round
*/
/datum/supermatter_delamination/proc/the_end()
SSticker.news_report = SUPERMATTER_CASCADE
SSticker.force_ending = TRUE
/**
* Break the lights on the station, have 35% of them be set to emergency
*/
/datum/supermatter_delamination/proc/break_lights_on_station()
for(var/obj/machinery/light/light_to_break in GLOB.machines)
if(prob(35))
light_to_break.set_major_emergency_light()
continue
light_to_break.break_light_tube()
#undef MIN_RIFT_SAFE_DIST
@@ -0,0 +1,106 @@
/// Priority is top to bottom.
GLOBAL_LIST_INIT(sm_delam_list, list(
/datum/sm_delam/cascade = new /datum/sm_delam/cascade,
/datum/sm_delam/singularity = new /datum/sm_delam/singularity,
/datum/sm_delam/tesla = new /datum/sm_delam/tesla,
/datum/sm_delam/explosive = new /datum/sm_delam/explosive,
))
/// Logic holder for supermatter delaminations, goes off the strategy design pattern.
/// Selected by [/obj/machinery/power/supermatter_crystal/proc/set_delam]
/datum/sm_delam
/// Whether we are eligible for this delamination or not. TRUE if valid, FALSE if not.
/// [/obj/machinery/power/supermatter_crystal/proc/set_delam]
/datum/sm_delam/proc/can_select(obj/machinery/power/supermatter_crystal/sm)
return FALSE
/// Called when the count down has been finished, do the nasty work.
/// [/obj/machinery/power/supermatter_crystal/proc/count_down]
/datum/sm_delam/proc/delaminate(obj/machinery/power/supermatter_crystal/sm)
qdel(sm)
/// Whatever we're supposed to do when a delam is currently in progress.
/// Mostly just to tell people how useless engi is, and play some alarm sounds.
/// Returns TRUE if we just told people a delam is going on. FALSE if its healing or we didnt say anything.
/// [/obj/machinery/power/supermatter_crystal/proc/process_atmos]
/datum/sm_delam/proc/delam_progress(obj/machinery/power/supermatter_crystal/sm)
if(sm.damage <= sm.warning_point) // Damage is too low, lets not
return FALSE
if (sm.damage >= sm.emergency_point && sm.damage_archived < sm.emergency_point)
sm.investigate_log("has entered the emergency point.", INVESTIGATE_ENGINE)
message_admins("[sm] has entered the emergency point [ADMIN_VERBOSEJMP(sm)].")
if((REALTIMEOFDAY - sm.lastwarning) < SUPERMATTER_WARNING_DELAY)
return FALSE
sm.lastwarning = REALTIMEOFDAY
switch(sm.get_status())
if(SUPERMATTER_DELAMINATING)
// SKYRAT EDIT ADDITION
alert_sound_to_playing('modular_skyrat/master_files/sound/effects/reactor/meltdown.ogg', override_volume = TRUE)
alert_sound_to_playing('modular_skyrat/modules/alerts/sound/alerts/alert1.ogg', override_volume = TRUE)
// SKYRAT EDIT END
playsound(sm, 'sound/misc/bloblarm.ogg', 100, FALSE, 40, 30, falloff_distance = 10)
if(SUPERMATTER_EMERGENCY)
// SKYRAT EDIT ADDITION
alert_sound_to_playing('modular_skyrat/master_files/sound/effects/reactor/core_overheating.ogg', override_volume = TRUE)
alert_sound_to_playing('modular_skyrat/modules/alerts/sound/alerts/alert1.ogg', override_volume = TRUE)
// SKYRAT EDIT END
playsound(sm, 'sound/machines/engine_alert1.ogg', 100, FALSE, 30, 30, falloff_distance = 10)
if(SUPERMATTER_DANGER)
playsound(sm, 'sound/machines/engine_alert2.ogg', 100, FALSE, 30, 30, falloff_distance = 10)
if(SUPERMATTER_WARNING)
playsound(sm, 'sound/machines/terminal_alert.ogg', 75)
if(sm.damage < sm.damage_archived) // Healing
sm.radio.talk_into(sm,"Crystalline hyperstructure returning to safe operating parameters. Integrity: [sm.get_integrity_percent()]%", sm.damage_archived >= sm.emergency_point ? sm.emergency_channel : sm.warning_channel)
return FALSE
if(sm.damage >= sm.emergency_point) // Taking damage, in emergency
sm.radio.talk_into(sm, "CRYSTAL DELAMINATION IMMINENT Integrity: [sm.get_integrity_percent()]%", sm.emergency_channel)
sm.lastwarning = REALTIMEOFDAY - (SUPERMATTER_WARNING_DELAY / 2) // Cut the time to next announcement in half.
else // Taking damage, in warning
sm.radio.talk_into(sm, "Danger! Crystal hyperstructure integrity faltering! Integrity: [sm.get_integrity_percent()]%", sm.warning_channel)
if(sm.damage_archived < sm.warning_point)
SEND_SIGNAL(sm, COMSIG_SUPERMATTER_DELAM_START_ALARM)
SEND_SIGNAL(sm, COMSIG_SUPERMATTER_DELAM_ALARM)
return TRUE
/// Called when a supermatter switches it's strategy from another one to us.
/// [/obj/machinery/power/supermatter_crystal/proc/set_delam]
/datum/sm_delam/proc/on_select(obj/machinery/power/supermatter_crystal/sm)
return
/// Called when a supermatter switches it's strategy from us to something else.
/// [/obj/machinery/power/supermatter_crystal/proc/set_delam]
/datum/sm_delam/proc/on_deselect(obj/machinery/power/supermatter_crystal/sm)
return
/// Added to an examine return value.
/// [/obj/machinery/power/supermatter_crystal/proc/examine]
/datum/sm_delam/proc/examine(obj/machinery/power/supermatter_crystal/sm)
return list()
/// Add whatever overlay to the sm.
/// [/obj/machinery/power/supermatter_crystal/proc/overlays]
/datum/sm_delam/proc/overlays(obj/machinery/power/supermatter_crystal/sm)
if(sm.final_countdown)
return list(mutable_appearance(sm.icon, "causality_field"))
return list()
/// Modifies the damage dealt to the sm.
/// [/obj/machinery/power/supermatter_crystal/proc/deal_damage]
/datum/sm_delam/proc/damage_multiplier(obj/machinery/power/supermatter_crystal/sm)
return 1
/// Returns a set of messages to be spouted during delams
/// First message is start of count down, second message is quitting of count down (if sm healed), third is 5 second intervals
/datum/sm_delam/proc/count_down_messages(obj/machinery/power/supermatter_crystal/sm)
var/list/messages = list()
messages += "CRYSTAL DELAMINATION IMMINENT. The supermatter has reached critical integrity failure. Emergency causality destabilization field has been activated."
messages += "Crystalline hyperstructure returning to safe operating parameters. Failsafe has been disengaged."
messages += "remain before causality stabilization."
return messages
@@ -0,0 +1,97 @@
/datum/sm_delam/cascade
/datum/sm_delam/cascade/can_select(obj/machinery/power/supermatter_crystal/sm)
if(!sm.is_main_engine)
return FALSE
var/total_moles = sm.absorbed_gasmix.total_moles()
if(total_moles < MOLE_PENALTY_THRESHOLD * sm.absorption_ratio)
return FALSE
for (var/gas_path in list(/datum/gas/antinoblium, /datum/gas/hypernoblium))
var/percent = sm.absorbed_gasmix.gases[gas_path]?[MOLES] / total_moles
if(!percent || percent < 0.4)
return FALSE
return TRUE
/datum/sm_delam/cascade/delam_progress(obj/machinery/power/supermatter_crystal/sm)
. = ..()
if(!.)
return FALSE
sm.radio.talk_into(
sm,
"DANGER: HYPERSTRUCTURE OSCILLATION FREQUENCY OUT OF BOUNDS.",
sm.damage >= sm.emergency_point ? sm.emergency_channel : sm.warning_channel
)
var/list/messages = list(
"Space seems to be shifting around you...",
"You hear a high-pitched ringing sound.",
"You feel tingling going down your back.",
"Something feels very off.",
"A drowning sense of dread washes over you.",
)
for(var/mob/victim as anything in GLOB.player_list)
to_chat(victim, span_danger(pick(messages)))
/datum/sm_delam/cascade/on_select(obj/machinery/power/supermatter_crystal/sm)
message_admins("[sm] is heading towards a cascade. [ADMIN_VERBOSEJMP(sm)]")
sm.investigate_log("is heading towards a cascade.", INVESTIGATE_ENGINE)
sm.warp = new(sm)
sm.vis_contents += sm.warp
animate(sm.warp, time = 1, transform = matrix().Scale(0.5,0.5))
animate(time = 9, transform = matrix())
addtimer(CALLBACK(src, .proc/announce_cascade, sm), 2 MINUTES)
/datum/sm_delam/cascade/on_deselect(obj/machinery/power/supermatter_crystal/sm)
message_admins("[sm] will no longer cascade. [ADMIN_VERBOSEJMP(sm)]")
sm.investigate_log("will no longer cascade.", INVESTIGATE_ENGINE)
sm.vis_contents -= sm.warp
QDEL_NULL(sm.warp)
/datum/sm_delam/cascade/delaminate(obj/machinery/power/supermatter_crystal/sm)
message_admins("Supermatter [sm] at [ADMIN_VERBOSEJMP(sm)] triggered a cascade delam.")
sm.investigate_log("triggered a cascade delam.", INVESTIGATE_ENGINE)
effect_explosion(sm)
effect_emergency_state()
effect_cascade_demoralize()
priority_announce("A Type-C resonance shift event has occurred in your sector. Scans indicate local oscillation flux affecting spatial and gravitational substructure. \
Multiple resonance hotspots have formed. Please standby.", "Nanotrasen Star Observation Association", ANNOUNCER_SPANOMALIES)
sleep(2 SECONDS)
effect_strand_shuttle()
sleep(5 SECONDS)
var/obj/cascade_portal/rift = effect_evac_rift_start()
RegisterSignal(rift, COMSIG_PARENT_QDELETING, .proc/end_round_holder)
effect_crystal_mass(sm, rift)
SSsupermatter_cascade.cascade_initiated = TRUE
qdel(sm)
/datum/sm_delam/cascade/examine(obj/machinery/power/supermatter_crystal/sm)
return list(span_bolddanger("The crystal is vibrating at immense speeds, warping space around it!"))
/datum/sm_delam/cascade/overlays(obj/machinery/power/supermatter_crystal/sm)
return list()
/datum/sm_delam/cascade/damage_multiplier(obj/machinery/power/supermatter_crystal/sm)
return 0.25
/datum/sm_delam/cascade/count_down_messages(obj/machinery/power/supermatter_crystal/sm)
var/list/messages = list()
messages += "CRYSTAL DELAMINATION IMMINENT. The supermatter has reached critical integrity failure. Harmonic frequency limits exceeded. Causality destabilization field could not be engaged."
messages += "Crystalline hyperstructure returning to safe operating parameters. Harmonic frequency restored within emergency bounds. Anti-resonance filter initiated."
messages += "remain before resonance-induced stabilization."
return messages
/datum/sm_delam/cascade/proc/announce_cascade(obj/machinery/power/supermatter_crystal/sm)
if(!can_select(sm))
return FALSE
priority_announce("Attention: Long range anomaly scans indicate abnormal quantities of harmonic flux originating from \
a subject within [station_name()], a resonance collapse may occur.",
"Nanotrasen Star Observation Association")
return TRUE
/// Signal calls cant sleep, we gotta do this.
/datum/sm_delam/cascade/proc/end_round_holder()
SIGNAL_HANDLER
INVOKE_ASYNC(src, .proc/effect_evac_rift_end)
@@ -110,6 +110,22 @@
pixel_y = -96
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
/obj/cascade_portal/Initialize(mapload)
. = ..()
var/turf/location = get_turf(src)
var/area_name = get_area_name(src)
message_admins("Exit rift created at [area_name]. [ADMIN_VERBOSEJMP(location)]")
log_game("Bluespace Exit Rift was created at [area_name].")
investigate_log("created at [area_name].", INVESTIGATE_ENGINE)
/obj/cascade_portal/Destroy(force)
var/turf/location = get_turf(src)
var/area_name = get_area_name(src)
message_admins("Exit rift at [area_name] deleted. [ADMIN_VERBOSEJMP(location)]")
log_game("Bluespace Exit Rift at [area_name] was deleted.")
investigate_log("was deleted.", INVESTIGATE_ENGINE)
return ..()
/obj/cascade_portal/Bumped(atom/movable/hit_object)
consume(hit_object)
new /obj/effect/particle_effect/sparks(loc)
@@ -135,7 +151,7 @@
while(!is_safe_turf(arrival_turf))
var/mob/living/consumed_mob = consumed_object
message_admins("[key_name_admin(consumed_mob)] has entered [src] [ADMIN_JMP(src)].")
message_admins("[key_name_admin(consumed_mob)] has entered [src] [ADMIN_VERBOSEJMP(src)].")
investigate_log("was entered by [key_name(consumed_mob)].", INVESTIGATE_ENGINE)
consumed_mob.forceMove(arrival_turf)
consumed_mob.Paralyze(100)
@@ -149,3 +165,4 @@
span_hear("You hear a loud crack as a small distortion passes through you."))
qdel(consumed_object)
@@ -0,0 +1,74 @@
// Singulo, tesla, and explosive delam
/// When we have too much gas.
/datum/sm_delam/singularity
/datum/sm_delam/singularity/can_select(obj/machinery/power/supermatter_crystal/sm)
return (sm.absorbed_gasmix.total_moles() >= MOLE_PENALTY_THRESHOLD)
/datum/sm_delam/singularity/delam_progress(obj/machinery/power/supermatter_crystal/sm)
. = ..()
if(!.)
return FALSE
sm.radio.talk_into(
sm,
"Warning: Critical coolant mass reached.",
sm.damage > sm.emergency_point ? sm.emergency_channel : sm.warning_channel
)
/datum/sm_delam/singularity/delaminate(obj/machinery/power/supermatter_crystal/sm)
message_admins("Supermatter [sm] at [ADMIN_VERBOSEJMP(sm)] triggered a singularity delam.")
sm.investigate_log("triggered a singularity delam.", INVESTIGATE_ENGINE)
effect_irradiate(sm)
effect_demoralize(sm)
if(sm.is_main_engine)
effect_anomaly(sm)
if(!effect_singulo(sm))
effect_explosion(sm)
qdel(sm)
/// When we have too much power.
/datum/sm_delam/tesla
/datum/sm_delam/tesla/can_select(obj/machinery/power/supermatter_crystal/sm)
return (sm.power > POWER_PENALTY_THRESHOLD)
/datum/sm_delam/tesla/delam_progress(obj/machinery/power/supermatter_crystal/sm)
. = ..()
if(!.)
return FALSE
sm.radio.talk_into(
sm,
"DANGER: CHARGE INERTIA CHAIN REACTION IN PROGRESS.",
sm.damage > sm.emergency_point ? sm.emergency_channel : sm.warning_channel
)
/datum/sm_delam/tesla/delaminate(obj/machinery/power/supermatter_crystal/sm)
message_admins("Supermatter [sm] at [ADMIN_VERBOSEJMP(sm)] triggered a tesla delam.")
sm.investigate_log("triggered a tesla delam.", INVESTIGATE_ENGINE)
effect_irradiate(sm)
effect_demoralize(sm)
if(sm.is_main_engine)
effect_anomaly(sm)
effect_tesla(sm)
effect_explosion(sm)
qdel(sm)
/// Default delam.
/datum/sm_delam/explosive
/datum/sm_delam/explosive/can_select(obj/machinery/power/supermatter_crystal/sm)
return TRUE
/datum/sm_delam/explosive/delaminate(obj/machinery/power/supermatter_crystal/sm)
message_admins("Supermatter [sm] at [ADMIN_VERBOSEJMP(sm)] triggered a normal delam.")
sm.investigate_log("triggered a normal delam.", INVESTIGATE_ENGINE)
effect_irradiate(sm)
effect_demoralize(sm)
if(sm.is_main_engine)
effect_anomaly(sm)
effect_explosion(sm)
qdel(sm)
@@ -0,0 +1,212 @@
// These are supposed to be discrete effects so we can tell at a glance what does each override
// of [/datum/sm_delam/proc/delaminate] does.
// Please keep them discrete and give them proper, descriptive function names.
// Oh and all of them returns true if the effect succeeded.
/// Irradiates mobs around 20 tiles of the sm.
/// Just the mobs apparently.
/datum/sm_delam/proc/effect_irradiate(obj/machinery/power/supermatter_crystal/sm)
var/turf/sm_turf = get_turf(sm)
for (var/mob/living/victim in range(20, sm))
if(victim.z != sm_turf.z)
continue
SSradiation.irradiate(victim)
return TRUE
/// Hallucinates and makes mobs in Z level sad.
/datum/sm_delam/proc/effect_demoralize(obj/machinery/power/supermatter_crystal/sm)
var/turf/sm_turf = get_turf(sm)
for(var/mob/living/victim as anything in GLOB.alive_mob_list)
if(!istype(victim) || victim.z != sm_turf.z)
continue
if(ishuman(victim))
//Hilariously enough, running into a closet should make you get hit the hardest.
var/mob/living/carbon/human/human = victim
human.hallucination += max(50, min(300, DETONATION_HALLUCINATION * sqrt(1 / (get_dist(victim, sm) + 1)) ) )
for(var/mob/victim as anything in GLOB.player_list)
var/turf/mob_turf = get_turf(victim)
if(sm_turf.z != mob_turf.z)
continue
SEND_SOUND(victim, 'sound/magic/charge.ogg')
if (victim.z != sm_turf.z)
to_chat(victim, span_boldannounce("You hold onto \the [victim.loc] as hard as you can, as reality distorts around you. You feel safe."))
continue
to_chat(victim, span_boldannounce("You feel reality distort for a moment..."))
SEND_SIGNAL(victim, COMSIG_ADD_MOOD_EVENT, "delam", /datum/mood_event/delam)
return TRUE
/// Spawns anomalies all over the station. Half instantly, the other half over time.
/datum/sm_delam/proc/effect_anomaly(obj/machinery/power/supermatter_crystal/sm)
var/anomalies = 10
var/list/anomaly_types = list(GRAVITATIONAL_ANOMALY = 55, HALLUCINATION_ANOMALY = 45, DELIMBER_ANOMALY = 35, FLUX_ANOMALY = 25, PYRO_ANOMALY = 5, VORTEX_ANOMALY = 1)
var/list/anomaly_places = GLOB.generic_event_spawns
// Spawns this many anomalies instantly. Spawns the rest with callbacks.
var/cutoff_point = round(anomalies * 0.5, 1)
for(var/i in 1 to anomalies)
var/anomaly_to_spawn = pick_weight(anomaly_types)
var/anomaly_location = pick_n_take(anomaly_places)
if(i < cutoff_point)
supermatter_anomaly_gen(anomaly_location, anomaly_to_spawn, has_changed_lifespan = FALSE)
continue
var/current_spawn = rand(5 SECONDS, 10 SECONDS)
var/next_spawn = rand(5 SECONDS, 10 SECONDS)
var/extended_spawn = 0
if(DT_PROB(1, next_spawn))
extended_spawn = rand(5 MINUTES, 15 MINUTES)
addtimer(CALLBACK(GLOBAL_PROC, .proc/supermatter_anomaly_gen, anomaly_location, anomaly_to_spawn, TRUE), current_spawn + extended_spawn)
return TRUE
/// Explodes
/datum/sm_delam/proc/effect_explosion(obj/machinery/power/supermatter_crystal/sm)
var/explosion_power = sm.explosion_power
var/power_scaling = sm.gasmix_power_ratio
var/turf/sm_turf = get_turf(sm)
//Dear mappers, balance the sm max explosion radius to 17.5, 37, 39, 41
explosion(origin = sm_turf,
devastation_range = explosion_power * max(power_scaling, 0.205) * 0.5,
heavy_impact_range = explosion_power * max(power_scaling, 0.205) + 2,
light_impact_range = explosion_power * max(power_scaling, 0.205) + 4,
flash_range = explosion_power * max(power_scaling, 0.205) + 6,
adminlog = TRUE,
ignorecap = TRUE
)
return TRUE
/// Spawns a scrung and eat the SM.
/datum/sm_delam/proc/effect_singulo(obj/machinery/power/supermatter_crystal/sm)
var/turf/sm_turf = get_turf(sm)
if(!sm_turf)
stack_trace("Supermatter [sm] failed to spawn singularity, cant get current turf.")
return FALSE
var/obj/singularity/created_singularity = new(sm_turf)
created_singularity.energy = 800
created_singularity.consume(sm)
return TRUE
/// Teslas
/datum/sm_delam/proc/effect_tesla(obj/machinery/power/supermatter_crystal/sm)
var/turf/sm_turf = get_turf(sm)
if(!sm_turf)
stack_trace("Supermatter [sm] failed to spawn tesla, cant get current turf.")
return FALSE
var/obj/energy_ball/created_tesla = new(sm_turf)
created_tesla.energy = 200 //Gets us about 9 balls
return TRUE
/// Mail the shuttle off to buy milk.
/datum/sm_delam/proc/effect_strand_shuttle()
set waitfor = FALSE
// set timer to infinity, so shuttle never arrives
SSshuttle.emergency.setTimer(INFINITY)
// disallow shuttle recalls, so people cannot cheese the timer
SSshuttle.emergency_no_recall = TRUE
// set supermatter cascade to true, to prevent auto evacuation due to no way of calling the shuttle
SSshuttle.supermatter_cascade = TRUE
// set hijack completion timer to infinity, so that you cant prematurely end the round with a hijack
for(var/obj/machinery/computer/emergency_shuttle/console in GLOB.machines)
console.hijack_completion_flight_time_set = INFINITY
/* This logic is to keep uncalled shuttles uncalled
In SSshuttle, there is not much of a way to prevent shuttle calls, unless we mess with admin panel vars
SHUTTLE_STRANDED is different here, because it *can* block the shuttle from being called, however if we don't register a hostile
environment, it gets unset immediately. Internally, it checks if the count of HEs is zero
and that the shuttle is in stranded mode, then frees it with an announcement.
This is a botched solution to a problem that could be solved with a small change in shuttle code, however-
*/
if(SSshuttle.emergency.mode == SHUTTLE_IDLE)
SSshuttle.emergency.mode = SHUTTLE_STRANDED
SSshuttle.registerHostileEnvironment(src)
return
// say goodbye to that shuttle of yours
if(SSshuttle.emergency.mode != SHUTTLE_ESCAPE)
priority_announce("Fatal error occurred in emergency shuttle uplink during transit. Unable to reestablish connection.",
"Emergency Shuttle Uplink Alert", 'sound/misc/announce_dig.ogg')
else
// except if you are on it already, then you are safe c:
minor_announce("ERROR: Corruption detected in navigation protocols. Connection with Transponder #XCC-P5831-ES13 lost. \
Backup exit route protocol decrypted. Calibrating route...",
"Emergency Shuttle", TRUE) // wait out until the rift on the station gets destroyed and the final message plays
var/list/mobs = mobs_in_area_type(list(/area/shuttle/escape))
for(var/mob/living/mob as anything in mobs) // emulate mob/living/lateShuttleMove() behaviour
if(mob.buckled)
continue
if(mob.client)
shake_camera(mob, 3 SECONDS * 0.25, 1)
mob.Paralyze(3 SECONDS, TRUE)
/datum/sm_delam/proc/effect_cascade_demoralize()
for(var/mob/player as anything in GLOB.player_list)
if(!isdead(player))
to_chat(player, span_boldannounce("Everything around you is resonating with a powerful energy. This can't be good."))
SEND_SIGNAL(player, COMSIG_ADD_MOOD_EVENT, "cascade", /datum/mood_event/cascade)
SEND_SOUND(player, 'sound/magic/charge.ogg')
/datum/sm_delam/proc/effect_emergency_state()
if(SSsecurity_level.get_current_level_as_number() != SEC_LEVEL_DELTA)
SSsecurity_level.set_level(SEC_LEVEL_DELTA) // skip the announcement and shuttle timer adjustment in set_security_level()
make_maint_all_access()
for(var/obj/machinery/light/light_to_break in GLOB.machines)
if(prob(35))
light_to_break.set_major_emergency_light()
continue
light_to_break.break_light_tube()
/// Spawn an evacuation rift for people to go through.
/datum/sm_delam/proc/effect_evac_rift_start()
var/obj/cascade_portal/rift = new /obj/cascade_portal(get_turf(pick(GLOB.generic_event_spawns)))
priority_announce("We have been hit by a sector-wide electromagnetic pulse. All of our systems are heavily damaged, including those \
required for shuttle navigation. We can only reasonably conclude that a supermatter cascade is occurring on or near your station.\n\n\
Evacuation is no longer possible by conventional means; however, we managed to open a rift near the [get_area_name(rift)]. \
All personnel are hereby required to enter the rift by any means available.\n\n\
[Gibberish("Retrieval of survivors will be conducted upon recovery of necessary facilities.", FALSE, 5)] \
[Gibberish("Good luck--", FALSE, 25)]")
return rift
/// Announce the destruction of the rift and end the round.
/datum/sm_delam/proc/effect_evac_rift_end()
priority_announce("[Gibberish("The rift has been destroyed, we can no longer help you.", FALSE, 5)]")
sleep(25 SECONDS)
priority_announce("Reports indicate formation of crystalline seeds following resonance shift event. \
Rapid expansion of crystal mass proportional to rising gravitational force. \
Matter collapse due to gravitational pull foreseeable.",
"Nanotrasen Star Observation Association")
sleep(25 SECONDS)
priority_announce("[Gibberish("All attempts at evacuation have now ceased, and all assets have been retrieved from your sector.\n \
To the remaining survivors of [station_name()], farewell.", FALSE, 5)]")
if(SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
// special message for hijacks
var/shuttle_msg = "Navigation protocol set to [SSshuttle.emergency.is_hijacked() ? "\[ERROR\]" : "backup route"]. \
Reorienting bluespace vessel to exit vector. ETA 15 seconds."
// garble the special message
if(SSshuttle.emergency.is_hijacked())
shuttle_msg = Gibberish(shuttle_msg, TRUE, 15)
minor_announce(shuttle_msg, "Emergency Shuttle", TRUE)
SSshuttle.emergency.setTimer(15 SECONDS)
return
sleep(10 SECONDS)
SSticker.news_report = SUPERMATTER_CASCADE
SSticker.force_ending = TRUE
/// Scatters crystal mass over the event spawns as long as they are at least 30 tiles away from whatever we want to avoid.
/datum/sm_delam/proc/effect_crystal_mass(obj/machinery/power/supermatter_crystal/sm, avoid)
new /obj/crystal_mass(get_turf(sm))
var/list/possible_spawns = GLOB.generic_event_spawns.Copy()
for(var/i in 1 to rand(4,6))
var/spawn_location
do
spawn_location = pick_n_take(possible_spawns)
while(get_dist(spawn_location, avoid) < 30)
new /obj/crystal_mass(get_turf(spawn_location))
@@ -39,7 +39,7 @@
has_been_powered = TRUE
else if(takes_damage)
damage += (projectile.damage * bullet_energy) * clamp((emergency_point - damage) / emergency_point, 0, 1)
if(damage > damage_penalty_point)
if(damage > danger_point)
visible_message(span_notice("[src] compresses under stress, resisting further impacts!"))
return BULLET_ACT_HIT
@@ -88,7 +88,7 @@
if(istype(item, /obj/item/destabilizing_crystal))
var/obj/item/destabilizing_crystal/destabilizing_crystal = item
if(!anomaly_event)
if(!is_main_engine)
to_chat(user, span_warning("You can't use \the [destabilizing_crystal] on \a [name]."))
return
@@ -102,11 +102,9 @@
log_game("[key_name(user)] attached [destabilizing_crystal] to the supermatter at [AREACOORD(src)]")
investigate_log("[key_name(user)] attached [destabilizing_crystal] to a supermatter crystal.", INVESTIGATE_ENGINE)
to_chat(user, span_danger("\The [destabilizing_crystal] snaps onto \the [src]."))
has_destabilizing_crystal = TRUE
cascade_initiated = TRUE
set_delam(SM_DELAM_PRIO_IN_GAME, /datum/sm_delam/cascade)
damage += 100
matter_power += 500
addtimer(CALLBACK(src, .proc/announce_incoming_cascade), 2 MINUTES)
qdel(destabilizing_crystal)
return
@@ -20,13 +20,12 @@
//Ok, get the air from the turf
var/datum/gas_mixture/env = local_turf.return_air()
environment_total_moles = env.total_moles()
var/datum/gas_mixture/removed
if(produces_gas)
//Remove gas from surrounding area
removed = env.remove(gasefficency * env.total_moles())
absorbed_gasmix = env.remove(absorption_ratio * env.total_moles())
else
// Pass all the gas related code an empty gas container
removed = new()
absorbed_gasmix = new()
overlays -= psyOverlay
if(psy_overlay)
overlays -= psyOverlay
@@ -36,61 +35,38 @@
else
psy_overlay = FALSE
damage_archived = damage
if(!removed || !removed.total_moles() || isspaceturf(local_turf)) //we're in space or there is no gas to process
if(!absorbed_gasmix || !absorbed_gasmix.total_moles() || isspaceturf(local_turf)) //we're in space or there is no gas to process
if(takes_damage)
damage += max((power / 1000) * DAMAGE_INCREASE_MULTIPLIER, 0.1) // always does at least some damage
if(!istype(env, /datum/gas_mixture/immutable) && produces_gas && power) //There is no gas to process, but we are not in a space turf. Lets make them.
//Power * 0.55 * a value between 1 and 0.8
var/device_energy = power * REACTION_POWER_MODIFIER * (1 - (psyCoeff * 0.2))
//Can't do stuff if it's null, so lets make a new gasmix.
removed = new()
absorbed_gasmix = new()
//Since there is no gas to process, we will produce as if heat penalty is 1 and temperature at TCMB.
removed.assert_gases(/datum/gas/plasma, /datum/gas/oxygen)
removed.temperature = ((device_energy) / THERMAL_RELEASE_MODIFIER)
removed.temperature = max(TCMB, min(removed.temperature, 2500))
removed.gases[/datum/gas/plasma][MOLES] = max((device_energy) / PLASMA_RELEASE_MODIFIER, 0)
removed.gases[/datum/gas/oxygen][MOLES] = max(((device_energy + TCMB) - T0C) / OXYGEN_RELEASE_MODIFIER, 0)
removed.garbage_collect()
env.merge(removed)
absorbed_gasmix.assert_gases(/datum/gas/plasma, /datum/gas/oxygen)
absorbed_gasmix.temperature = ((device_energy) / THERMAL_RELEASE_MODIFIER)
absorbed_gasmix.temperature = max(TCMB, min(absorbed_gasmix.temperature, 2500))
absorbed_gasmix.gases[/datum/gas/plasma][MOLES] = max((device_energy) / PLASMA_RELEASE_MODIFIER, 0)
absorbed_gasmix.gases[/datum/gas/oxygen][MOLES] = max(((device_energy + TCMB) - T0C) / OXYGEN_RELEASE_MODIFIER, 0)
absorbed_gasmix.garbage_collect()
env.merge(absorbed_gasmix)
air_update_turf(FALSE, FALSE)
else
if(takes_damage)
//causing damage
deal_damage(removed)
deal_damage(absorbed_gasmix)
//registers the current enviromental gases in the various lists and vars
setup_lists(removed)
setup_lists(absorbed_gasmix)
//some gases can have special interactions
special_gases_interactions(env, removed)
special_gases_interactions(env, absorbed_gasmix)
//main power calculations proc
power_calculations(env, removed)
power_calculations(env, absorbed_gasmix)
//irradiate at this point
emit_radiation()
//handles temperature increase and gases made by the crystal
temperature_gas_production(env, removed)
var/cascading = check_cascade_requirements()
if(cascading)
if(!cascade_initiated)
addtimer(CALLBACK(src, .proc/announce_incoming_cascade), 2 MINUTES, TIMER_UNIQUE | TIMER_OVERRIDE)
log_game("[src] has begun a cascade.")
message_admins("[src] has begun a cascade, reasons: [cascading]. [ADMIN_JMP(src)]")
investigate_log("has begun a cascade, reasons: [cascading].", INVESTIGATE_ENGINE)
cascade_initiated = TRUE
if(!warp)
warp = new(src)
vis_contents += warp
animate(warp, time = 1, transform = matrix().Scale(0.5,0.5))
animate(time = 9, transform = matrix())
else
if(warp)
vis_contents -= warp
QDEL_NULL(warp)
if(cascade_initiated)
log_game("[src] has stopped its cascade.")
message_admins("[src] has stopped its cascade. [ADMIN_JMP(src)]")
investigate_log("has stopped its cascade.", INVESTIGATE_ENGINE)
cascade_initiated = FALSE
temperature_gas_production(env, absorbed_gasmix)
//handles hallucinations and the presence of a psychiatrist
psychological_examination()
@@ -105,16 +81,19 @@
//After this point power is lowered
//This wraps around to the begining of the function
//Handle high power zaps/anomaly generation
handle_high_power(removed)
handle_high_power(absorbed_gasmix)
if(prob(15))
supermatter_pull(loc, min(power/850, 3))//850, 1700, 2550
//Tells the engi team to get their butt in gear
handle_emergency_alerts()
if(damage == 0) // Clear any in game forced delams if on full health.
set_delam(SM_DELAM_PRIO_IN_GAME, SM_DELAM_STRATEGY_PURGE)
else
set_delam() // This one cant clear any forced delams.
delamination_strategy.delam_progress(src)
if(damage == 0 && has_destabilizing_crystal)
has_destabilizing_crystal = FALSE
if(damage > explosion_point && !final_countdown)
count_down()
return TRUE
@@ -148,7 +127,7 @@
has_holes = TRUE
break
var/cascade_multiplier = cascade_initiated ? 0.25 : 1
var/delam_damage_multipler = delamination_strategy.damage_multiplier(src)
//Due to DAMAGE_INCREASE_MULTIPLIER, we only deal one 4th of the damage the statements otherwise would cause
//((((some value between 0.5 and 1 * temp - ((273.15 + 40) * some values between 1 and 10)) * some number between 0.25 and knock your socks off / 150) * 0.25
@@ -156,9 +135,9 @@
//Mols start to have a positive effect on damage after 350
damage = max(damage + (max(clamp(removed.total_moles() / 200, 0.5, 1) * removed.temperature - ((T0C + HEAT_PENALTY_THRESHOLD)*dynamic_heat_resistance), 0) * mole_heat_penalty / 150 ) * DAMAGE_INCREASE_MULTIPLIER, 0)
//Power only starts affecting damage when it is above 5000 (1250 when a cascade is occurring)
damage = max(damage + (max(power - (POWER_PENALTY_THRESHOLD * cascade_multiplier), 0)/500) * DAMAGE_INCREASE_MULTIPLIER, 0)
damage = max(damage + (max(power - (POWER_PENALTY_THRESHOLD * delam_damage_multipler), 0)/500) * DAMAGE_INCREASE_MULTIPLIER, 0)
//Molar count only starts affecting damage when it is above 1800 (450 when a cascade is occurring)
damage = max(damage + (max(combined_gas - (MOLE_PENALTY_THRESHOLD * cascade_multiplier), 0)/80) * DAMAGE_INCREASE_MULTIPLIER, 0)
damage = max(damage + (max(combined_gas - (MOLE_PENALTY_THRESHOLD * delam_damage_multipler), 0)/80) * DAMAGE_INCREASE_MULTIPLIER, 0)
//There might be a way to integrate healing and hurting via heat
//healing damage
@@ -360,7 +339,7 @@
psyCoeff = clamp(psyCoeff + psy_coeff_diff, 0, 1)
/obj/machinery/power/supermatter_crystal/proc/handle_high_power(datum/gas_mixture/removed)
if(power <= POWER_PENALTY_THRESHOLD && damage <= damage_penalty_point) //If the power is above 5000 or if the damage is above 550
if(power <= POWER_PENALTY_THRESHOLD && damage <= danger_point) //If the power is above 5000 or if the damage is above 550
return
var/range = 4
zap_cutoff = 1500
@@ -390,7 +369,7 @@
flags |= (ZAP_MOB_STUN | ZAP_MACHINE_EXPLOSIVE | ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE)
zap_count = 4
//Now we deal with damage shit
if (damage > damage_penalty_point && prob(20))
if (damage > danger_point && prob(20))
zap_count += 1
if(zap_count >= 1)
@@ -407,59 +386,38 @@
if((power > SEVERE_POWER_PENALTY_THRESHOLD && prob(2)) || (prob(0.3) && power > POWER_PENALTY_THRESHOLD))
supermatter_anomaly_gen(src, PYRO_ANOMALY, rand(5, 10))
/obj/machinery/power/supermatter_crystal/proc/handle_emergency_alerts()
if(damage <= warning_point) // while the core is still damaged and it's still worth noting its status
return
if(damage_archived < warning_point) //If damage_archive is under the warning point, this is the very first cycle that we've reached said point.
SEND_SIGNAL(src, COMSIG_SUPERMATTER_DELAM_START_ALARM)
if((REALTIMEOFDAY - lastwarning) / 10 >= WARNING_DELAY)
alarm()
/**
* Sets the delam of our sm.
*
* Arguments:
* * priority: Truthy values means a forced delam. If current forced_delam is higher than priority we dont run.
* Set to a number higher than [SM_DELAM_PRIO_IN_GAME] to fully force an admin delam.
* * delam_path: Typepath of a [/datum/sm_delam]. [SM_DELAM_STRATEGY_PURGE] means reset and put prio back to zero.
*
* Returns: Not used for anything, just returns true on succesful set, manual and automatic. Helps admins check stuffs.
*/
/obj/machinery/power/supermatter_crystal/proc/set_delam(priority = SM_DELAM_PRIO_NONE, manual_delam_path = SM_DELAM_STRATEGY_PURGE)
if(priority < delam_priority)
return FALSE
var/datum/sm_delam/new_delam = null
//Oh shit it's bad, time to freak out
if(damage > emergency_point)
radio.talk_into(src, "[emergency_alert] Integrity: [get_integrity_percent()]%", common_channel)
SEND_SIGNAL(src, COMSIG_SUPERMATTER_DELAM_ALARM)
lastwarning = REALTIMEOFDAY
if(!has_reached_emergency)
investigate_log("has reached the emergency point for the first time.", INVESTIGATE_ENGINE)
message_admins("[src] has reached the emergency point [ADMIN_JMP(src)].")
has_reached_emergency = TRUE
else if(damage >= damage_archived) // The damage is still going up
radio.talk_into(src, "[warning_alert] Integrity: [get_integrity_percent()]%", engineering_channel)
SEND_SIGNAL(src, COMSIG_SUPERMATTER_DELAM_ALARM)
lastwarning = REALTIMEOFDAY - (WARNING_DELAY * 5)
if(manual_delam_path == SM_DELAM_STRATEGY_PURGE)
for (var/delam_path in GLOB.sm_delam_list)
var/datum/sm_delam/delam = GLOB.sm_delam_list[delam_path]
if(!delam.can_select(src))
continue
if(delam == delamination_strategy)
return FALSE
new_delam = delam
break
delam_priority = SM_DELAM_PRIO_NONE
else
new_delam = GLOB.sm_delam_list[manual_delam_path]
delam_priority = priority
else // Phew, we're safe
radio.talk_into(src, "[safe_alert] Integrity: [get_integrity_percent()]%", engineering_channel)
lastwarning = REALTIMEOFDAY
if(power > POWER_PENALTY_THRESHOLD)
radio.talk_into(src, "Warning: Hyperstructure has reached dangerous power level.", engineering_channel)
if(powerloss_inhibitor < 0.5)
radio.talk_into(src, "DANGER: CHARGE INERTIA CHAIN REACTION IN PROGRESS.", engineering_channel)
if(combined_gas > MOLE_PENALTY_THRESHOLD)
radio.talk_into(src, "Warning: Critical coolant mass reached.", engineering_channel)
if(check_cascade_requirements())
var/channel_to_talk_to = damage > emergency_point ? common_channel : engineering_channel
radio.talk_into(src, "DANGER: HYPERSTRUCTURE OSCILLATION FREQUENCY OUT OF BOUNDS.", channel_to_talk_to)
for(var/mob/victim as anything in GLOB.player_list)
var/list/messages = list(
"Space seems to be shifting around you...",
"You hear a high-pitched ringing sound.",
"You feel tingling going down your back.",
"Something feels very off.",
"A drowning sense of dread washes over you."
)
to_chat(victim, span_danger(pick(messages)))
//Boom (Mind blown)
if(damage > explosion_point)
countdown()
/obj/machinery/power/supermatter_crystal/proc/announce_incoming_cascade()
if(check_cascade_requirements())
priority_announce("Attention: Long range anomaly scans indicate abnormal quantities of harmonic flux originating from \
a subject within [station_name()], a resonance collapse may occur.",
"Nanotrasen Star Observation Association")
if(!new_delam)
return FALSE
delamination_strategy?.on_deselect(src)
delamination_strategy = new_delam
delamination_strategy.on_select(src)
return TRUE
+5 -2
View File
@@ -3967,11 +3967,14 @@
#include "code\modules\power\singularity\narsie.dm"
#include "code\modules\power\singularity\singularity.dm"
#include "code\modules\power\supermatter\supermatter.dm"
#include "code\modules\power\supermatter\supermatter_cascade_components.dm"
#include "code\modules\power\supermatter\supermatter_delamination.dm"
#include "code\modules\power\supermatter\supermatter_hit_procs.dm"
#include "code\modules\power\supermatter\supermatter_process.dm"
#include "code\modules\power\supermatter\supermatter_radiation.dm"
#include "code\modules\power\supermatter\supermatter_delamination\_sm_delam.dm"
#include "code\modules\power\supermatter\supermatter_delamination\cascade_delam.dm"
#include "code\modules\power\supermatter\supermatter_delamination\cascade_delam_objects.dm"
#include "code\modules\power\supermatter\supermatter_delamination\common_delams.dm"
#include "code\modules\power\supermatter\supermatter_delamination\delamination_effects.dm"
#include "code\modules\power\tesla\coil.dm"
#include "code\modules\power\tesla\energy_ball.dm"
#include "code\modules\power\turbine\turbine.dm"