diff --git a/code/__DEFINES/supermatter_defines.dm b/code/__DEFINES/supermatter_defines.dm new file mode 100644 index 000000000000..b8b8611e27fa --- /dev/null +++ b/code/__DEFINES/supermatter_defines.dm @@ -0,0 +1,5 @@ +#define SM_EVENT_THREAT_D "Delta" +#define SM_EVENT_THREAT_C "Charlie" +#define SM_EVENT_THREAT_B "Bravo" +#define SM_EVENT_THREAT_A "Alpha" +#define SM_EVENT_THREAT_S "Sierra" diff --git a/code/game/machinery/computer/sm_monitor.dm b/code/game/machinery/computer/sm_monitor.dm index 52ea9e88affa..4c5e1171af58 100644 --- a/code/game/machinery/computer/sm_monitor.dm +++ b/code/game/machinery/computer/sm_monitor.dm @@ -144,4 +144,3 @@ if("back") active = null - diff --git a/code/modules/events/apc_short.dm b/code/modules/events/apc_short.dm index 7af88445c54e..c1528dc03ccc 100644 --- a/code/modules/events/apc_short.dm +++ b/code/modules/events/apc_short.dm @@ -59,17 +59,7 @@ continue // if we are going to break this one if(prob(APC_BREAK_PROBABILITY)) - // if it has internal wires, cut the power wires - if(A.wires) - if(!A.wires.is_cut(WIRE_MAIN_POWER1)) - A.wires.cut(WIRE_MAIN_POWER1) - if(!A.wires.is_cut(WIRE_MAIN_POWER2)) - A.wires.cut(WIRE_MAIN_POWER2) - // if it was operating, toggle off the breaker - if(A.operating) - A.toggle_breaker() - // no matter what, ensure the area knows something happened to the power - current_area.powernet.power_change() + A.apc_short() affected_apc_count++ log_and_message_admins("APC Short Out event has shorted out [affected_apc_count] APCs.") diff --git a/code/modules/power/apc/apc.dm b/code/modules/power/apc/apc.dm index a75c6f7f0593..38d6472ec4cd 100644 --- a/code/modules/power/apc/apc.dm +++ b/code/modules/power/apc/apc.dm @@ -1012,6 +1012,19 @@ to_chat(user, "You emag the APC interface.") update_icon() +/obj/machinery/power/apc/proc/apc_short() + // if it has internal wires, cut the power wires + if(wires) + if(!wires.is_cut(WIRE_MAIN_POWER1)) + wires.cut(WIRE_MAIN_POWER1) + if(!wires.is_cut(WIRE_MAIN_POWER2)) + wires.cut(WIRE_MAIN_POWER2) + // if it was operating, toggle off the breaker + if(operating) + toggle_breaker() + // no matter what, ensure the area knows something happened to the power + apc_area.powernet.power_change() + /// ************* /// APC subtypes /// ************* diff --git a/code/modules/power/engines/supermatter/supermatter.dm b/code/modules/power/engines/supermatter/supermatter.dm index 4bb907ddc9e4..a63d670cfec4 100644 --- a/code/modules/power/engines/supermatter/supermatter.dm +++ b/code/modules/power/engines/supermatter/supermatter.dm @@ -155,6 +155,8 @@ var/dynamic_heat_resistance = 1 ///Uses powerloss_dynamic_scaling and combined_gas to lessen the effects of our powerloss functions var/powerloss_inhibitor = 1 + ///value plus T0C = temp at which the SM starts to take damage. Variable for event usage + var/heat_penalty_threshold = HEAT_PENALTY_THRESHOLD ///Based on co2 percentage, slowly moves between 0 and 1. We use it to calc the powerloss_inhibitor var/powerloss_dynamic_scaling= 0 ///Affects the amount of radiation the sm makes. We multiply this with power to find the rads. @@ -206,6 +208,23 @@ ///Disables the sm's proccessing totally. var/processes = TRUE + //vars used for supermatter events (Anomalous crystal activityw) + /// Do we have an active event? + var/datum/supermatter_event/event_active + ///flat multiplies the amount of gas released by the SM. + var/gas_multiplier = 1 + ///flat multiplies the heat released by the SM + var/heat_multiplier = 1 + ///amount of EER to ADD + var/power_additive = 0 + /// A list of all previous events + var/list/last_events + /// Time of next event + var/next_event_time + /// Run S-Class event? So we can only run one S-class event per round per crystal + var/has_run_sclass = FALSE + + /obj/machinery/atmospherics/supermatter_crystal/Initialize(mapload) . = ..() supermatter_id = global_supermatter_id++ @@ -220,6 +239,7 @@ if(is_main_engine) GLOB.main_supermatter_engine = src soundloop = new(list(src), TRUE) + make_next_event_time() /obj/machinery/atmospherics/supermatter_crystal/Destroy() if(warp) @@ -399,6 +419,8 @@ visible_message("[src] melts through [T]!") return + try_events() + //We vary volume by power, and handle OH FUCK FUSION IN COOLING LOOP noises. if(power) soundloop.volume = clamp((50 + (power / 50)), 50, 100) @@ -439,7 +461,7 @@ //((((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 //Heat and mols account for each other, a lot of hot mols are more damaging then a few //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) + 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 damage = max(damage + (max(power - POWER_PENALTY_THRESHOLD, 0)/500) * DAMAGE_INCREASE_MULTIPLIER, 0) //Molar count only starts affecting damage when it is above 1800 @@ -449,7 +471,7 @@ //healing damage if(combined_gas < MOLE_PENALTY_THRESHOLD) //Only has a net positive effect when the temp is below 313.15, heals up to 2 damage. Psycologists increase this temp min by up to 45 - damage = max(damage + (min(removed.temperature - (T0C + HEAT_PENALTY_THRESHOLD), 0) / 150 ), 0) + damage = max(damage + (min(removed.temperature - (T0C + heat_penalty_threshold), 0) / 150 ), 0) //Check for holes in the SM inner chamber for(var/t in RANGE_TURFS(1, loc)) @@ -538,15 +560,15 @@ //Also keep in mind we are only adding this temperature to (efficiency)% of the one tile the rock //is on. An increase of 4*C @ 25% efficiency here results in an increase of 1*C / (#tilesincore) overall. //Power * 0.55 * (some value between 1.5 and 23) / 5 - removed.temperature += ((device_energy * dynamic_heat_modifier) / THERMAL_RELEASE_MODIFIER) + removed.temperature += (((device_energy * dynamic_heat_modifier) / THERMAL_RELEASE_MODIFIER) * heat_multiplier) //We can only emit so much heat, that being 57500 removed.temperature = max(0, min(removed.temperature, 2500 * dynamic_heat_modifier)) //Calculate how much gas to release //Varies based on power and gas content - removed.toxins += max((device_energy * dynamic_heat_modifier) / PLASMA_RELEASE_MODIFIER, 0) + removed.toxins += max(((device_energy * dynamic_heat_modifier) / PLASMA_RELEASE_MODIFIER) * gas_multiplier, 0) //Varies based on power, gas content, and heat - removed.oxygen += max(((device_energy + removed.temperature * dynamic_heat_modifier) - T0C) / OXYGEN_RELEASE_MODIFIER, 0) + removed.oxygen += max((((device_energy + removed.temperature * dynamic_heat_modifier) - T0C) / OXYGEN_RELEASE_MODIFIER) * gas_multiplier, 0) if(produces_gas) env.merge(removed) @@ -649,7 +671,7 @@ //Boom (Mind blown) if(damage > explosion_point) countdown() - + power += power_additive return 1 /obj/machinery/atmospherics/supermatter_crystal/bullet_act(obj/item/projectile/Proj) @@ -1152,6 +1174,47 @@ power += amount message_admins("[src] has been activated and given an increase EER of [amount] at [ADMIN_JMP(src)]") +/obj/machinery/atmospherics/supermatter_crystal/proc/make_next_event_time() + // Some completely random bullshit to make a "bell curve" + var/fake_time = rand(5 MINUTES, 25 MINUTES) + if(fake_time < 15 MINUTES && prob(30)) + fake_time += rand(2 MINUTES, 10 MINUTES) + else if(fake_time > 15 MINUTES && prob(30)) + fake_time -= rand(2 MINUTES, 10 MINUTES) + next_event_time += fake_time + +/obj/machinery/atmospherics/supermatter_crystal/proc/try_events() + if(has_been_powered == FALSE) + return + if(!next_event_time) // for when the SM starts + make_next_event_time() + return + if(world.time < next_event_time) + return + if(event_active) + return + var/static/list/events = list(/datum/supermatter_event/delta_tier = 40, + /datum/supermatter_event/charlie_tier = 40, + /datum/supermatter_event/bravo_tier = 15, + /datum/supermatter_event/alpha_tier = 5, + /datum/supermatter_event/sierra_tier = 1) + + var/datum/supermatter_event/event = pick(subtypesof(pickweight(events))) + if(istype(event, /datum/supermatter_event/sierra_tier) && has_run_sclass) + make_next_event_time() + return // We're only gonna have one s-class per round, take a break engineers + run_event(event) + make_next_event_time() + +/obj/machinery/atmospherics/supermatter_crystal/proc/run_event(datum/supermatter_event/event) // mostly admin testing and stuff + if(ispath(event)) + event = new event(src) + if(!istype(event)) + log_debug("Attempted supermatter event aborted due to incorrect path. Incorrect path type: [event.type].") + return + event.start_event() + + #undef HALLUCINATION_RANGE #undef GRAVITATIONAL_ANOMALY #undef FLUX_ANOMALY diff --git a/code/modules/power/engines/supermatter/supermatter_event.dm b/code/modules/power/engines/supermatter/supermatter_event.dm new file mode 100644 index 000000000000..4c5f966bcae4 --- /dev/null +++ b/code/modules/power/engines/supermatter/supermatter_event.dm @@ -0,0 +1,209 @@ +/datum/supermatter_event + var/name = "Unknown X-K (Report this to coders)" + var/obj/machinery/atmospherics/supermatter_crystal/supermatter + var/datum/gas_mixture/environment + /// Probability of the event not running, higher tiers being rarer + var/threat_level + var/duration + +/datum/supermatter_event/New(obj/machinery/atmospherics/supermatter_crystal/_supermatter) + . = ..() + supermatter = _supermatter + if(!supermatter) + stack_trace("a /datum/supermatter_event was called without an involved supermatter.") + return + if(!istype(supermatter)) + stack_trace("a /datum/supermatter_event was called with (name: [supermatter], type: [supermatter.type]) instead of a supermatter!") + return + var/turf/T = get_turf(supermatter) + environment = T.return_air() + +/datum/supermatter_event/proc/start_event() + supermatter.event_active = src + on_start() + alert_engi() + if(duration) + addtimer(CALLBACK(src, PROC_REF(on_end)), duration) + +/datum/supermatter_event/proc/on_start() + return + +/datum/supermatter_event/proc/alert_engi() + return + +/datum/supermatter_event/proc/on_end() + sm_radio_say("Anomalous crystal activity has ended.") + supermatter.heat_penalty_threshold = HEAT_PENALTY_THRESHOLD + supermatter.gas_multiplier = 1 + supermatter.power_additive = 0 + supermatter.heat_multiplier = 1 + supermatter.event_active = null + supermatter.last_events += src + +/datum/supermatter_event/proc/sm_radio_say(text) + if(!text) + return + supermatter.radio.autosay(text, supermatter, "Engineering", list(supermatter.z)) + +/datum/supermatter_event/proc/general_radio_say(text) + if(!text) + return + supermatter.radio.autosay(text, supermatter, null, list(supermatter.z)) + +// Below this are procs used for the SM events, in order of severity + +//D class events + +/datum/supermatter_event/delta_tier + threat_level = SM_EVENT_THREAT_D + duration = 10 SECONDS + +/datum/supermatter_event/delta_tier/alert_engi() + sm_radio_say("Abnormal crystal activity detected! Activity class: [name].") + +// sleeping gas +/datum/supermatter_event/delta_tier/sleeping_gas + name = "D-1" + +/datum/supermatter_event/delta_tier/sleeping_gas/on_start() + environment.sleeping_agent += 200 + +// nitrogen +/datum/supermatter_event/delta_tier/nitrogen + name = "D-2" + +/datum/supermatter_event/delta_tier/nitrogen/on_start() + environment.nitrogen += 200 + +// carbon dioxide +/datum/supermatter_event/delta_tier/carbon_dioxide + name = "D-3" + +/datum/supermatter_event/delta_tier/carbon_dioxide/on_start() + environment.carbon_dioxide += 250 + + +// C class events + +/datum/supermatter_event/charlie_tier + threat_level = SM_EVENT_THREAT_C + duration = 15 SECONDS + +/datum/supermatter_event/charlie_tier/alert_engi() + sm_radio_say("Anomalous crystal activity detected. Activity class: [name]. Operator intervention may be required.") + +// oxygen +/datum/supermatter_event/charlie_tier/oxygen + name = "C-1" + +/datum/supermatter_event/charlie_tier/oxygen/on_start() + environment.oxygen += 250 + +// plasma +/datum/supermatter_event/charlie_tier/plasma + name = "C-2" + +/datum/supermatter_event/charlie_tier/plasma/on_start() + environment.toxins += 200 + +// lowers the temp required for the SM to take damage. +/datum/supermatter_event/charlie_tier/heat_penalty_threshold + name = "C-3" + duration = 5 MINUTES + +/datum/supermatter_event/charlie_tier/heat_penalty_threshold/on_start() + supermatter.heat_penalty_threshold -= -73 + +//Class B events +/datum/supermatter_event/bravo_tier + threat_level = SM_EVENT_THREAT_B + duration = 1 MINUTES + +/datum/supermatter_event/bravo_tier/alert_engi() + sm_radio_say("Anomalous crystal activity detected! Activity class: [name]. Operator intervention is required!") + + +// more gas +/datum/supermatter_event/bravo_tier/gas_multiply + name = "B-1" + +/datum/supermatter_event/bravo_tier/gas_multiply/on_start() + supermatter.gas_multiplier = 1.5 + + +/datum/supermatter_event/bravo_tier/heat_multiplier + name = "B-2" + +/datum/supermatter_event/bravo_tier/heat_multiplier/on_start() + supermatter.heat_multiplier = 1.25 + +/datum/supermatter_event/bravo_tier/power_additive + name = "B-3" + +/datum/supermatter_event/bravo_tier/power_additive/on_start() + supermatter.power_additive = 2000 + +//A class events +/datum/supermatter_event/alpha_tier + threat_level = SM_EVENT_THREAT_A + duration = 10 SECONDS + +/datum/supermatter_event/alpha_tier/alert_engi() + sm_radio_say("ALERT: Critical anomalous crystal activity detected! Activity class: [name]. IMMEDIATE Operator intervention is REQUIRED!") + +/datum/supermatter_event/alpha_tier/apc_short + name = "A-1" + +/datum/supermatter_event/alpha_tier/apc_short/on_start() + var/area/current_area = get_area(src) + var/obj/machinery/power/apc/A = current_area.get_apc() + A.apc_short() + +/datum/supermatter_event/alpha_tier/air_siphon + name = "A-2" + +/datum/supermatter_event/alpha_tier/air_siphon/on_start() + var/area/current_area = get_area(src) + var/obj/machinery/alarm/engine/A = current_area.master_air_alarm + A.apply_mode(AALARM_MODE_SCRUBBING) + +/datum/supermatter_event/alpha_tier/gas_multiplier + name = "A-3" + duration = 2 MINUTES + +/datum/supermatter_event/alpha_tier/gas_multiplier/on_start() + supermatter.gas_multiplier = 4 + +// S-tier events are special. They are very dangerous, but give a 5 minute warning to the engis. +/datum/supermatter_event/sierra_tier + threat_level = SM_EVENT_THREAT_S + duration = 7 MINUTES // 2 MINUTES of s-tier anomaly + +/datum/supermatter_event/sierra_tier/alert_engi() + general_radio_say("ALERT: Anomalous supermatter state expected in: 5 minutes.") + sm_radio_say("EMERGENCY ALERT: 5 MINUTES UNTIL [supermatter] EXHIBITS [name] CLASS ANOMALOUS ACTIVITY!") + +/datum/supermatter_event/sierra_tier/on_start() + addtimer(CALLBACK(src, PROC_REF(start_sierra_event)), 5 MINUTES) + supermatter.has_run_sclass = TRUE + +/datum/supermatter_event/sierra_tier/proc/start_sierra_event() + general_radio_say("ALERT: ANOMALOUS SUPERMATTER STATE DETECTED!") + sm_radio_say("EMERGENCY ALERT: Class [name] anomalous behavior in progress!") + +//S class events +//Arc-type +/datum/supermatter_event/sierra_tier/arc + name = "S-ARC" + +/datum/supermatter_event/sierra_tier/arc/start_sierra_event() + ..() + supermatter.power_additive = 6000 + +// Laminate type +/datum/supermatter_event/sierra_tier/laminate + name = "S-LAMINATE REJECTION" + +/datum/supermatter_event/sierra_tier/laminate/start_sierra_event() + ..() + supermatter.heat_multiplier = 10 diff --git a/paradise.dme b/paradise.dme index bf213e821de2..6a3213e0e73b 100644 --- a/paradise.dme +++ b/paradise.dme @@ -99,6 +99,7 @@ #include "code\__DEFINES\station_goals.dm" #include "code\__DEFINES\status_effects.dm" #include "code\__DEFINES\subsystems.dm" +#include "code\__DEFINES\supermatter_defines.dm" #include "code\__DEFINES\surgery_defines.dm" #include "code\__DEFINES\text_defines.dm" #include "code\__DEFINES\tg_cooldowns.dm" @@ -2373,6 +2374,7 @@ #include "code\modules\power\engines\singularity\particle_accelerator\particle_emitter.dm" #include "code\modules\power\engines\singularity\particle_accelerator\particle_power.dm" #include "code\modules\power\engines\supermatter\supermatter.dm" +#include "code\modules\power\engines\supermatter\supermatter_event.dm" #include "code\modules\power\engines\tesla\coil.dm" #include "code\modules\power\engines\tesla\energy_ball.dm" #include "code\modules\power\engines\tesla\generator.dm"