9f6511c8b6
All I'm doing here is raising the power_penalty_thresholds to a higher number so that it takes more time and effort to force the mega delamination. Also by leaving a wider gap between Severe and Critical stages, it gives more warning to AI and Engineers that Tesla delamination is happening soon. As some of us know by now, it's /very/ easy to force Tesla delams and that uhh... it's aids to deal with due to all the effects happening so quickly as it powers through all the stages from just 3 simple switches. It takes effort and time for Singulo delam to start happening due to the high amount of moles needed on. that. tile. Does not take much for Tesla. Fixing that now.
823 lines
33 KiB
Plaintext
823 lines
33 KiB
Plaintext
//Ported from /vg/station13, which was in turn forked from baystation12;
|
|
//Please do not bother them with bugs from this port, however, as it has been modified quite a bit.
|
|
//Modifications include removing the world-ending full supermatter variation, and leaving only the shard.
|
|
|
|
#define PLASMA_HEAT_PENALTY 15 // Higher == Bigger heat and waste penalty from having the crystal surrounded by this gas. Negative numbers reduce penalty.
|
|
#define OXYGEN_HEAT_PENALTY 1
|
|
#define CO2_HEAT_PENALTY 0.1
|
|
#define PLUOXIUM_HEAT_PENALTY -1
|
|
#define TRITIUM_HEAT_PENALTY 10
|
|
#define NITROGEN_HEAT_PENALTY -1.5
|
|
#define BZ_HEAT_PENALTY 5
|
|
|
|
#define OXYGEN_TRANSMIT_MODIFIER 1.5 //Higher == Bigger bonus to power generation.
|
|
#define PLASMA_TRANSMIT_MODIFIER 4
|
|
#define BZ_TRANSMIT_MODIFIER -2
|
|
|
|
#define TRITIUM_RADIOACTIVITY_MODIFIER 3 //Higher == Crystal spews out more radiation
|
|
#define BZ_RADIOACTIVITY_MODIFIER 5
|
|
#define PLUOXIUM_RADIOACTIVITY_MODIFIER -2
|
|
|
|
#define N2O_HEAT_RESISTANCE 6 //Higher == Gas makes the crystal more resistant against heat damage.
|
|
#define PLUOXIUM_HEAT_RESISTANCE 3
|
|
|
|
#define POWERLOSS_INHIBITION_GAS_THRESHOLD 0.20 //Higher == Higher percentage of inhibitor gas needed before the charge inertia chain reaction effect starts.
|
|
#define POWERLOSS_INHIBITION_MOLE_THRESHOLD 20 //Higher == More moles of the gas are needed before the charge inertia chain reaction effect starts. //Scales powerloss inhibition down until this amount of moles is reached
|
|
#define POWERLOSS_INHIBITION_MOLE_BOOST_THRESHOLD 500 //bonus powerloss inhibition boost if this amount of moles is reached
|
|
|
|
#define MOLE_PENALTY_THRESHOLD 1800 //Higher == Shard can absorb more moles before triggering the high mole penalties.
|
|
#define MOLE_HEAT_PENALTY 350 //Heat damage scales around this. Too hot setups with this amount of moles do regular damage, anything above and below is scaled
|
|
#define POWER_PENALTY_THRESHOLD 5000 //Higher == Engine can generate more power before triggering the high power penalties.
|
|
#define SEVERE_POWER_PENALTY_THRESHOLD 7000 //Same as above, but causes more dangerous effects
|
|
#define CRITICAL_POWER_PENALTY_THRESHOLD 12000 //Even more dangerous effects, threshold for tesla delamination
|
|
#define HEAT_PENALTY_THRESHOLD 40 //Higher == Crystal safe operational temperature is higher.
|
|
#define DAMAGE_HARDCAP 0.002
|
|
#define DAMAGE_INCREASE_MULTIPLIER 0.25
|
|
|
|
|
|
#define THERMAL_RELEASE_MODIFIER 5 //Higher == less heat released during reaction, not to be confused with the above values
|
|
#define PLASMA_RELEASE_MODIFIER 750 //Higher == less plasma released by reaction
|
|
#define OXYGEN_RELEASE_MODIFIER 325 //Higher == less oxygen released at high temperature/power
|
|
|
|
#define REACTION_POWER_MODIFIER 0.55 //Higher == more overall power
|
|
|
|
#define MATTER_POWER_CONVERSION 10 //Crystal converts 1/this value of stored matter into energy.
|
|
|
|
//These would be what you would get at point blank, decreases with distance
|
|
#define DETONATION_RADS 200
|
|
#define DETONATION_HALLUCINATION 600
|
|
|
|
|
|
#define WARNING_DELAY 60
|
|
|
|
#define HALLUCINATION_RANGE(P) (min(7, round(P ** 0.25)))
|
|
|
|
|
|
#define GRAVITATIONAL_ANOMALY "gravitational_anomaly"
|
|
#define FLUX_ANOMALY "flux_anomaly"
|
|
#define PYRO_ANOMALY "pyro_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
|
|
|
|
GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
|
|
|
/obj/machinery/power/supermatter_crystal
|
|
name = "supermatter crystal"
|
|
desc = "A strangely translucent and iridescent crystal."
|
|
icon = 'icons/obj/supermatter.dmi'
|
|
icon_state = "darkmatter"
|
|
density = TRUE
|
|
anchored = TRUE
|
|
var/uid = 1
|
|
var/static/gl_uid = 1
|
|
light_range = 4
|
|
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
|
|
|
|
critical_machine = TRUE
|
|
|
|
var/gasefficency = 0.15
|
|
|
|
var/base_icon_state = "darkmatter"
|
|
|
|
var/final_countdown = FALSE
|
|
|
|
var/damage = 0
|
|
var/damage_archived = 0
|
|
var/safe_alert = "Crystalline hyperstructure returning to safe operating parameters."
|
|
var/warning_point = 50
|
|
var/warning_alert = "Danger! Crystal hyperstructure integrity faltering!"
|
|
var/damage_penalty_point = 550
|
|
var/emergency_point = 700
|
|
var/emergency_alert = "CRYSTAL DELAMINATION IMMINENT."
|
|
var/explosion_point = 900
|
|
|
|
var/emergency_issued = FALSE
|
|
|
|
var/explosion_power = 35
|
|
var/temp_factor = 30
|
|
|
|
var/lastwarning = 0 // Time in 1/10th of seconds since the last sent warning
|
|
var/power = 0
|
|
|
|
var/n2comp = 0 // raw composition of each gas in the chamber, ranges from 0 to 1
|
|
|
|
var/plasmacomp = 0
|
|
var/o2comp = 0
|
|
var/co2comp = 0
|
|
var/n2ocomp = 0
|
|
var/pluoxiumcomp = 0
|
|
var/tritiumcomp = 0
|
|
var/bzcomp = 0
|
|
|
|
var/pluoxiumbonus = 0
|
|
|
|
var/combined_gas = 0
|
|
var/gasmix_power_ratio = 0
|
|
var/dynamic_heat_modifier = 1
|
|
var/dynamic_heat_resistance = 1
|
|
var/powerloss_inhibitor = 1
|
|
var/powerloss_dynamic_scaling= 0
|
|
var/power_transmission_bonus = 0
|
|
var/mole_heat_penalty = 0
|
|
|
|
|
|
var/matter_power = 0
|
|
|
|
//Temporary values so that we can optimize this
|
|
//How much the bullets damage should be multiplied by when it is added to the internal variables
|
|
var/config_bullet_energy = 2
|
|
//How much of the power is left after processing is finished?
|
|
// var/config_power_reduction_per_tick = 0.5
|
|
//How much hallucination should it produce per unit of power?
|
|
var/config_hallucination_power = 0.1
|
|
|
|
var/obj/item/radio/radio
|
|
var/radio_key = /obj/item/encryptionkey/headset_eng
|
|
var/engineering_channel = "Engineering"
|
|
var/common_channel = null
|
|
|
|
//for logging
|
|
var/has_been_powered = FALSE
|
|
var/has_reached_emergency = FALSE
|
|
|
|
// For making hugbox supermatter
|
|
var/takes_damage = TRUE
|
|
var/produces_gas = TRUE
|
|
var/obj/effect/countdown/supermatter/countdown
|
|
|
|
var/is_main_engine = FALSE
|
|
|
|
var/datum/looping_sound/supermatter/soundloop
|
|
|
|
var/moveable = FALSE
|
|
|
|
/obj/machinery/power/supermatter_crystal/Initialize()
|
|
. = ..()
|
|
uid = gl_uid++
|
|
SSair.atmos_machinery += src
|
|
countdown = new(src)
|
|
countdown.start()
|
|
GLOB.poi_list |= src
|
|
radio = new(src)
|
|
radio.keyslot = new radio_key
|
|
radio.listening = 0
|
|
radio.recalculateChannels()
|
|
investigate_log("has been created.", INVESTIGATE_SUPERMATTER)
|
|
if(is_main_engine)
|
|
GLOB.main_supermatter_engine = src
|
|
|
|
soundloop = new(list(src), TRUE)
|
|
|
|
/obj/machinery/power/supermatter_crystal/Destroy()
|
|
investigate_log("has been destroyed.", INVESTIGATE_SUPERMATTER)
|
|
SSair.atmos_machinery -= src
|
|
QDEL_NULL(radio)
|
|
GLOB.poi_list -= src
|
|
QDEL_NULL(countdown)
|
|
if(is_main_engine && GLOB.main_supermatter_engine == src)
|
|
GLOB.main_supermatter_engine = null
|
|
QDEL_NULL(soundloop)
|
|
return ..()
|
|
|
|
/obj/machinery/power/supermatter_crystal/examine(mob/user)
|
|
..()
|
|
if(!ishuman(user))
|
|
return
|
|
|
|
var/range = HALLUCINATION_RANGE(power)
|
|
for(var/mob/living/carbon/human/H in viewers(range, src))
|
|
if(H != user)
|
|
continue
|
|
if(!istype(H.glasses, /obj/item/clothing/glasses/meson))
|
|
to_chat(H, "<span class='danger'>You get headaches just from looking at it.</span>")
|
|
return
|
|
|
|
/obj/machinery/power/supermatter_crystal/proc/get_status()
|
|
var/turf/T = get_turf(src)
|
|
if(!T)
|
|
return SUPERMATTER_ERROR
|
|
var/datum/gas_mixture/air = T.return_air()
|
|
if(!air)
|
|
return SUPERMATTER_ERROR
|
|
|
|
if(get_integrity() < SUPERMATTER_DELAM_PERCENT)
|
|
return SUPERMATTER_DELAMINATING
|
|
|
|
if(get_integrity() < SUPERMATTER_EMERGENCY_PERCENT)
|
|
return SUPERMATTER_EMERGENCY
|
|
|
|
if(get_integrity() < SUPERMATTER_DANGER_PERCENT)
|
|
return SUPERMATTER_DANGER
|
|
|
|
if((get_integrity() < SUPERMATTER_WARNING_PERCENT) || (air.temperature > CRITICAL_TEMPERATURE))
|
|
return SUPERMATTER_WARNING
|
|
|
|
if(air.temperature > (CRITICAL_TEMPERATURE * 0.8))
|
|
return SUPERMATTER_NOTIFY
|
|
|
|
if(power > 5)
|
|
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)
|
|
if(SUPERMATTER_EMERGENCY)
|
|
playsound(src, 'sound/machines/engine_alert1.ogg', 100)
|
|
if(SUPERMATTER_DANGER)
|
|
playsound(src, 'sound/machines/engine_alert2.ogg', 100)
|
|
if(SUPERMATTER_WARNING)
|
|
playsound(src, 'sound/machines/terminal_alert.ogg', 75)
|
|
|
|
/obj/machinery/power/supermatter_crystal/proc/get_integrity()
|
|
var/integrity = damage / explosion_point
|
|
integrity = round(100 - integrity * 100, 0.01)
|
|
integrity = integrity < 0 ? 0 : integrity
|
|
return integrity
|
|
|
|
/obj/machinery/power/supermatter_crystal/proc/countdown()
|
|
set waitfor = FALSE
|
|
|
|
if(final_countdown) // We're already doing it go away
|
|
return
|
|
final_countdown = TRUE
|
|
|
|
var/image/causality_field = image(icon, null, "causality_field")
|
|
add_overlay(causality_field, TRUE)
|
|
|
|
var/speaking = "[emergency_alert] The supermatter has reached critical integrity failure. Emergency causality destabilization field has been activated."
|
|
radio.talk_into(src, speaking, common_channel, language = get_default_language())
|
|
for(var/i in SUPERMATTER_COUNTDOWN_TIME to 0 step -10)
|
|
if(damage < explosion_point) // Cutting it a bit close there engineers
|
|
radio.talk_into(src, "[safe_alert] Failsafe has been disengaged.", common_channel)
|
|
cut_overlay(causality_field, TRUE)
|
|
final_countdown = FALSE
|
|
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)
|
|
speaking = "[DisplayTimeText(i, TRUE)] remain before causality stabilization."
|
|
else
|
|
speaking = "[i*0.1]..."
|
|
radio.talk_into(src, speaking, common_channel)
|
|
sleep(10)
|
|
|
|
explode()
|
|
|
|
/obj/machinery/power/supermatter_crystal/proc/explode()
|
|
for(var/mob in GLOB.alive_mob_list)
|
|
var/mob/living/L = mob
|
|
if(istype(L) && L.z == z)
|
|
if(ishuman(mob))
|
|
//Hilariously enough, running into a closet should make you get hit the hardest.
|
|
var/mob/living/carbon/human/H = mob
|
|
H.hallucination += max(50, min(300, DETONATION_HALLUCINATION * sqrt(1 / (get_dist(mob, src) + 1)) ) )
|
|
var/rads = DETONATION_RADS * sqrt( 1 / (get_dist(L, src) + 1) )
|
|
L.rad_act(rads)
|
|
|
|
var/turf/T = get_turf(src)
|
|
for(var/mob/M in GLOB.player_list)
|
|
if(M.z == z)
|
|
SEND_SOUND(M, 'sound/magic/charge.ogg')
|
|
to_chat(M, "<span class='boldannounce'>You feel reality distort for a moment...</span>")
|
|
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "delam", /datum/mood_event/delam)
|
|
if(combined_gas > MOLE_PENALTY_THRESHOLD)
|
|
investigate_log("has collapsed into a singularity.", INVESTIGATE_SUPERMATTER)
|
|
if(T)
|
|
var/obj/singularity/S = new(T)
|
|
S.energy = 800
|
|
S.consume(src)
|
|
else
|
|
investigate_log("has exploded.", INVESTIGATE_SUPERMATTER)
|
|
explosion(get_turf(T), explosion_power * max(gasmix_power_ratio, 0.205) * 0.5 , explosion_power * max(gasmix_power_ratio, 0.205) + 2, explosion_power * max(gasmix_power_ratio, 0.205) + 4 , explosion_power * max(gasmix_power_ratio, 0.205) + 6, 1, 1)
|
|
if(power > POWER_PENALTY_THRESHOLD)
|
|
investigate_log("has spawned additional energy balls.", INVESTIGATE_SUPERMATTER)
|
|
var/obj/singularity/energy_ball/E = new(T)
|
|
E.energy = power
|
|
qdel(src)
|
|
|
|
/obj/machinery/power/supermatter_crystal/proc/consume_turf(turf/T)
|
|
var/oldtype = T.type
|
|
var/turf/newT = T.ScrapeAway()
|
|
if(newT.type == oldtype)
|
|
return
|
|
playsound(T, 'sound/effects/supermatter.ogg', 50, 1)
|
|
T.visible_message("<span class='danger'>[T] smacks into [src] and rapidly flashes to ash.</span>",\
|
|
"<span class='italics'>You hear a loud crack as you are washed with a wave of heat.</span>")
|
|
T.CalculateAdjacentTurfs()
|
|
|
|
/obj/machinery/power/supermatter_crystal/process_atmos()
|
|
var/turf/T = loc
|
|
|
|
if(isnull(T)) // We have a null turf...something is wrong, stop processing this entity.
|
|
return PROCESS_KILL
|
|
|
|
if(!istype(T)) //We are in a crate or somewhere that isn't turf, if we return to turf resume processing but for now.
|
|
return //Yeah just stop.
|
|
if(istype(T, /turf/closed))
|
|
consume_turf(T)
|
|
|
|
if(power)
|
|
soundloop.volume = min(40, (round(power/100)/50)+1) // 5 +1 volume per 20 power. 2500 power is max
|
|
|
|
if(isclosedturf(T))
|
|
var/turf/did_it_melt = T.Melt()
|
|
if(!isclosedturf(did_it_melt)) //In case some joker finds way to place these on indestructible walls
|
|
visible_message("<span class='warning'>[src] melts through [T]!</span>")
|
|
return
|
|
|
|
//Ok, get the air from the turf
|
|
var/datum/gas_mixture/env = T.return_air()
|
|
|
|
var/datum/gas_mixture/removed
|
|
|
|
if(produces_gas)
|
|
//Remove gas from surrounding area
|
|
removed = env.remove(gasefficency * env.total_moles())
|
|
else
|
|
// Pass all the gas related code an empty gas container
|
|
removed = new()
|
|
|
|
damage_archived = damage
|
|
if(!removed || !removed.total_moles() || isspaceturf(T)) //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
|
|
else
|
|
if(takes_damage)
|
|
//causing damage
|
|
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(power - POWER_PENALTY_THRESHOLD, 0)/500) * DAMAGE_INCREASE_MULTIPLIER, 0)
|
|
damage = max(damage + (max(combined_gas - MOLE_PENALTY_THRESHOLD, 0)/80) * DAMAGE_INCREASE_MULTIPLIER, 0)
|
|
|
|
//healing damage
|
|
if(combined_gas < MOLE_PENALTY_THRESHOLD)
|
|
damage = max(damage + (min(removed.temperature - (T0C + HEAT_PENALTY_THRESHOLD), 0) / 150 ), 0)
|
|
|
|
//capping damage
|
|
damage = min(damage_archived + (DAMAGE_HARDCAP * explosion_point),damage)
|
|
if(damage > damage_archived && prob(10))
|
|
playsound(get_turf(src), 'sound/effects/empulse.ogg', 50, 1)
|
|
|
|
//calculating gas related values
|
|
combined_gas = max(removed.total_moles(), 0)
|
|
|
|
plasmacomp = max(removed.gases[/datum/gas/plasma]/combined_gas, 0)
|
|
o2comp = max(removed.gases[/datum/gas/oxygen]/combined_gas, 0)
|
|
co2comp = max(removed.gases[/datum/gas/carbon_dioxide]/combined_gas, 0)
|
|
pluoxiumcomp = max(removed.gases[/datum/gas/pluoxium]/combined_gas, 0)
|
|
tritiumcomp = max(removed.gases[/datum/gas/tritium]/combined_gas, 0)
|
|
bzcomp = max(removed.gases[/datum/gas/bz]/combined_gas, 0)
|
|
|
|
n2ocomp = max(removed.gases[/datum/gas/nitrous_oxide]/combined_gas, 0)
|
|
n2comp = max(removed.gases[/datum/gas/nitrogen]/combined_gas, 0)
|
|
|
|
if(pluoxiumcomp >= 0.15)
|
|
pluoxiumbonus = 1 //makes pluoxium only work at 15%+
|
|
else
|
|
pluoxiumbonus = 0
|
|
|
|
gasmix_power_ratio = min(max(plasmacomp + o2comp + co2comp + tritiumcomp + bzcomp - pluoxiumcomp - n2comp, 0), 1)
|
|
|
|
dynamic_heat_modifier = max((plasmacomp * PLASMA_HEAT_PENALTY) + (o2comp * OXYGEN_HEAT_PENALTY) + (co2comp * CO2_HEAT_PENALTY) + (tritiumcomp * TRITIUM_HEAT_PENALTY) + ((pluoxiumcomp * PLUOXIUM_HEAT_PENALTY) * pluoxiumbonus) + (n2comp * NITROGEN_HEAT_PENALTY) + (bzcomp * BZ_HEAT_PENALTY), 0.5)
|
|
dynamic_heat_resistance = max((n2ocomp * N2O_HEAT_RESISTANCE) + ((pluoxiumcomp * PLUOXIUM_HEAT_RESISTANCE) * pluoxiumbonus), 1)
|
|
|
|
power_transmission_bonus = max((plasmacomp * PLASMA_TRANSMIT_MODIFIER) + (o2comp * OXYGEN_TRANSMIT_MODIFIER) + (bzcomp * BZ_TRANSMIT_MODIFIER), 0)
|
|
|
|
//more moles of gases are harder to heat than fewer, so let's scale heat damage around them
|
|
mole_heat_penalty = max(combined_gas / MOLE_HEAT_PENALTY, 0.25)
|
|
|
|
if (combined_gas > POWERLOSS_INHIBITION_MOLE_THRESHOLD && co2comp > POWERLOSS_INHIBITION_GAS_THRESHOLD)
|
|
powerloss_dynamic_scaling = CLAMP(powerloss_dynamic_scaling + CLAMP(co2comp - powerloss_dynamic_scaling, -0.02, 0.02), 0, 1)
|
|
else
|
|
powerloss_dynamic_scaling = CLAMP(powerloss_dynamic_scaling - 0.05,0, 1)
|
|
powerloss_inhibitor = CLAMP(1-(powerloss_dynamic_scaling * CLAMP(combined_gas/POWERLOSS_INHIBITION_MOLE_BOOST_THRESHOLD,1 ,1.5)),0 ,1)
|
|
|
|
if(matter_power)
|
|
var/removed_matter = max(matter_power/MATTER_POWER_CONVERSION, 40)
|
|
power = max(power + removed_matter, 0)
|
|
matter_power = max(matter_power - removed_matter, 0)
|
|
|
|
var/temp_factor = 50
|
|
|
|
if(gasmix_power_ratio > 0.8)
|
|
// with a perfect gas mix, make the power less based on heat
|
|
icon_state = "[base_icon_state]_glow"
|
|
else
|
|
// in normal mode, base the produced energy around the heat
|
|
temp_factor = 30
|
|
icon_state = base_icon_state
|
|
|
|
power = max( (removed.temperature * temp_factor / T0C) * gasmix_power_ratio + power, 0) //Total laser power plus an overload
|
|
|
|
if(prob(50))
|
|
radiation_pulse(src, power * (1 + (tritiumcomp * TRITIUM_RADIOACTIVITY_MODIFIER) + ((pluoxiumcomp * PLUOXIUM_RADIOACTIVITY_MODIFIER) * pluoxiumbonus) * (power_transmission_bonus/(10-(bzcomp * BZ_RADIOACTIVITY_MODIFIER))))) // Rad Modifiers BZ(500%), Tritium(300%), and Pluoxium(-200%)
|
|
if(bzcomp >= 0.4 && prob(30 * bzcomp))
|
|
fire_nuclear_particle() // Start to emit radballs at a maximum of 30% chance per tick
|
|
|
|
var/device_energy = power * REACTION_POWER_MODIFIER
|
|
|
|
//To figure out how much temperature to add each tick, consider that at one atmosphere's worth
|
|
//of pure oxygen, with all four lasers firing at standard energy and no N2 present, at room temperature
|
|
//that the device energy is around 2140. At that stage, we don't want too much heat to be put out
|
|
//Since the core is effectively "cold"
|
|
|
|
//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.
|
|
removed.temperature += ((device_energy * dynamic_heat_modifier) / THERMAL_RELEASE_MODIFIER)
|
|
|
|
removed.temperature = max(0, min(removed.temperature, 2500 * dynamic_heat_modifier))
|
|
|
|
//Calculate how much gas to release
|
|
removed.gases[/datum/gas/plasma] += max((device_energy * dynamic_heat_modifier) / PLASMA_RELEASE_MODIFIER, 0)
|
|
|
|
removed.gases[/datum/gas/oxygen] += max(((device_energy + removed.temperature * dynamic_heat_modifier) - T0C) / OXYGEN_RELEASE_MODIFIER, 0)
|
|
|
|
if(produces_gas)
|
|
env.merge(removed)
|
|
air_update_turf()
|
|
|
|
for(var/mob/living/carbon/human/l in view(src, HALLUCINATION_RANGE(power))) // If they can see it without mesons on. Bad on them.
|
|
if(!istype(l.glasses, /obj/item/clothing/glasses/meson))
|
|
var/D = sqrt(1 / max(1, get_dist(l, src)))
|
|
l.hallucination += power * config_hallucination_power * D
|
|
l.hallucination = CLAMP(0, 200, l.hallucination)
|
|
|
|
for(var/mob/living/l in range(src, round((power / 100) ** 0.25)))
|
|
var/rads = (power / 10) * sqrt( 1 / max(get_dist(l, src),1) )
|
|
l.rad_act(rads)
|
|
|
|
power -= ((power/500)**3) * powerloss_inhibitor
|
|
|
|
if(power > POWER_PENALTY_THRESHOLD || damage > damage_penalty_point)
|
|
|
|
if(power > POWER_PENALTY_THRESHOLD)
|
|
playsound(src.loc, 'sound/weapons/emitter2.ogg', 100, 1, extrarange = 10)
|
|
supermatter_zap(src, 5, min(power*2, 20000))
|
|
supermatter_zap(src, 5, min(power*2, 20000))
|
|
if(power > SEVERE_POWER_PENALTY_THRESHOLD)
|
|
supermatter_zap(src, 5, min(power*2, 20000))
|
|
if(power > CRITICAL_POWER_PENALTY_THRESHOLD)
|
|
supermatter_zap(src, 5, min(power*2, 20000))
|
|
else if (damage > damage_penalty_point && prob(20))
|
|
playsound(src.loc, 'sound/weapons/emitter2.ogg', 100, 1, extrarange = 10)
|
|
supermatter_zap(src, 5, CLAMP(power*2, 4000, 20000))
|
|
|
|
if(prob(15) && power > POWER_PENALTY_THRESHOLD)
|
|
supermatter_pull(src, power/750)
|
|
if(prob(5))
|
|
supermatter_anomaly_gen(src, FLUX_ANOMALY, rand(5, 10))
|
|
if(power > SEVERE_POWER_PENALTY_THRESHOLD && prob(5) || prob(1))
|
|
supermatter_anomaly_gen(src, GRAVITATIONAL_ANOMALY, rand(5, 10))
|
|
if(power > SEVERE_POWER_PENALTY_THRESHOLD && prob(2) || prob(0.3) && power > POWER_PENALTY_THRESHOLD)
|
|
supermatter_anomaly_gen(src, PYRO_ANOMALY, rand(5, 10))
|
|
|
|
if(damage > warning_point) // while the core is still damaged and it's still worth noting its status
|
|
if((REALTIMEOFDAY - lastwarning) / 10 >= WARNING_DELAY)
|
|
alarm()
|
|
|
|
if(damage > emergency_point)
|
|
radio.talk_into(src, "[emergency_alert] Integrity: [get_integrity()]%", common_channel)
|
|
lastwarning = REALTIMEOFDAY
|
|
if(!has_reached_emergency)
|
|
investigate_log("has reached the emergency point for the first time.", INVESTIGATE_SUPERMATTER)
|
|
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()]%", engineering_channel)
|
|
lastwarning = REALTIMEOFDAY - (WARNING_DELAY * 5)
|
|
|
|
else // Phew, we're safe
|
|
radio.talk_into(src, "[safe_alert] Integrity: [get_integrity()]%", 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(damage > explosion_point)
|
|
countdown()
|
|
|
|
return 1
|
|
|
|
/obj/machinery/power/supermatter_crystal/bullet_act(obj/item/projectile/Proj)
|
|
var/turf/L = loc
|
|
if(!istype(L))
|
|
return FALSE
|
|
if(!istype(Proj.firer, /obj/machinery/power/emitter))
|
|
investigate_log("has been hit by [Proj] fired by [key_name(Proj.firer)]", INVESTIGATE_SUPERMATTER)
|
|
if(Proj.flag != "bullet")
|
|
power += Proj.damage * config_bullet_energy
|
|
if(!has_been_powered)
|
|
investigate_log("has been powered for the first time.", INVESTIGATE_SUPERMATTER)
|
|
message_admins("[src] has been powered for the first time [ADMIN_JMP(src)].")
|
|
has_been_powered = TRUE
|
|
else if(takes_damage)
|
|
damage += Proj.damage * config_bullet_energy
|
|
return FALSE
|
|
|
|
/obj/machinery/power/supermatter_crystal/singularity_act()
|
|
var/gain = 100
|
|
investigate_log("Supermatter shard consumed by singularity.", INVESTIGATE_SINGULO)
|
|
message_admins("Singularity has consumed a supermatter shard and can now become stage six.")
|
|
visible_message("<span class='userdanger'>[src] is consumed by the singularity!</span>")
|
|
for(var/mob/M in GLOB.player_list)
|
|
if(M.z == z)
|
|
SEND_SOUND(M, 'sound/effects/supermatter.ogg') //everyone goan know bout this
|
|
to_chat(M, "<span class='boldannounce'>A horrible screeching fills your ears, and a wave of dread washes over you...</span>")
|
|
qdel(src)
|
|
return gain
|
|
|
|
/obj/machinery/power/supermatter_crystal/blob_act(obj/structure/blob/B)
|
|
if(B && !isspaceturf(loc)) //does nothing in space
|
|
playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
|
|
damage += B.obj_integrity * 0.5 //take damage equal to 50% of remaining blob health before it tried to eat us
|
|
if(B.obj_integrity > 100)
|
|
B.visible_message("<span class='danger'>\The [B] strikes at \the [src] and flinches away!</span>",\
|
|
"<span class='italics'>You hear a loud crack as you are washed with a wave of heat.</span>")
|
|
B.take_damage(100, BURN)
|
|
else
|
|
B.visible_message("<span class='danger'>\The [B] strikes at \the [src] and rapidly flashes to ash.</span>",\
|
|
"<span class='italics'>You hear a loud crack as you are washed with a wave of heat.</span>")
|
|
Consume(B)
|
|
|
|
/obj/machinery/power/supermatter_crystal/attack_tk(mob/user)
|
|
if(iscarbon(user))
|
|
var/mob/living/carbon/C = user
|
|
log_game("[key_name(C)] has been disintegrated by a telekenetic grab on a supermatter crystal.</span>")
|
|
to_chat(C, "<span class='userdanger'>That was a really dense idea.</span>")
|
|
C.visible_message("<span class='userdanger'>A bright flare of radiation is seen from [C]'s head, shortly before you hear a sickening sizzling!</span>")
|
|
var/obj/item/organ/brain/rip_u = locate(/obj/item/organ/brain) in C.internal_organs
|
|
rip_u.Remove(C)
|
|
qdel(rip_u)
|
|
return
|
|
return ..()
|
|
|
|
/obj/machinery/power/supermatter_crystal/attack_paw(mob/user)
|
|
dust_mob(user, cause = "monkey attack")
|
|
|
|
/obj/machinery/power/supermatter_crystal/attack_alien(mob/user)
|
|
dust_mob(user, cause = "alien attack")
|
|
|
|
/obj/machinery/power/supermatter_crystal/attack_animal(mob/living/simple_animal/S)
|
|
var/murder
|
|
if(!S.melee_damage_upper && !S.melee_damage_lower)
|
|
murder = S.friendly
|
|
else
|
|
murder = S.attacktext
|
|
dust_mob(S, \
|
|
"<span class='danger'>[S] unwisely [murder] [src], and [S.p_their()] body burns brilliantly before flashing into ash!</span>", \
|
|
"<span class='userdanger'>You unwisely touch [src], and your vision glows brightly as your body crumbles to dust. Oops.</span>", \
|
|
"simple animal attack")
|
|
|
|
/obj/machinery/power/supermatter_crystal/attack_robot(mob/user)
|
|
if(Adjacent(user))
|
|
dust_mob(user, cause = "cyborg attack")
|
|
|
|
/obj/machinery/power/supermatter_crystal/attack_ai(mob/user)
|
|
return
|
|
|
|
/obj/machinery/power/supermatter_crystal/attack_hand(mob/living/user)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
dust_mob(user, cause = "hand")
|
|
|
|
/obj/machinery/power/supermatter_crystal/proc/dust_mob(mob/living/nom, vis_msg, mob_msg, cause)
|
|
if(nom.incorporeal_move || nom.status_flags & GODMODE)
|
|
return
|
|
if(!vis_msg)
|
|
vis_msg = "<span class='danger'>[nom] reaches out and touches [src], inducing a resonance... [nom.p_their()] body starts to glow and bursts into flames before flashing into ash"
|
|
if(!mob_msg)
|
|
mob_msg = "<span class='userdanger'>You reach out and touch [src]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\"</span>"
|
|
if(!cause)
|
|
cause = "contact"
|
|
nom.visible_message(vis_msg, mob_msg, "<span class='italics'>You hear an unearthly noise as a wave of heat washes over you.</span>")
|
|
investigate_log("has been attacked ([cause]) by [key_name(nom)]", INVESTIGATE_SUPERMATTER)
|
|
playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
|
|
Consume(nom)
|
|
|
|
/obj/machinery/power/supermatter_crystal/attackby(obj/item/W, mob/living/user, params)
|
|
if(!istype(W) || (W.item_flags & ABSTRACT) || !istype(user))
|
|
return
|
|
if (istype(W, /obj/item/melee/roastingstick))
|
|
return ..()
|
|
if(istype(W, /obj/item/scalpel/supermatter))
|
|
to_chat(user, "<span class='notice'>You carefully begin to scrape \the [src] with \the [W]...</span>")
|
|
if(W.use_tool(src, user, 60, volume=100))
|
|
to_chat(user, "<span class='notice'>You extract a sliver from \the [src]. \The [src] begins to react violently!</span>")
|
|
new /obj/item/nuke_core/supermatter_sliver(drop_location())
|
|
matter_power += 200
|
|
else if(user.dropItemToGround(W))
|
|
user.visible_message("<span class='danger'>As [user] touches \the [src] with \a [W], silence fills the room...</span>",\
|
|
"<span class='userdanger'>You touch \the [src] with \the [W], and everything suddenly goes silent.</span>\n<span class='notice'>\The [W] flashes into dust as you flinch away from \the [src].</span>",\
|
|
"<span class='italics'>Everything suddenly goes silent.</span>")
|
|
investigate_log("has been attacked ([W]) by [key_name(user)]", INVESTIGATE_SUPERMATTER)
|
|
Consume(W)
|
|
playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
|
|
|
|
radiation_pulse(src, 150, 4)
|
|
|
|
/obj/machinery/power/supermatter_crystal/wrench_act(mob/user, obj/item/tool)
|
|
if (moveable)
|
|
default_unfasten_wrench(user, tool, time = 20)
|
|
return TRUE
|
|
|
|
/obj/machinery/power/supermatter_crystal/Bumped(atom/movable/AM)
|
|
if(isliving(AM))
|
|
AM.visible_message("<span class='danger'>\The [AM] slams into \the [src] inducing a resonance... [AM.p_their()] body starts to glow and catch flame before flashing into ash.</span>",\
|
|
"<span class='userdanger'>You slam into \the [src] as your ears are filled with unearthly ringing. Your last thought is \"Oh, fuck.\"</span>",\
|
|
"<span class='italics'>You hear an unearthly noise as a wave of heat washes over you.</span>")
|
|
else if(isobj(AM) && !iseffect(AM))
|
|
AM.visible_message("<span class='danger'>\The [AM] smacks into \the [src] and rapidly flashes to ash.</span>", null,\
|
|
"<span class='italics'>You hear a loud crack as you are washed with a wave of heat.</span>")
|
|
else
|
|
return
|
|
|
|
playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
|
|
|
|
Consume(AM)
|
|
|
|
/obj/machinery/power/supermatter_crystal/proc/Consume(atom/movable/AM)
|
|
if(isliving(AM))
|
|
var/mob/living/user = AM
|
|
if(user.status_flags & GODMODE)
|
|
return
|
|
message_admins("[src] has consumed [key_name_admin(user)] [ADMIN_JMP(src)].")
|
|
investigate_log("has consumed [key_name(user)].", INVESTIGATE_SUPERMATTER)
|
|
user.dust(force = TRUE)
|
|
matter_power += 200
|
|
else if(istype(AM, /obj/singularity))
|
|
return
|
|
else if(isobj(AM))
|
|
if(!iseffect(AM))
|
|
var/suspicion = ""
|
|
if(AM.fingerprintslast)
|
|
suspicion = "last touched by [AM.fingerprintslast]"
|
|
message_admins("[src] has consumed [AM], [suspicion] [ADMIN_JMP(src)].")
|
|
investigate_log("has consumed [AM] - [suspicion].", INVESTIGATE_SUPERMATTER)
|
|
qdel(AM)
|
|
if(!iseffect(AM))
|
|
matter_power += 200
|
|
|
|
//Some poor sod got eaten, go ahead and irradiate people nearby.
|
|
radiation_pulse(src, 3000, 2, TRUE)
|
|
for(var/mob/living/L in range(10))
|
|
investigate_log("has irradiated [key_name(L)] after consuming [AM].", INVESTIGATE_SUPERMATTER)
|
|
if(L in view())
|
|
L.show_message("<span class='danger'>As \the [src] slowly stops resonating, you find your skin covered in new radiation burns.</span>", 1,\
|
|
"<span class='danger'>The unearthly ringing subsides and you notice you have new radiation burns.</span>", 2)
|
|
else
|
|
L.show_message("<span class='italics'>You hear an unearthly ringing and notice your skin is covered in fresh radiation burns.</span>", 2)
|
|
|
|
//Do not blow up our internal radio
|
|
/obj/machinery/power/supermatter_crystal/contents_explosion(severity, target)
|
|
return
|
|
|
|
/obj/machinery/power/supermatter_crystal/prevent_content_explosion()
|
|
return TRUE
|
|
|
|
/obj/machinery/power/supermatter_crystal/engine
|
|
is_main_engine = TRUE
|
|
|
|
/obj/machinery/power/supermatter_crystal/shard
|
|
name = "supermatter shard"
|
|
desc = "A strangely translucent and iridescent crystal that looks like it used to be part of a larger structure."
|
|
base_icon_state = "darkmatter_shard"
|
|
icon_state = "darkmatter_shard"
|
|
anchored = FALSE
|
|
gasefficency = 0.125
|
|
explosion_power = 12
|
|
moveable = TRUE
|
|
|
|
/obj/machinery/power/supermatter_crystal/shard/engine
|
|
name = "anchored supermatter shard"
|
|
is_main_engine = TRUE
|
|
anchored = TRUE
|
|
moveable = FALSE
|
|
|
|
// When you wanna make a supermatter shard for the dramatic effect, but
|
|
// don't want it exploding suddenly
|
|
/obj/machinery/power/supermatter_crystal/shard/hugbox
|
|
name = "anchored supermatter shard"
|
|
takes_damage = FALSE
|
|
produces_gas = FALSE
|
|
moveable = FALSE
|
|
anchored = TRUE
|
|
|
|
/obj/machinery/power/supermatter_crystal/shard/hugbox/fakecrystal //Hugbox shard with crystal visuals, used in the Supermatter/Hyperfractal shuttle
|
|
name = "supermatter crystal"
|
|
base_icon_state = "darkmatter"
|
|
icon_state = "darkmatter"
|
|
|
|
/obj/machinery/power/supermatter_crystal/proc/supermatter_pull(turf/center, pull_range = 10)
|
|
playsound(src.loc, 'sound/weapons/marauder.ogg', 100, 1, extrarange = 7)
|
|
for(var/atom/P in orange(pull_range,center))
|
|
if(ismovableatom(P))
|
|
var/atom/movable/pulled_object = P
|
|
if(ishuman(P))
|
|
var/mob/living/carbon/human/H = P
|
|
H.apply_effect(40, EFFECT_KNOCKDOWN, 0)
|
|
if(pulled_object && !pulled_object.anchored && !ishuman(P))
|
|
step_towards(pulled_object,center)
|
|
step_towards(pulled_object,center)
|
|
step_towards(pulled_object,center)
|
|
step_towards(pulled_object,center)
|
|
|
|
/obj/machinery/power/supermatter_crystal/proc/supermatter_anomaly_gen(turf/anomalycenter, type = FLUX_ANOMALY, anomalyrange = 5)
|
|
var/turf/L = pick(orange(anomalyrange, anomalycenter))
|
|
if(L)
|
|
switch(type)
|
|
if(FLUX_ANOMALY)
|
|
var/obj/effect/anomaly/flux/A = new(L, 300)
|
|
A.explosive = FALSE
|
|
if(GRAVITATIONAL_ANOMALY)
|
|
new /obj/effect/anomaly/grav(L, 250)
|
|
if(PYRO_ANOMALY)
|
|
new /obj/effect/anomaly/pyro(L, 200)
|
|
|
|
/obj/machinery/power/supermatter_crystal/proc/supermatter_zap(atom/zapstart, range = 3, power)
|
|
. = zapstart.dir
|
|
if(power < 1000)
|
|
return
|
|
|
|
var/target_atom
|
|
var/mob/living/target_mob
|
|
var/obj/machinery/target_machine
|
|
var/obj/structure/target_structure
|
|
var/list/arctargetsmob = list()
|
|
var/list/arctargetsmachine = list()
|
|
var/list/arctargetsstructure = list()
|
|
|
|
if(prob(20)) //let's not hit all the engineers with every beam and/or segment of the arc
|
|
for(var/mob/living/Z in oview(zapstart, range+2))
|
|
arctargetsmob += Z
|
|
if(arctargetsmob.len)
|
|
var/mob/living/H = pick(arctargetsmob)
|
|
var/atom/A = H
|
|
target_mob = H
|
|
target_atom = A
|
|
|
|
else
|
|
for(var/obj/machinery/X in oview(zapstart, range+2))
|
|
arctargetsmachine += X
|
|
if(arctargetsmachine.len)
|
|
var/obj/machinery/M = pick(arctargetsmachine)
|
|
var/atom/A = M
|
|
target_machine = M
|
|
target_atom = A
|
|
|
|
else
|
|
for(var/obj/structure/Y in oview(zapstart, range+2))
|
|
arctargetsstructure += Y
|
|
if(arctargetsstructure.len)
|
|
var/obj/structure/O = pick(arctargetsstructure)
|
|
var/atom/A = O
|
|
target_structure = O
|
|
target_atom = A
|
|
|
|
if(target_atom)
|
|
zapstart.Beam(target_atom, icon_state="nzcrentrs_power", time=5)
|
|
var/zapdir = get_dir(zapstart, target_atom)
|
|
if(zapdir)
|
|
. = zapdir
|
|
|
|
if(target_mob)
|
|
target_mob.electrocute_act(rand(5,10), "Supermatter Discharge Bolt", 1, stun = 0)
|
|
if(prob(15))
|
|
supermatter_zap(target_mob, 5, power / 2)
|
|
supermatter_zap(target_mob, 5, power / 2)
|
|
else
|
|
supermatter_zap(target_mob, 5, power / 1.5)
|
|
|
|
else if(target_machine)
|
|
if(prob(15))
|
|
supermatter_zap(target_machine, 5, power / 2)
|
|
supermatter_zap(target_machine, 5, power / 2)
|
|
else
|
|
supermatter_zap(target_machine, 5, power / 1.5)
|
|
|
|
else if(target_structure)
|
|
if(prob(15))
|
|
supermatter_zap(target_structure, 5, power / 2)
|
|
supermatter_zap(target_structure, 5, power / 2)
|
|
else
|
|
supermatter_zap(target_structure, 5, power / 1.5)
|
|
|
|
#undef HALLUCINATION_RANGE
|
|
#undef GRAVITATIONAL_ANOMALY
|
|
#undef FLUX_ANOMALY
|
|
#undef PYRO_ANOMALY
|