mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-09 07:48:55 +00:00
1013 lines
45 KiB
Plaintext
1013 lines
45 KiB
Plaintext
//For my sanity :))
|
|
|
|
#define COOLANT_INPUT_GATE airs[1]
|
|
#define MODERATOR_INPUT_GATE airs[2]
|
|
#define COOLANT_OUTPUT_GATE airs[3]
|
|
|
|
#define RBMK_TEMPERATURE_OPERATING 640 //Celsius
|
|
#define RBMK_TEMPERATURE_CRITICAL 810 //At this point the entire ship/station is alerted to a meltdown. This may need altering
|
|
#define RBMK_TEMPERATURE_MELTDOWN 900
|
|
|
|
#define RBMK_NO_COOLANT_TOLERANCE 5 //How many process()ing ticks the reactor can sustain without coolant before slowly taking damage
|
|
|
|
#define RBMK_PRESSURE_OPERATING 1000 //PSI
|
|
#define RBMK_PRESSURE_CRITICAL 1469.59 //PSI
|
|
|
|
#define RBMK_MAX_CRITICALITY 3 //No more criticality than N for now.
|
|
|
|
#define RBMK_POWER_FLAVOURISER 1000 //To turn those KWs into something usable
|
|
|
|
//Math. Lame.
|
|
#define KPA_TO_PSI(A) (A/6.895)
|
|
#define PSI_TO_KPA(A) (A*6.895)
|
|
#define KELVIN_TO_CELSIUS(A) (A-273.15)
|
|
#define MEGAWATTS /1e+6
|
|
#define CELSIUS_TO_KELVIN(T_K) ((T_K) + T0C)
|
|
|
|
//Reference: Heaters go up to 500K.
|
|
//Hot plasmaburn: 14164.95 C.
|
|
|
|
/**
|
|
What is this?
|
|
Moderators list (Not gonna keep this accurate forever):
|
|
Fuel Type:
|
|
Oxygen: Power production multiplier. Allows you to run a low plasma, high oxy mix, and still get a lot of power.
|
|
Plasma: Power production gas. More plasma -> more power, but it enriches your fuel and makes the reactor much, much harder to control.
|
|
Tritium: Extremely efficient power production gas. Will cause chernobyl if used improperly.
|
|
Moderation Type:
|
|
N2: Helps you regain control of the reaction by increasing control rod effectiveness, will massively boost the rad production of the reactor.
|
|
CO2: Super effective shutdown gas for runaway reactions. MASSIVE RADIATION PENALTY!
|
|
Pluoxium: Same as N2, but no cancer-rads!
|
|
Permeability Type:
|
|
BZ: Increases your reactor's ability to transfer its heat to the coolant, thus letting you cool it down faster (but your output will get hotter)
|
|
Water Vapour: More efficient permeability modifier
|
|
Hyper Noblium: Extremely efficient permeability increase. (10x as efficient as bz)
|
|
Depletion type:
|
|
Nitryl: When you need weapons grade plutonium yesterday. Causes your fuel to deplete much, much faster. Not a huge amount of use outside of sabotage.
|
|
Sabotage:
|
|
Meltdown:
|
|
Flood reactor moderator with plasma, they won't be able to mitigate the reaction with control rods.
|
|
Shut off coolant entirely. Raise control rods.
|
|
Swap all fuel out with spent fuel, as it's way stronger.
|
|
Blowout:
|
|
Shut off exit valve for quick overpressure.
|
|
Cause a pipefire in the coolant line (LETHAL).
|
|
Tack heater onto coolant line (can also cause straight meltdown)
|
|
Tips:
|
|
Be careful to not exhaust your plasma supply. I recommend you DON'T max out the moderator input when youre running plasma + o2, or you're at a tangible risk of running out of those gasses from atmos.
|
|
The reactor CHEWS through moderator. It does not do this slowly. Be very careful with that!
|
|
*/
|
|
|
|
//Remember kids. If the reactor itself is not physically powered by an APC, it cannot shove coolant in!
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor
|
|
name = "Advanced Gas-Cooled Nuclear Reactor"
|
|
desc = "A tried and tested design which can output stable power at an acceptably low risk. The moderator can be changed to provide different effects."
|
|
icon = 'icons/obj/machines/rbmk.dmi'
|
|
icon_state = "reactor_map"
|
|
pixel_x = -32
|
|
pixel_y = -32
|
|
density = FALSE //It burns you if you're stupid enough to walk over it.
|
|
anchored = TRUE
|
|
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
|
|
light_color = LIGHT_COLOR_CYAN
|
|
dir = WEST //Less headache inducing :))
|
|
var/id = null //Change me mappers
|
|
//Variables essential to operation
|
|
var/temperature = 0 //Lose control of this -> Meltdown
|
|
var/vessel_integrity = 400 //How long can the reactor withstand overpressure / meltdown? This gives you a fair chance to react to even a massive pipe fire
|
|
var/pressure = 0 //Lose control of this -> Blowout
|
|
var/K = 0 //Rate of reaction.
|
|
var/desired_k = 0
|
|
var/control_rod_effectiveness = 0.65 //Starts off with a lot of control over K. If you flood this thing with plasma, you lose your ability to control K as easily.
|
|
var/power = 0 //0-100%. A function of the maximum heat you can achieve within operating temperature
|
|
var/power_modifier = 1 //Upgrade me with parts, science! Flat out increase to physical power output when loaded with plasma.
|
|
var/list/fuel_rods = list()
|
|
//Secondary variables.
|
|
var/next_slowprocess = 0
|
|
var/gas_absorption_effectiveness = 0.5
|
|
var/gas_absorption_constant = 0.5 //We refer to this one as it's set on init, randomized.
|
|
var/minimum_coolant_level = 2
|
|
var/warning = FALSE //Have we begun warning the crew of their impending death?
|
|
var/next_warning = 0 //To avoid spam.
|
|
var/last_power_produced = 0 //For logging purposes
|
|
var/next_flicker = 0 //Light flicker timer
|
|
var/base_power_modifier = RBMK_POWER_FLAVOURISER
|
|
var/slagged = FALSE //Is this reactor even usable any more?
|
|
//Console statistics.
|
|
var/last_coolant_temperature = 0
|
|
var/last_output_temperature = 0
|
|
var/last_heat_delta = 0 //For administrative cheating only. Knowing the delta lets you know EXACTLY what to set K at.
|
|
var/no_coolant_ticks = 0 //How many times in succession did we not have enough coolant? Decays twice as fast as it accumulates.
|
|
var/last_user = null
|
|
var/current_desired_k = null
|
|
var/datum/looping_sound/rbmk_reactor/soundloop
|
|
var/datum/powernet/powernet = null
|
|
|
|
//Use this in your maps if you want everything to be preset.
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/preset
|
|
id = "default_reactor_for_lazy_mappers"
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/examine(mob/user)
|
|
. = ..()
|
|
if(Adjacent(src, user))
|
|
if(do_after(user, 1 SECONDS, target=src))
|
|
var/percent = vessel_integrity / initial(vessel_integrity) * 100
|
|
var/msg = "<span class='warning'>The reactor looks operational.</span>"
|
|
switch(percent)
|
|
if(0 to 10)
|
|
msg = "<span class='boldwarning'>[src]'s seals are dangerously warped and you can see cracks all over the reactor vessel! </span>"
|
|
if(10 to 40)
|
|
msg = "<span class='boldwarning'>[src]'s seals are heavily warped and cracked! </span>"
|
|
if(40 to 60)
|
|
msg = "<span class='warning'>[src]'s seals are holding, but barely. You can see some micro-fractures forming in the reactor vessel.</span>"
|
|
if(60 to 80)
|
|
msg = "<span class='warning'>[src]'s seals are in-tact, but slightly worn. There are no visible cracks in the reactor vessel.</span>"
|
|
if(80 to 90)
|
|
msg = "<span class='notice'>[src]'s seals are in good shape, and there are no visible cracks in the reactor vessel.</span>"
|
|
if(95 to 100)
|
|
msg = "<span class='notice'>[src]'s seals look factory new, and the reactor's in excellent shape.</span>"
|
|
. += msg
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/attackby(obj/item/W, mob/user, params)
|
|
if(istype(W, /obj/item/fuel_rod))
|
|
if(power >= 20)
|
|
to_chat(user, "<span class='notice'>You cannot insert fuel into [src] when it has been raised above 20% power.</span>")
|
|
return FALSE
|
|
if(fuel_rods.len >= 5)
|
|
to_chat(user, "<span class='warning'>[src] is already at maximum fuel load.</span>")
|
|
return FALSE
|
|
to_chat(user, "<span class='notice'>You start to insert [W] into [src]...</span>")
|
|
radiation_pulse(src, temperature)
|
|
if(do_after(user, 5 SECONDS, target=src))
|
|
if(!fuel_rods.len)
|
|
start_up() //That was the first fuel rod. Let's heat it up.
|
|
message_admins("Reactor first started up by [ADMIN_LOOKUPFLW(user)] in [ADMIN_VERBOSEJMP(src)]")
|
|
investigate_log("Reactor first started by [key_name(user)] at [AREACOORD(src)]", INVESTIGATE_SINGULO)
|
|
fuel_rods += W
|
|
W.forceMove(src)
|
|
radiation_pulse(src, temperature) //Wear protective equipment when even breathing near a reactor!
|
|
investigate_log("Rod added to reactor by [key_name(user)] at [AREACOORD(src)]", INVESTIGATE_SINGULO)
|
|
return TRUE
|
|
if(istype(W, /obj/item/sealant))
|
|
if(power >= 20)
|
|
to_chat(user, "<span class='notice'>You cannot repair [src] while it is running at above 20% power.</span>")
|
|
return FALSE
|
|
if(vessel_integrity >= 350)
|
|
to_chat(user, "<span class='notice'>[src]'s seals are already in-tact, repairing them further would require a new set of seals.</span>")
|
|
return FALSE
|
|
if(vessel_integrity <= 0.5 * initial(vessel_integrity)) //Heavily damaged.
|
|
to_chat(user, "<span class='notice'>[src]'s reactor vessel is cracked and worn, you need to repair the cracks with a welder before you can repair the seals.</span>")
|
|
return FALSE
|
|
if(do_after(user, 5 SECONDS, target=src))
|
|
if(vessel_integrity >= 350) //They might've stacked doafters
|
|
to_chat(user, "<span class='notice'>[src]'s seals are already in-tact, repairing them further would require a new set of seals.</span>")
|
|
return FALSE
|
|
playsound(src, 'sound/effects/spray2.ogg', 50, 1, -6)
|
|
user.visible_message("<span class='warning'>[user] applies sealant to some of [src]'s worn out seals.</span>", "<span class='notice'>You apply sealant to some of [src]'s worn out seals.</span>")
|
|
vessel_integrity += 10
|
|
vessel_integrity = clamp(vessel_integrity, 0, initial(vessel_integrity))
|
|
return TRUE
|
|
return ..()
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/welder_act(mob/living/user, obj/item/I)
|
|
if(power >= 20)
|
|
to_chat(user, "<span class='notice'>You can't repair [src] while it is running at above 20% power.</span>")
|
|
return FALSE
|
|
if(vessel_integrity > 0.5 * initial(vessel_integrity))
|
|
to_chat(user, "<span class='notice'>[src] is free from cracks. Further repairs must be carried out with flexi-seal sealant.</span>")
|
|
return FALSE
|
|
if(I.use_tool(src, user, 0, volume=40))
|
|
if(vessel_integrity > 0.5 * initial(vessel_integrity))
|
|
to_chat(user, "<span class='notice'>[src] is free from cracks. Further repairs must be carried out with flexi-seal sealant.</span>")
|
|
return FALSE
|
|
vessel_integrity += 20
|
|
to_chat(user, "<span class='notice'>You weld together some of [src]'s cracks. This'll do for now.</span>")
|
|
return TRUE
|
|
|
|
//Admin procs to mess with the reaction environment.
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/lazy_startup()
|
|
for(var/I=0;I<5;I++)
|
|
fuel_rods += new /obj/item/fuel_rod(src)
|
|
message_admins("Reactor started up by admins in [ADMIN_VERBOSEJMP(src)]")
|
|
start_up()
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/deplete()
|
|
for(var/obj/item/fuel_rod/FR in fuel_rods)
|
|
FR.depletion = 100
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/Initialize()
|
|
. = ..()
|
|
connect_to_network()
|
|
icon_state = "reactor_off"
|
|
gas_absorption_effectiveness = rand(5, 6)/10 //All reactors are slightly different. This will result in you having to figure out what the balance is for K.
|
|
gas_absorption_constant = gas_absorption_effectiveness //And set this up for the rest of the round.
|
|
STOP_PROCESSING(SSmachines, src) //We'll handle this one ourselves.
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/Crossed(atom/movable/AM, oldloc)
|
|
. = ..()
|
|
if(isliving(AM) && temperature > 0)
|
|
var/mob/living/L = AM
|
|
L.adjust_bodytemperature(clamp(temperature, BODYTEMP_COOLING_MAX, BODYTEMP_HEATING_MAX)) //If you're on fire, you heat up!
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/process()
|
|
update_parents() //Update the pipenet to register new gas mixes
|
|
if(next_slowprocess < world.time)
|
|
slowprocess()
|
|
next_slowprocess = world.time + 1 SECONDS //Set to wait for another second before processing again, we don't need to process more than once a second
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/has_fuel()
|
|
return fuel_rods?.len
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/slowprocess()
|
|
//Let's get our gasses sorted out.
|
|
var/datum/gas_mixture/coolant_input = COOLANT_INPUT_GATE
|
|
var/datum/gas_mixture/moderator_input = MODERATOR_INPUT_GATE
|
|
var/datum/gas_mixture/coolant_output = COOLANT_OUTPUT_GATE
|
|
|
|
//Firstly, heat up the reactor based off of K.
|
|
var/input_moles = coolant_input.total_moles() //Firstly. Do we have enough moles of coolant?
|
|
if(input_moles >= minimum_coolant_level)
|
|
last_coolant_temperature = KELVIN_TO_CELSIUS(coolant_input.return_temperature())
|
|
//Important thing to remember, once you slot in the fuel rods, this thing will not stop making heat, at least, not unless you can live to be thousands of years old which is when the spent fuel finally depletes fully.
|
|
var/heat_delta = (KELVIN_TO_CELSIUS(coolant_input.return_temperature()) / 100) * gas_absorption_effectiveness //Take in the gas as a cooled input, cool the reactor a bit. The optimum, 100% balanced reaction sits at K=1, coolant input temp of 200K / -73 celsius.
|
|
last_heat_delta = heat_delta
|
|
temperature += heat_delta
|
|
coolant_output.merge(coolant_input) //And now, shove the input into the output.
|
|
coolant_input.clear() //Clear out anything left in the input gate.
|
|
color = null
|
|
no_coolant_ticks = max(0, no_coolant_ticks-2) //Needs half as much time to recover the ticks than to acquire them
|
|
else
|
|
if(has_fuel())
|
|
no_coolant_ticks++
|
|
if(no_coolant_ticks > RBMK_NO_COOLANT_TOLERANCE)
|
|
temperature += temperature / 500 //This isn't really harmful early game, but when your reactor is up to full power, this can get out of hand quite quickly.
|
|
vessel_integrity -= temperature / 200 //Think fast chucklenuts!
|
|
take_damage(10) //Just for the sound effect, to let you know you've fucked up.
|
|
color = "[COLOR_RED]"
|
|
investigate_log("Reactor taking damage from the lack of coolant", INVESTIGATE_SINGULO)
|
|
//Now, heat up the output and set our pressure.
|
|
coolant_output.set_temperature(CELSIUS_TO_KELVIN(temperature)) //Heat the coolant output gas that we just had pass through us.
|
|
last_output_temperature = KELVIN_TO_CELSIUS(coolant_output.return_temperature())
|
|
pressure = KPA_TO_PSI(coolant_output.return_pressure())
|
|
power = (temperature / RBMK_TEMPERATURE_CRITICAL) * 100
|
|
var/radioactivity_spice_multiplier = 1 //Some gasses make the reactor a bit spicy.
|
|
var/depletion_modifier = 0.035 //How rapidly do your rods decay
|
|
gas_absorption_effectiveness = gas_absorption_constant
|
|
//Next up, handle moderators!
|
|
if(moderator_input.total_moles() >= minimum_coolant_level)
|
|
var/total_fuel_moles = moderator_input.get_moles(GAS_PLASMA) + (moderator_input.get_moles(GAS_TRITIUM)*10) //Constricted plasma is 50% more efficient as fuel than plasma, but is harder to produce
|
|
var/power_modifier = max((moderator_input.get_moles(GAS_O2) / moderator_input.total_moles() * 10), 1) //You can never have negative IPM. For now.
|
|
if(total_fuel_moles >= minimum_coolant_level) //You at least need SOME fuel.
|
|
var/power_produced = max((total_fuel_moles / moderator_input.total_moles() * 10), 1)
|
|
last_power_produced = max(0,((power_produced*power_modifier)*moderator_input.total_moles()))
|
|
last_power_produced *= (power/100) //Aaaand here comes the cap. Hotter reactor => more power.
|
|
last_power_produced *= base_power_modifier //Finally, we turn it into actual usable numbers.
|
|
radioactivity_spice_multiplier += moderator_input.get_moles(GAS_TRITIUM) / 5 //Chernobyl 2.
|
|
var/turf/T = get_turf(src)
|
|
if(power >= 20)
|
|
coolant_output.adjust_moles(GAS_NITRYL, total_fuel_moles/50) //Shove out nitryl into the air when it's fuelled. You need to filter this off, or you're gonna have a bad time.
|
|
var/obj/structure/cable/C = T.get_cable_node()
|
|
if(!C?.powernet)
|
|
//message_admins("No cable or cable has no powernet!")
|
|
return
|
|
else
|
|
C.powernet.newavail += last_power_produced //hacky wtf
|
|
//message_admins("Adding [last_power_produced] to powernet.")
|
|
add_avail(last_power_produced)
|
|
var/total_control_moles = moderator_input.get_moles(GAS_N2) + (moderator_input.get_moles(GAS_CO2)*2) + (moderator_input.get_moles(GAS_PLUOXIUM)*3) //N2 helps you control the reaction at the cost of making it absolutely blast you with rads. Pluoxium has the same effect but without the rads!
|
|
if(total_control_moles >= minimum_coolant_level)
|
|
var/control_bonus = total_control_moles / 250 //1 mol of n2 -> 0.002 bonus control rod effectiveness, if you want a super controlled reaction, you'll have to sacrifice some power.
|
|
control_rod_effectiveness = initial(control_rod_effectiveness) + control_bonus
|
|
radioactivity_spice_multiplier += moderator_input.get_moles(GAS_N2) / 25 //An example setup of 50 moles of n2 (for dealing with spent fuel) leaves us with a radioactivity spice multiplier of 3.
|
|
radioactivity_spice_multiplier += moderator_input.get_moles(GAS_CO2) / 12.5
|
|
var/total_permeability_moles = moderator_input.get_moles(GAS_BZ) + (moderator_input.get_moles(GAS_H2O)*2) + (moderator_input.get_moles(GAS_HYPERNOB)*10)
|
|
if(total_permeability_moles >= minimum_coolant_level)
|
|
var/permeability_bonus = total_permeability_moles / 500
|
|
gas_absorption_effectiveness = gas_absorption_constant + permeability_bonus
|
|
var/total_degradation_moles = moderator_input.get_moles(GAS_NITRYL) //Because it's quite hard to get.
|
|
if(total_degradation_moles >= minimum_coolant_level*0.5) //I'll be nice.
|
|
depletion_modifier += total_degradation_moles / 15 //Oops! All depletion. This causes your fuel rods to get SPICY.
|
|
playsound(src, pick('sound/machines/sm/accent/normal/1.ogg','sound/machines/sm/accent/normal/2.ogg','sound/machines/sm/accent/normal/3.ogg','sound/machines/sm/accent/normal/4.ogg','sound/machines/sm/accent/normal/5.ogg'), 100, TRUE)
|
|
//From this point onwards, we clear out the remaining gasses.
|
|
moderator_input.clear() //Woosh. And the soul is gone.
|
|
K += total_fuel_moles / 1000
|
|
var/fuel_power = 0 //So that you can't magically generate K with your control rods.
|
|
if(!has_fuel()) //Reactor must be fuelled and ready to go before we can heat it up boys.
|
|
K = 0
|
|
else
|
|
for(var/obj/item/fuel_rod/FR in fuel_rods)
|
|
K += FR.fuel_power
|
|
fuel_power += FR.fuel_power
|
|
FR.deplete(depletion_modifier)
|
|
//Firstly, find the difference between the two numbers.
|
|
var/difference = abs(K - desired_k)
|
|
//Then, hit as much of that goal with our cooling per tick as we possibly can.
|
|
difference = clamp(difference, 0, control_rod_effectiveness) //And we can't instantly zap the K to what we want, so let's zap as much of it as we can manage....
|
|
if(difference > fuel_power && desired_k > K)
|
|
message_admins("Not enough fuel to get [difference]. We have fuel [fuel_power]")
|
|
investigate_log("Reactor has not enough fuel to get [difference]. We have fuel [fuel_power]", INVESTIGATE_SINGULO)
|
|
difference = fuel_power //Again, to stop you being able to run off of 1 fuel rod.
|
|
if(K != desired_k)
|
|
if(desired_k > K)
|
|
K += difference
|
|
else if(desired_k < K)
|
|
K -= difference
|
|
if(K == desired_k && last_user && current_desired_k != desired_k)
|
|
current_desired_k = desired_k
|
|
message_admins("Reactor desired criticality set to [desired_k] by [ADMIN_LOOKUPFLW(last_user)] in [ADMIN_VERBOSEJMP(src)]")
|
|
investigate_log("reactor desired criticality set to [desired_k] by [key_name(last_user)] at [AREACOORD(src)]", INVESTIGATE_SINGULO)
|
|
|
|
K = clamp(K, 0, RBMK_MAX_CRITICALITY)
|
|
if(has_fuel())
|
|
temperature += K
|
|
else
|
|
temperature -= 10 //Nothing to heat us up, so.
|
|
handle_alerts() //Let's check if they're about to die, and let them know.
|
|
update_icon()
|
|
radiation_pulse(src, temperature*radioactivity_spice_multiplier)
|
|
if(power >= 93 && world.time >= next_flicker) //You're overloading the reactor. Give a more subtle warning that power is getting out of control.
|
|
next_flicker = world.time + 2 MINUTES
|
|
for(var/obj/machinery/light/L in GLOB.machines)
|
|
if(prob(25) && L.z == z) //If youre running the reactor cold though, no need to flicker the lights.
|
|
L.flicker()
|
|
investigate_log("Reactor overloading at [power]% power", INVESTIGATE_SINGULO)
|
|
for(var/atom/movable/I in get_turf(src))
|
|
if(isliving(I))
|
|
var/mob/living/L = I
|
|
if(temperature > 0)
|
|
L.adjust_bodytemperature(clamp(temperature, BODYTEMP_COOLING_MAX, BODYTEMP_HEATING_MAX)) //If you're on fire, you heat up!
|
|
if(istype(I, /obj/item/reagent_containers/food) && !istype(I, /obj/item/reagent_containers/food/drinks))
|
|
playsound(src, pick('sound/machines/fryer/deep_fryer_1.ogg', 'sound/machines/fryer/deep_fryer_2.ogg'), 100, TRUE)
|
|
var/obj/item/reagent_containers/food/grilled_item = I
|
|
if(prob(80))
|
|
continue //To give the illusion that it's actually cooking omegalul.
|
|
switch(power)
|
|
if(20 to 39)
|
|
grilled_item.name = "grilled [initial(grilled_item.name)]"
|
|
grilled_item.desc = "[initial(I.desc)] It's been grilled over a nuclear reactor."
|
|
if(!(grilled_item.foodtype & FRIED))
|
|
grilled_item.foodtype |= FRIED
|
|
if(40 to 70)
|
|
grilled_item.name = "heavily grilled [initial(grilled_item.name)]"
|
|
grilled_item.desc = "[initial(I.desc)] It's been heavily grilled through the magic of nuclear fission."
|
|
if(!(grilled_item.foodtype & FRIED))
|
|
grilled_item.foodtype |= FRIED
|
|
if(70 to 95)
|
|
grilled_item.name = "Three-Mile Nuclear-Grilled [initial(grilled_item.name)]"
|
|
grilled_item.desc = "A [initial(grilled_item.name)]. It's been put on top of a nuclear reactor running at extreme power by some badass engineer."
|
|
if(!(grilled_item.foodtype & FRIED))
|
|
grilled_item.foodtype |= FRIED
|
|
if(95 to INFINITY)
|
|
grilled_item.name = "Ultimate Meltdown Grilled [initial(grilled_item.name)]"
|
|
grilled_item.desc = "A [initial(grilled_item.name)]. A grill this perfect is a rare technique only known by a few engineers who know how to perform a 'controlled' meltdown whilst also having the time to throw food on a reactor. I'll bet it tastes amazing."
|
|
if(!(grilled_item.foodtype & FRIED))
|
|
grilled_item.foodtype |= FRIED
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/relay(var/sound, var/message=null, loop = FALSE, channel = null) //Sends a sound + text message to the crew of a ship
|
|
for(var/mob/M in GLOB.player_list)
|
|
if(M.z == z)
|
|
if(!isinspace(M))
|
|
if(sound)
|
|
if(channel) //Doing this forbids overlapping of sounds
|
|
SEND_SOUND(M, sound(sound, repeat = loop, wait = 0, volume = 70, channel = channel))
|
|
else
|
|
SEND_SOUND(M, sound(sound, repeat = loop, wait = 0, volume = 70))
|
|
if(message)
|
|
to_chat(M, message)
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/stop_relay(channel) //Stops all playing sounds for crewmen on N channel.
|
|
for(var/mob/M in GLOB.player_list)
|
|
if(M.z == z)
|
|
M.stop_sound_channel(channel)
|
|
|
|
//Method to handle sound effects, reactor warnings, all that jazz.
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/handle_alerts()
|
|
var/alert = FALSE //If we have an alert condition, we'd best let people know.
|
|
if(K <= 0 && temperature <= 0)
|
|
shut_down()
|
|
//First alert condition: Overheat
|
|
if(temperature >= RBMK_TEMPERATURE_CRITICAL)
|
|
alert = TRUE
|
|
investigate_log("Reactor reaching critical temperature at [temperature] C with desired criticality at [desired_k]", INVESTIGATE_SINGULO)
|
|
message_admins("Reactor reaching critical temperature at [ADMIN_VERBOSEJMP(src)]")
|
|
if(temperature >= RBMK_TEMPERATURE_MELTDOWN)
|
|
var/temp_damage = min(temperature/100, initial(vessel_integrity)/40) //40 seconds to meltdown from full integrity, worst-case. Bit less than blowout since it's harder to spike heat that much.
|
|
vessel_integrity -= temp_damage
|
|
if(vessel_integrity <= temp_damage)
|
|
investigate_log("Reactor melted down at [temperature] C with desired criticality at [desired_k]", INVESTIGATE_SINGULO)
|
|
meltdown() //Oops! All meltdown
|
|
return
|
|
else
|
|
alert = FALSE
|
|
if(temperature < -200) //That's as cold as I'm letting you get it, engineering.
|
|
color = COLOR_CYAN
|
|
temperature = -200
|
|
else
|
|
color = null
|
|
//Second alert condition: Overpressurized (the more lethal one)
|
|
if(pressure >= RBMK_PRESSURE_CRITICAL)
|
|
alert = TRUE
|
|
investigate_log("Reactor reaching critical pressure at [pressure] PSI with desired criticality at [desired_k]", INVESTIGATE_SINGULO)
|
|
message_admins("Reactor reaching critical pressure at [ADMIN_VERBOSEJMP(src)]")
|
|
shake_animation(0.5)
|
|
playsound(loc, 'sound/machines/clockcult/steam_whoosh.ogg', 100, TRUE)
|
|
var/turf/T = get_turf(src)
|
|
T.atmos_spawn_air("water_vapor=[pressure/100];TEMP=[CELSIUS_TO_KELVIN(temperature)]")
|
|
var/pressure_damage = min(pressure/100, initial(vessel_integrity)/45) //You get 45 seconds (if you had full integrity), worst-case. But hey, at least it can't be instantly nuked with a pipe-fire.. though it's still very difficult to save.
|
|
vessel_integrity -= pressure_damage
|
|
if(vessel_integrity <= pressure_damage) //It wouldn't
|
|
investigate_log("Reactor blowout at [pressure] PSI with desired criticality at [desired_k]", INVESTIGATE_SINGULO)
|
|
blowout()
|
|
return
|
|
if(warning)
|
|
if(!alert) //Congrats! You stopped the meltdown / blowout.
|
|
stop_relay(CHANNEL_REACTOR_ALERT)
|
|
warning = FALSE
|
|
set_light(0)
|
|
light_color = LIGHT_COLOR_CYAN
|
|
set_light(10)
|
|
else
|
|
if(!alert)
|
|
return
|
|
if(world.time < next_warning)
|
|
return
|
|
next_warning = world.time + 30 SECONDS //To avoid engis pissing people off when reaaaally trying to stop the meltdown or whatever.
|
|
warning = TRUE //Start warning the crew of the imminent danger.
|
|
relay('sound/effects/rbmk/alarm.ogg', null, loop=TRUE, channel = CHANNEL_REACTOR_ALERT)
|
|
set_light(0)
|
|
light_color = LIGHT_COLOR_RED
|
|
set_light(10)
|
|
|
|
//Failure condition 1: Meltdown. Achieved by having heat go over tolerances. This is less devastating because it's easier to achieve.
|
|
//Results: Engineering becomes unusable and your engine irreparable
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/meltdown()
|
|
set waitfor = FALSE
|
|
SSair.stop_processing_machine(src)
|
|
slagged = TRUE
|
|
color = null
|
|
update_icon()
|
|
STOP_PROCESSING(SSmachines, src)
|
|
icon_state = "reactor_slagged"
|
|
AddComponent(/datum/component/radioactive, 15000 , src, 0)
|
|
var/obj/effect/landmark/nuclear_waste_spawner/NSW = new /obj/effect/landmark/nuclear_waste_spawner/strong(get_turf(src))
|
|
relay('sound/effects/rbmk/meltdown.ogg', "<span class='userdanger'>You hear a horrible metallic hissing.</span>")
|
|
stop_relay(CHANNEL_REACTOR_ALERT)
|
|
NSW.fire() //This will take out engineering for a decent amount of time as they have to clean up the sludge.
|
|
for(var/obj/machinery/power/apc/apc in GLOB.apcs_list)
|
|
if((apc.z == z) && prob(70))
|
|
apc.overload_lighting()
|
|
var/datum/gas_mixture/coolant_input = COOLANT_INPUT_GATE
|
|
var/datum/gas_mixture/moderator_input = MODERATOR_INPUT_GATE
|
|
var/datum/gas_mixture/coolant_output = COOLANT_OUTPUT_GATE
|
|
var/turf/T = get_turf(src)
|
|
coolant_input.set_temperature(CELSIUS_TO_KELVIN(temperature)*2)
|
|
moderator_input.set_temperature(CELSIUS_TO_KELVIN(temperature)*2)
|
|
coolant_output.set_temperature(CELSIUS_TO_KELVIN(temperature)*2)
|
|
T.assume_air(coolant_input)
|
|
T.assume_air(moderator_input)
|
|
T.assume_air(coolant_output)
|
|
power = 0 //we set it to zero so the reactor can be serviced and repaired.
|
|
explosion(get_turf(src), 0, 5, 10, 20, TRUE, TRUE)
|
|
empulse(get_turf(src), 25, 15)
|
|
QDEL_NULL(soundloop)
|
|
|
|
//Failure condition 2: Blowout. Achieved by reactor going over-pressured. This is a round-ender because it requires more fuckery to achieve.
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/blowout()
|
|
explosion(get_turf(src), GLOB.MAX_EX_DEVESTATION_RANGE, GLOB.MAX_EX_HEAVY_RANGE, GLOB.MAX_EX_LIGHT_RANGE, GLOB.MAX_EX_FLASH_RANGE)
|
|
meltdown() //Double kill.
|
|
power = 0 //we set it to zero so the reactor can be serviced and repaired.
|
|
SSweather.run_weather("nuclear fallout")
|
|
for(var/X in GLOB.landmarks_list)
|
|
if(istype(X, /obj/effect/landmark/nuclear_waste_spawner))
|
|
var/obj/effect/landmark/nuclear_waste_spawner/WS = X
|
|
if(is_station_level(WS.z)) //Begin the SLUDGING
|
|
WS.fire()
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/update_icon()
|
|
icon_state = "reactor_off"
|
|
switch(temperature)
|
|
if(0 to 200)
|
|
icon_state = "reactor_on"
|
|
if(200 to RBMK_TEMPERATURE_OPERATING)
|
|
icon_state = "reactor_hot"
|
|
if(RBMK_TEMPERATURE_OPERATING to 750)
|
|
icon_state = "reactor_veryhot"
|
|
if(750 to RBMK_TEMPERATURE_CRITICAL) //Point of no return.
|
|
icon_state = "reactor_overheat"
|
|
if(RBMK_TEMPERATURE_CRITICAL to INFINITY)
|
|
icon_state = "reactor_meltdown"
|
|
if(!has_fuel())
|
|
icon_state = "reactor_off"
|
|
if(slagged)
|
|
icon_state = "reactor_slagged"
|
|
|
|
|
|
//Startup, shutdown
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/start_up()
|
|
START_PROCESSING(SSmachines, src)
|
|
desired_k = 1
|
|
set_light(10)
|
|
var/startup_sound = pick('sound/effects/ship/reactor/startup.ogg', 'sound/effects/ship/reactor/startup2.ogg')
|
|
playsound(loc, startup_sound, 100)
|
|
soundloop = new(src, TRUE)
|
|
if(!powernet)
|
|
message_admins("No powernet for the Nuclear Reactor! Trying to add.")
|
|
connect_to_network()
|
|
if(!powernet)
|
|
message_admins("Powernet add fail. This reactor will never produce power.")
|
|
|
|
//Shuts off the fuel rods, ambience, etc. Keep in mind that your temperature may still go up!
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/shut_down()
|
|
STOP_PROCESSING(SSmachines, src)
|
|
set_light(0)
|
|
K = 0
|
|
desired_k = 0
|
|
temperature = 0
|
|
update_icon()
|
|
QDEL_NULL(soundloop)
|
|
|
|
/obj/item/fuel_rod/Initialize()
|
|
.=..()
|
|
AddComponent(/datum/component/radioactive, 350 , src)
|
|
|
|
//Controlling the reactor.
|
|
|
|
/obj/machinery/computer/reactor
|
|
name = "Reactor control console"
|
|
desc = "Scream"
|
|
light_color = "#55BA55"
|
|
light_power = 1
|
|
light_range = 3
|
|
icon = 'icons/obj/rbmk_computer.dmi'
|
|
icon_state = "oldcomp"
|
|
icon_screen = "library"
|
|
icon_keyboard = null
|
|
var/obj/machinery/atmospherics/components/trinary/nuclear_reactor/reactor = null
|
|
var/id = "default_reactor_for_lazy_mappers"
|
|
|
|
/obj/machinery/computer/reactor/Initialize(mapload, obj/item/circuitboard/C)
|
|
. = ..()
|
|
addtimer(CALLBACK(src, PROC_REF(link_to_reactor)), 10 SECONDS)
|
|
|
|
/obj/machinery/computer/reactor/wrench_act(mob/living/user, obj/item/I)
|
|
to_chat(user, "<span class='notice'>You start [anchored ? "un" : ""]securing [name]...</span>")
|
|
if(I.use_tool(src, user, 40, volume=75))
|
|
to_chat(user, "<span class='notice'>You [anchored ? "un" : ""]secure [name].</span>")
|
|
setAnchored(!anchored)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/obj/machinery/computer/reactor/proc/link_to_reactor()
|
|
for(var/obj/machinery/atmospherics/components/trinary/nuclear_reactor/asdf in GLOB.machines)
|
|
if(asdf.id && asdf.id == id)
|
|
reactor = asdf
|
|
return TRUE
|
|
return FALSE
|
|
|
|
#define FREQ_RBMK_CONTROL 1439.69
|
|
|
|
/obj/machinery/computer/reactor/control_rods
|
|
name = "Control rod management computer"
|
|
desc = "A computer which can remotely raise / lower the control rods of a reactor."
|
|
icon_screen = "rbmk_rods"
|
|
|
|
/obj/machinery/computer/reactor/control_rods/attack_hand(mob/living/user)
|
|
. = ..()
|
|
ui_interact(user)
|
|
|
|
/obj/machinery/computer/reactor/control_rods/ui_interact(mob/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "RbmkControlRods")
|
|
ui.open()
|
|
ui.set_autoupdate(TRUE)
|
|
|
|
/obj/machinery/computer/reactor/control_rods/ui_act(action, params)
|
|
if(..())
|
|
return
|
|
if(!reactor)
|
|
return
|
|
if(action == "input")
|
|
var/input = text2num(params["target"])
|
|
reactor.last_user = usr
|
|
reactor.desired_k = clamp(input, 0, 3)
|
|
|
|
/obj/machinery/computer/reactor/control_rods/ui_data(mob/user)
|
|
var/list/data = list()
|
|
data["control_rods"] = 0
|
|
data["k"] = 0
|
|
data["desiredK"] = 0
|
|
if(reactor)
|
|
data["k"] = reactor.K
|
|
data["desiredK"] = reactor.desired_k
|
|
data["control_rods"] = 100 - (reactor.desired_k / 3 * 100) //Rod insertion is extrapolated as a function of the percentage of K
|
|
return data
|
|
|
|
/obj/machinery/computer/reactor/stats
|
|
name = "Reactor Statistics Console"
|
|
desc = "A console for monitoring the statistics of a nuclear reactor."
|
|
icon_screen = "rbmk_stats"
|
|
var/next_stat_interval = 0
|
|
var/list/psiData = list()
|
|
var/list/powerData = list()
|
|
var/list/tempInputData = list()
|
|
var/list/tempOutputdata = list()
|
|
|
|
/obj/machinery/computer/reactor/stats/attack_hand(mob/living/user)
|
|
. = ..()
|
|
ui_interact(user)
|
|
|
|
/obj/machinery/computer/reactor/stats/ui_interact(mob/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "RbmkStats")
|
|
ui.open()
|
|
ui.set_autoupdate(TRUE)
|
|
|
|
/obj/machinery/computer/reactor/stats/process()
|
|
if(world.time >= next_stat_interval)
|
|
next_stat_interval = world.time + 1 SECONDS //You only get a slow tick.
|
|
psiData += (reactor) ? reactor.pressure : 0
|
|
if(psiData.len > 100) //Only lets you track over a certain timeframe.
|
|
psiData.Cut(1, 2)
|
|
powerData += (reactor) ? reactor.power*10 : 0 //We scale up the figure for a consistent:tm: scale
|
|
if(powerData.len > 100) //Only lets you track over a certain timeframe.
|
|
powerData.Cut(1, 2)
|
|
tempInputData += (reactor) ? reactor.last_coolant_temperature : 0 //We scale up the figure for a consistent:tm: scale
|
|
if(tempInputData.len > 100) //Only lets you track over a certain timeframe.
|
|
tempInputData.Cut(1, 2)
|
|
tempOutputdata += (reactor) ? reactor.last_output_temperature : 0 //We scale up the figure for a consistent:tm: scale
|
|
if(tempOutputdata.len > 100) //Only lets you track over a certain timeframe.
|
|
tempOutputdata.Cut(1, 2)
|
|
|
|
/obj/machinery/computer/reactor/stats/ui_data(mob/user)
|
|
var/list/data = list()
|
|
data["powerData"] = powerData
|
|
data["psiData"] = psiData
|
|
data["tempInputData"] = tempInputData
|
|
data["tempOutputdata"] = tempOutputdata
|
|
data["coolantInput"] = reactor ? reactor.last_coolant_temperature : 0
|
|
data["coolantOutput"] = reactor ? reactor.last_output_temperature : 0
|
|
data["power"] = reactor ? reactor.power : 0
|
|
data ["psi"] = reactor ? reactor.pressure : 0
|
|
return data
|
|
|
|
/obj/machinery/computer/reactor/fuel_rods
|
|
name = "Reactor Fuel Management Console"
|
|
desc = "A console which can remotely raise fuel rods out of nuclear reactors."
|
|
icon_screen = "rbmk_fuel"
|
|
|
|
/obj/machinery/computer/reactor/fuel_rods/attack_hand(mob/living/user)
|
|
. = ..()
|
|
if(!reactor)
|
|
return FALSE
|
|
if(reactor.power > 20)
|
|
to_chat(user, "<span class='warning'>You cannot remove fuel from [reactor] when it is above 20% power.</span>")
|
|
return FALSE
|
|
if(!reactor.fuel_rods.len)
|
|
to_chat(user, "<span class='warning'>[reactor] does not have any fuel rods loaded.</span>")
|
|
return FALSE
|
|
var/atom/movable/fuel_rod = input(usr, "Select a fuel rod to remove", "[src]", null) as null|anything in reactor.fuel_rods
|
|
if(!fuel_rod)
|
|
return
|
|
playsound(src, pick('sound/effects/rbmk/switch.ogg','sound/effects/rbmk/switch2.ogg','sound/effects/rbmk/switch3.ogg'), 100, FALSE)
|
|
playsound(reactor, 'sound/effects/ship/freespace2/crane_1.wav', 100, FALSE)
|
|
fuel_rod.forceMove(get_turf(reactor))
|
|
reactor.fuel_rods -= fuel_rod
|
|
|
|
//Preset pumps for mappers. You can also set the id tags yourself.
|
|
/obj/machinery/atmospherics/components/binary/pump/rbmk_input
|
|
id = "rbmk_input"
|
|
frequency = FREQ_RBMK_CONTROL
|
|
|
|
/obj/machinery/atmospherics/components/binary/pump/rbmk_output
|
|
id = "rbmk_output"
|
|
frequency = FREQ_RBMK_CONTROL
|
|
|
|
/obj/machinery/atmospherics/components/binary/pump/rbmk_moderator
|
|
id = "rbmk_moderator"
|
|
frequency = FREQ_RBMK_CONTROL
|
|
|
|
/obj/machinery/computer/reactor/pump
|
|
name = "Reactor inlet valve computer"
|
|
desc = "A computer which controls valve settings on an advanced gas cooled reactor. Alt click it to remotely set pump pressure."
|
|
icon_screen = "rbmk_input"
|
|
id = "rbmk_input"
|
|
var/datum/radio_frequency/radio_connection
|
|
var/on = FALSE
|
|
|
|
/obj/machinery/computer/reactor/pump/AltClick(mob/user)
|
|
. = ..()
|
|
var/newPressure = input(user, "Set new output pressure (kPa)", "Remote pump control", null) as num
|
|
if(!newPressure)
|
|
return
|
|
newPressure = clamp(newPressure, 0, MAX_OUTPUT_PRESSURE) //Number sanitization is not handled in the pumps themselves, only during their ui_act which this doesn't use.
|
|
signal(on, newPressure)
|
|
|
|
/obj/machinery/computer/reactor/attack_robot(mob/user)
|
|
. = ..()
|
|
attack_hand(user)
|
|
|
|
/obj/machinery/computer/reactor/attack_ai(mob/user)
|
|
. = ..()
|
|
attack_hand(user)
|
|
|
|
/obj/machinery/computer/reactor/pump/attack_hand(mob/living/user)
|
|
. = ..()
|
|
if(!is_operational())
|
|
return FALSE
|
|
playsound(loc, pick('sound/effects/rbmk/switch.ogg','sound/effects/rbmk/switch2.ogg','sound/effects/rbmk/switch3.ogg'), 100, FALSE)
|
|
visible_message("<span class='notice'>[src]'s switch flips [on ? "off" : "on"].</span>")
|
|
on = !on
|
|
signal(on)
|
|
|
|
/obj/machinery/computer/reactor/pump/Initialize(mapload, obj/item/circuitboard/C)
|
|
. = ..()
|
|
radio_connection = SSradio.add_object(src, FREQ_RBMK_CONTROL,filter=RADIO_ATMOSIA)
|
|
|
|
/obj/machinery/computer/reactor/pump/proc/signal(power, set_output_pressure=null)
|
|
var/datum/signal/signal
|
|
if(!set_output_pressure) //Yes this is stupid, but technically if you pass through "set_output_pressure" onto the signal, it'll always try and set its output pressure and yeahhh...
|
|
signal = new(list(
|
|
"tag" = id,
|
|
"frequency" = FREQ_RBMK_CONTROL,
|
|
"timestamp" = world.time,
|
|
"power" = power,
|
|
"sigtype" = "command"
|
|
))
|
|
else
|
|
signal = new(list(
|
|
"tag" = id,
|
|
"frequency" = FREQ_RBMK_CONTROL,
|
|
"timestamp" = world.time,
|
|
"power" = power,
|
|
"set_output_pressure" = set_output_pressure,
|
|
"sigtype" = "command"
|
|
))
|
|
radio_connection.post_signal(src, signal, filter=RADIO_ATMOSIA)
|
|
|
|
//Preset subtypes for mappers
|
|
/obj/machinery/computer/reactor/pump/rbmk_input
|
|
name = "Reactor inlet valve computer"
|
|
icon_screen = "rbmk_input"
|
|
id = "rbmk_input"
|
|
|
|
/obj/machinery/computer/reactor/pump/rbmk_output
|
|
name = "Reactor output valve computer"
|
|
icon_screen = "rbmk_output"
|
|
id = "rbmk_output"
|
|
|
|
/obj/machinery/computer/reactor/pump/rbmk_moderator
|
|
name = "Reactor moderator valve computer"
|
|
icon_screen = "rbmk_moderator"
|
|
id = "rbmk_moderator"
|
|
|
|
//Monitoring program.
|
|
/datum/computer_file/program/nuclear_monitor
|
|
filename = "rbmkmonitor"
|
|
filedesc = "Nuclear Reactor Monitoring"
|
|
ui_header = "smmon_0.gif"
|
|
program_icon_state = "smmon_0"
|
|
extended_desc = "This program connects to specially calibrated sensors to provide information on the status of nuclear reactors."
|
|
requires_ntnet = TRUE
|
|
transfer_access = ACCESS_CONSTRUCTION
|
|
//network_destination = "rbmk monitoring system" //Apparently we don't use these anymore
|
|
size = 2
|
|
tgui_id = "NtosRbmkStats"
|
|
//ui_x = 350
|
|
//ui_y = 550
|
|
var/active = TRUE //Easy process throttle
|
|
var/next_stat_interval = 0
|
|
var/list/psiData = list()
|
|
var/list/powerData = list()
|
|
var/list/tempInputData = list()
|
|
var/list/tempOutputdata = list()
|
|
var/obj/machinery/atmospherics/components/trinary/nuclear_reactor/reactor //Our reactor.
|
|
|
|
/datum/computer_file/program/nuclear_monitor/process_tick()
|
|
..()
|
|
if(!reactor || !active)
|
|
return FALSE
|
|
var/stage = 0
|
|
//This is dirty but i'm lazy wahoo!
|
|
if(reactor.power > 0)
|
|
stage = 1
|
|
if(reactor.power >= 40)
|
|
stage = 2
|
|
if(reactor.temperature >= RBMK_TEMPERATURE_OPERATING)
|
|
stage = 3
|
|
if(reactor.temperature >= RBMK_TEMPERATURE_CRITICAL)
|
|
stage = 4
|
|
if(reactor.temperature >= RBMK_TEMPERATURE_MELTDOWN)
|
|
stage = 5
|
|
if(reactor.vessel_integrity <= 100) //Bye bye! GET OUT!
|
|
stage = 6
|
|
ui_header = "smmon_[stage].gif"
|
|
program_icon_state = "smmon_[stage]"
|
|
if(istype(computer))
|
|
computer.update_icon()
|
|
if(world.time >= next_stat_interval)
|
|
next_stat_interval = world.time + 1 SECONDS //You only get a slow tick.
|
|
psiData += (reactor) ? reactor.pressure : 0
|
|
if(psiData.len > 100) //Only lets you track over a certain timeframe.
|
|
psiData.Cut(1, 2)
|
|
powerData += (reactor) ? reactor.power*10 : 0 //We scale up the figure for a consistent:tm: scale
|
|
if(powerData.len > 100) //Only lets you track over a certain timeframe.
|
|
powerData.Cut(1, 2)
|
|
tempInputData += (reactor) ? reactor.last_coolant_temperature : 0 //We scale up the figure for a consistent:tm: scale
|
|
if(tempInputData.len > 100) //Only lets you track over a certain timeframe.
|
|
tempInputData.Cut(1, 2)
|
|
tempOutputdata += (reactor) ? reactor.last_output_temperature : 0 //We scale up the figure for a consistent:tm: scale
|
|
if(tempOutputdata.len > 100) //Only lets you track over a certain timeframe.
|
|
tempOutputdata.Cut(1, 2)
|
|
|
|
/datum/computer_file/program/nuclear_monitor/run_program(mob/living/user)
|
|
. = ..(user)
|
|
//No reactor? Go find one then.
|
|
if(!reactor)
|
|
for(var/obj/machinery/atmospherics/components/trinary/nuclear_reactor/R in GLOB.machines)
|
|
if(R.z == usr.z)
|
|
reactor = R
|
|
break
|
|
active = TRUE
|
|
|
|
/datum/computer_file/program/nuclear_monitor/kill_program(forced = FALSE)
|
|
active = FALSE
|
|
..()
|
|
|
|
/datum/computer_file/program/nuclear_monitor/ui_data()
|
|
var/list/data = get_header_data()
|
|
data["powerData"] = powerData
|
|
data["psiData"] = psiData
|
|
data["tempInputData"] = tempInputData
|
|
data["tempOutputdata"] = tempOutputdata
|
|
data["coolantInput"] = reactor ? reactor.last_coolant_temperature : 0
|
|
data["coolantOutput"] = reactor ? reactor.last_output_temperature : 0
|
|
data["power"] = reactor ? reactor.power : 0
|
|
data ["psi"] = reactor ? reactor.pressure : 0
|
|
return data
|
|
|
|
/datum/computer_file/program/nuclear_monitor/ui_act(action, params)
|
|
if(..())
|
|
return TRUE
|
|
|
|
switch(action)
|
|
if("swap_reactor")
|
|
var/list/choices = list()
|
|
for(var/obj/machinery/atmospherics/components/trinary/nuclear_reactor/R in GLOB.machines)
|
|
if(R.z != usr.z)
|
|
continue
|
|
choices += R
|
|
reactor = input(usr, "What reactor do you wish to monitor?", "[src]", null) as null|anything in choices
|
|
powerData = list()
|
|
psiData = list()
|
|
tempInputData = list()
|
|
tempOutputdata = list()
|
|
return TRUE
|
|
|
|
/obj/effect/decal/nuclear_waste
|
|
name = "Plutonium sludge"
|
|
desc = "A writhing pool of heavily irradiated, spent reactor fuel. You probably shouldn't step through this..."
|
|
icon = 'icons/obj/machines/reactor_parts.dmi'
|
|
icon_state = "nuclearwaste"
|
|
alpha = 150
|
|
light_color = LIGHT_COLOR_CYAN
|
|
color = "#ff9eff"
|
|
|
|
/obj/effect/decal/nuclear_waste/Initialize()
|
|
. = ..()
|
|
for(var/obj/A in get_turf(src))
|
|
if(istype(A, /obj/structure))
|
|
qdel(src) //It is more processing efficient to do this here rather than when searching for available turfs.
|
|
set_light(3)
|
|
AddComponent(/datum/component/radioactive, 1000, src, 0)
|
|
|
|
/obj/effect/decal/nuclear_waste/epicenter //The one that actually does the irradiating. This is to avoid every bit of sludge PROCESSING
|
|
name = "Dense nuclear sludge"
|
|
|
|
/obj/effect/landmark/nuclear_waste_spawner //Clean way of spawning nuclear gunk after a reactor core meltdown.
|
|
name = "Nuclear waste spawner"
|
|
var/range = 5 //5 tile radius to spawn goop
|
|
|
|
/obj/effect/landmark/nuclear_waste_spawner/strong
|
|
range = 10
|
|
|
|
/obj/effect/landmark/nuclear_waste_spawner/proc/fire()
|
|
playsound(loc, 'sound/effects/gib_step.ogg', 100)
|
|
new /obj/effect/decal/nuclear_waste/epicenter(get_turf(src))
|
|
for(var/turf/open/floor in orange(range, get_turf(src)))
|
|
if(prob(35)) //Scatter the sludge, don't smear it everywhere
|
|
new /obj/effect/decal/nuclear_waste (floor)
|
|
qdel(src)
|
|
|
|
/obj/effect/decal/nuclear_waste/epicenter/Initialize()
|
|
. = ..()
|
|
|
|
/obj/effect/decal/nuclear_waste/Crossed(atom/movable/AM)
|
|
. = ..()
|
|
if(isliving(AM))
|
|
var/mob/living/L = AM
|
|
playsound(loc, 'sound/effects/gib_step.ogg', HAS_TRAIT(L, TRAIT_LIGHT_STEP) ? 20 : 50, 1)
|
|
radiation_pulse(src, 500, 5) //MORE RADS
|
|
|
|
/obj/effect/decal/nuclear_waste/attackby(obj/item/tool, mob/user)
|
|
if(tool.tool_behaviour == TOOL_SHOVEL)
|
|
radiation_pulse(src, 1000, 5) //MORE RADS
|
|
to_chat(user, "<span class='notice'>You start to clear [src]...</span>")
|
|
if(tool.use_tool(src, user, 50, volume=100))
|
|
to_chat(user, "<span class='notice'>You clear [src]. </span>")
|
|
qdel(src)
|
|
return
|
|
. = ..()
|
|
|
|
/datum/weather/nuclear_fallout
|
|
name = "nuclear fallout"
|
|
desc = "Irradiated dust falls down everywhere."
|
|
telegraph_duration = 50
|
|
telegraph_message = "<span class='boldwarning'>The air suddenly becomes dusty..</span>"
|
|
weather_message = "<span class='userdanger'><i>You feel a wave of hot ash fall down on you.</i></span>"
|
|
weather_overlay = "light_ash"
|
|
telegraph_overlay = "light_snow"
|
|
weather_duration_lower = 600
|
|
weather_duration_upper = 1500
|
|
weather_color = "green"
|
|
telegraph_sound = null
|
|
weather_sound = 'sound/effects/ship/reactor/falloutwind.ogg'
|
|
end_duration = 100
|
|
area_type = /area
|
|
protected_areas = list(/area/maintenance, /area/ai_monitored/turret_protected/ai_upload, /area/ai_monitored/turret_protected/ai_upload_foyer,
|
|
/area/ai_monitored/turret_protected/ai, /area/commons/storage/emergency/starboard, /area/commons/storage/emergency/port, /area/shuttle)
|
|
target_trait = ZTRAIT_STATION
|
|
end_message = "<span class='notice'>The ash stops falling.</span>"
|
|
immunity_type = "rad"
|
|
|
|
/datum/weather/nuclear_fallout/weather_act(mob/living/L)
|
|
L.rad_act(100)
|
|
|
|
/datum/weather/nuclear_fallout/telegraph()
|
|
..()
|
|
status_alarm(TRUE)
|
|
|
|
/datum/weather/nuclear_fallout/proc/status_alarm(active) //Makes the status displays show the radiation warning for those who missed the announcement.
|
|
var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS)
|
|
if(!frequency)
|
|
return
|
|
|
|
var/datum/signal/signal = new
|
|
if (active)
|
|
signal.data["command"] = "alert"
|
|
signal.data["picture_state"] = "radiation"
|
|
else
|
|
signal.data["command"] = "shuttle"
|
|
|
|
var/atom/movable/virtualspeaker/virt = new(null)
|
|
frequency.post_signal(virt, signal)
|
|
|
|
/datum/weather/nuclear_fallout/end()
|
|
if(..())
|
|
return
|
|
status_alarm(FALSE)
|
|
|
|
/obj/item/sealant
|
|
name = "Flexi seal"
|
|
desc = "A neat spray can that can repair torn inflatable segments, and more!"
|
|
icon = 'icons/obj/inflatable.dmi'
|
|
icon_state = "sealant"
|
|
w_class = WEIGHT_CLASS_TINY
|
|
|
|
/area/engineering/main/reactor_core
|
|
name = "Nuclear Reactor Core"
|
|
|
|
/area/engineering/main/reactor_control
|
|
name = "Reactor Control Room"
|
|
|
|
|
|
//Procs shamelessly taken from machinery/power
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/connect_to_network()
|
|
var/turf/T = src.loc
|
|
if(!T || !istype(T))
|
|
return FALSE
|
|
|
|
var/obj/structure/cable/C = T.get_cable_node() //check if we have a node cable on the machine turf, the first found is picked
|
|
if(!C || !C.powernet)
|
|
return FALSE
|
|
|
|
C.powernet.add_machine(src)
|
|
return TRUE
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/disconnect_from_network()
|
|
if(!powernet)
|
|
return FALSE
|
|
powernet.remove_machine(src)
|
|
return TRUE
|
|
|
|
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/add_avail(amount)
|
|
if(powernet)
|
|
powernet.newavail += amount
|
|
return TRUE
|
|
else
|
|
return FALSE
|