The NGCR: Nuclear Fission Reactor (#30493)

* coefficient balancing

* damage and meltdowns

* meltdown stuff

* alert stuff

* lots of work - whew

* some enrichment code

* rod encrichmnt

* working on enrichment

* more fabrication

* rod fab

* start to the nuke

* overload sprites

* overload code work

* some overload tweaking

* small tweak

* coolant ejections and QOL things

* overheat events + ripley gripper

* rebase + venting code

* save before rebase

* some pre-work for rods

* finishing the base rods

* fixed my dme

* de linting

* tiny lint fix

* more lint fixes

* linting

* linting

* linting

* linting

* linting

* temp delint

* temp delint

* undo TM stuff + minor fix

* didnt save

* some fixes

* fixes

* fixes and engine repair

* fixed broken durability decay

* LOTS of things

* tgui

* lint

* linter

* linter

* minor shit

* Update boxstation.dmm

* major refactors and fixes

* saved this

* critical testing tweaks and fixes

* fixes and tweaks

* smithing start

* forgot to save

* craftables + grill start

* saved

* fix

* more grill work

* Update tgui.bundle.js

* linter

* linter

* fixes

* rod fabricator initial

* cooking work

* push

* soundwork

* sound work tweak

* comments + sounds + toxins gen rework

* lots of work

* sprite stuff

* deconflicting

* delinting

* bundle rebuild

* prettier

* feex

* fuck you OD

* who asked?

* update to tgui

* another edit to tgui

* finish tgui

* remove debug metadata button

* rod tweaks for tgui

* Update code/datums/uplink_items/uplink_traitor.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/game/mecha/equipment/tools/work_tools.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/game/mecha/equipment/tools/work_tools.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/game/objects/items/robot/cyborg_gripper.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/mob/living/simple_animal/parrot.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/mob/living/simple_animal/parrot.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/mob/living/simple_animal/parrot.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/mob/living/simple_animal/parrot.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/power/engines/fission/nuclear_misc.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/power/engines/fission/nuclear_misc.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/power/engines/fission/nuclear_misc.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/power/engines/fission/nuclear_rods.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/power/engines/fission/nuclear_rods.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/power/engines/fission/reactor.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/power/engines/fission/reactor.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/power/engines/fission/nuclear_rods.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/power/engines/fission/nuclear_rods.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/power/engines/fission/nuclear_rods.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/power/engines/fission/reactor.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/smithing/components/misc_components.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/power/engines/fission/nuclear_rods.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update tgui/packages/tgui/interfaces/NuclearRodFabricator.jsx

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Spans

* tgui build

* rod redo

* improve tgui for fabricator

* sprites and centrifuge/fab work

* tgui update

* spritework

* cyberiad + hydrogen conversion

* kerberos + counter

* Update code/modules/power/engines/fission/nuclear_rods.dm

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* sprite + fab tweak

* tgui bundle

* lintering

* bugfixing

* linting

* linting

* event tweak

* add missing gases to fission monitor

* issue fixing

* sprite/overlay fixes

* mapping

* stations again

* space lattice

* tine tweak

* linter

* no rod alerts

* buttons

* loose wire

* make it so you can interact through rod casings and the uhh big thing in the center, what's that called again

* fixes

* door fix

* many bug fixes + crates

* fab ghost touch

* water convert + maint sprite + fixes

* pack changes + neighbor fix

* doors rename

* didnt save

* hydrogen fix

* map tweaks

* repair fixes + corium LETHALITY

* upped broken rad damage

* pipe rename + overload icons

* more roundstart moderators

* rod tree tweaks

* tweaks

* pack and enrichment fixes

* misc tweaks and fixes

* fixes: Density, circuits, coolant offline negation

* Apply suggestions from code review

Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* review changes

* linter + fix

* reviews and fixes

* LOTS of tweaks and changes

* supermatter kit

* spacematter balance

* tgui

* fixes and tweaks

* didnt save this

* mapping + smith fix

* cargo rods arnt radioactive til opened

* Apply suggestions from code review

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* review items

* fixes

* linters

* moving components out of nullspace

* examine fix

* Update tgui.bundle.js

* explosion nerf and minor fix

* Apply suggestions from code review

Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* reviews

* map fix + ripley rad immune

* Apply suggestions from code review

Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* review

* fix chamber examine

* tweaks + rod fab disk drop

* Apply suggestions from code review

Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* review changes

* Update code/modules/power/engines/fission/nuclear_rods.dm

Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* fixes

* tgui bundle

* small rod tweaks

* Update code/game/machinery/computer/buildandrepair.dm

Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/smithing/components/reactor_components.dm

Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/power/engines/fission/reactor_machines.dm

Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* Update code/modules/power/engines/fission/reactor_machines.dm

Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com>
Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>

* reviews

* Update code/modules/power/engines/fission/reactor_machines.dm

Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com>

---------

Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com>
Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com>
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
Co-authored-by: Paul <pmerkamp@gmail.com>
Co-authored-by: Pooble <90473506+poobsie@users.noreply.github.com>
Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com>
This commit is contained in:
Kyani
2026-01-07 04:19:43 -05:00
committed by GitHub
parent 6611476bdb
commit f81ef075f1
59 changed files with 13266 additions and 8242 deletions
@@ -0,0 +1,103 @@
/datum/nuclear_rod_design
var/type_path
var/category = "Unknown"
var/list/metadata
/datum/nuclear_rod_design/proc/build_metadata_list(path)
metadata = list()
type_path = path
var/obj/item/nuclear_rod/T = path
metadata["name"] = initial(T.name)
metadata["desc"] = initial(T.desc)
metadata["icon"] = initial(T.icon)
metadata["icon_state"] = initial(T.icon_state)
metadata["type_path"] = path
metadata["max_durability"] = initial(T.max_durability)
metadata["degradation_speed"] = initial(T.degradation_speed)
metadata["heat_amount"] = initial(T.heat_amount)
metadata["heat_amp_mod"] = initial(T.heat_amp_mod)
metadata["power_amount"] = initial(T.power_amount)
metadata["power_amp_mod"] = initial(T.power_amp_mod)
metadata["alpha_rad"] = initial(T.alpha_rad)
metadata["beta_rad"] = initial(T.beta_rad)
metadata["gamma_rad"] = initial(T.gamma_rad)
metadata["minimum_temp_modifier"] = initial(T.minimum_temp_modifier)
metadata["upgrade_required"] = initial(T.upgrade_required)
metadata["required_object"] = initial(T.required_object)
// Temp object lets us read in materials and adjacent requirements because you can't initial() a list
var/obj/item/nuclear_rod/temp_rod = new path()
var/list/raw_materials = temp_rod.materials
var/list/requirements = temp_rod.adjacent_requirements
qdel(temp_rod)
if(raw_materials && length(raw_materials))
var/list/formatted_materials = list()
for(var/mat_id in raw_materials)
var/display_name = CallMaterialName(mat_id)
formatted_materials[display_name] = raw_materials[mat_id]
metadata["materials"] = formatted_materials
else
metadata["materials"] = list()
if(ispath(path, /obj/item/nuclear_rod/fuel))
var/obj/item/nuclear_rod/fuel/F = path
metadata["craftable"] = initial(F.craftable)
metadata["enrichment_cycles"] = initial(F.enrichment_cycles)
metadata["power_enrich_threshold"] = initial(F.power_enrich_threshold)
metadata["heat_enrich_threshold"] = initial(F.heat_enrich_threshold)
// Get enrichment result names
if(initial(F.power_enrich_result))
var/obj/item/nuclear_rod/power_result = initial(F.power_enrich_result)
metadata["power_enrichment"] = initial(power_result.name)
metadata["power_enrichment_requirement"] = initial(F.power_enrich_threshold)
else
metadata["power_enrichment"] = null
metadata["power_enrichment_requirement"] = null
if(initial(F.heat_enrich_result))
var/obj/item/nuclear_rod/heat_result = initial(F.heat_enrich_result)
metadata["heat_enrichment"] = initial(heat_result.name)
metadata["heat_enrichment_requirement"] = initial(F.heat_enrich_threshold)
else
metadata["heat_enrichment"] = null
metadata["heat_enrichment_requirement"] = null
else if(ispath(path, /obj/item/nuclear_rod/moderator))
var/obj/item/nuclear_rod/moderator/M = path
metadata["craftable"] = initial(M.craftable)
else if(ispath(path, /obj/item/nuclear_rod/coolant))
var/obj/item/nuclear_rod/coolant/C = path
metadata["craftable"] = initial(C.craftable)
else
metadata["craftable"] = FALSE
if(requirements && length(requirements))
var/list/temp_reqs = list()
var/list/req_counts = list()
// Count occurrences of each requirement type
for(var/req_path in requirements)
var/obj/item/nuclear_rod/req = req_path
var/req_name = initial(req.name)
if(req_counts[req_name])
req_counts[req_name]++
else
req_counts[req_name] = 1
// Format the requirements with counts
for(var/req_name in req_counts)
var/count = req_counts[req_name]
temp_reqs += "[count]x [req_name]"
metadata["neighbor_requirements"] = temp_reqs
metadata["adjacent_requirements_display"] = english_list(temp_reqs, and_text = ", ")
else
metadata["neighbor_requirements"] = list()
metadata["adjacent_requirements_display"] = "None"
return TRUE
@@ -0,0 +1,140 @@
#define MINIMUM_MOLES 3 //! the minimum amount of moles we transfer, regardless of pressure on the other side.
/obj/machinery/atmospherics/unary/reactor_gas_node
name = "reactor gas intake"
desc = "A sturdy-looking gas inlet that injects gas into the reactor."
icon = 'icons/obj/fission/reactor_machines.dmi'
icon_state = "gas_node"
layer = GAS_PIPE_VISIBLE_LAYER
max_integrity = 2000
target_pressure = 100000 // Maximum pressure in KPA
flags_2 = NO_MALF_EFFECT_2
/// Hold which reactor the intake is connected to.
var/obj/machinery/atmospherics/fission_reactor/linked_reactor
/// Is this vent taking air in or out. TRUE by default.
var/intake_vent = TRUE
/obj/machinery/atmospherics/unary/reactor_gas_node/output
name = "Reactor Gas Extractor"
intake_vent = FALSE
/obj/machinery/atmospherics/unary/reactor_gas_node/Initialize(mapload)
. = ..()
component_parts = list()
component_parts += new /obj/item/circuitboard/machine/reactor_gas_node(src)
component_parts += new /obj/item/stack/sheet/metal(src, 2)
component_parts += new /obj/item/stack/cable_coil(src, 2)
initialize_directions = dir
RefreshParts()
update_icon()
return INITIALIZE_HINT_LATELOAD
// Needs lateload to prevent reactor not being initialized yet and thus not able to set the link.
/obj/machinery/atmospherics/unary/reactor_gas_node/LateInitialize()
. = ..()
form_link(TRUE)
/obj/machinery/atmospherics/unary/reactor_gas_node/examine(mob/user)
. = ..()
. += SPAN_NOTICE("A wrench can be used to alter the direction of the node.")
. += SPAN_NOTICE("Gas nodes will only link with reactors when facing a reactor from the side opposite of the inlet pipe.")
/obj/machinery/atmospherics/unary/reactor_gas_node/process_atmos()
if(stat & (NOPOWER|BROKEN))
return FALSE
if(!linked_reactor)
return FALSE
if(linked_reactor.admin_intervention)
return FALSE
if(linked_reactor.safety_override) // We dont want to cool down an intentional runaway reactor
return FALSE
var/datum/gas_mixture/network1
var/datum/gas_mixture/network2
if(intake_vent)
network1 = linked_reactor.air_contents
network2 = air_contents
else
network1 = air_contents
network2 = linked_reactor.air_contents
if(!network1 || !network2)
return FALSE
// This is basically passive gate code
var/output_starting_pressure = network1.return_pressure()
var/input_starting_pressure = network2.return_pressure()
// Calculate necessary moles to transfer using PV = nRT
if((network2.total_moles() > 0) && (network2.temperature() > 0))
var/pressure_delta = min(target_pressure - output_starting_pressure, (input_starting_pressure - output_starting_pressure) / 2)
if(intake_vent)
pressure_delta = max(pressure_delta, MINIMUM_MOLES) // Always work at least a little bit when inputting gas
var/transfer_moles = pressure_delta * network1.volume / (network2.temperature() * R_IDEAL_GAS_EQUATION)
// Actually transfer the gas
var/datum/gas_mixture/removed = network2.remove(transfer_moles)
network1.merge(removed)
parent.update = TRUE
return TRUE
/obj/machinery/atmospherics/unary/reactor_gas_node/screwdriver_act(mob/living/user, obj/item/I)
default_deconstruction_screwdriver(user, icon_state, icon_state, I)
/obj/machinery/atmospherics/unary/reactor_gas_node/crowbar_act(mob/living/user, obj/item/I)
to_chat(user, SPAN_INFORMATION("You begin to pry out the internal piping..."))
if(I.use_tool(src, user, 3 SECONDS, volume = I.tool_volume))
default_deconstruction_crowbar(user, I)
/obj/machinery/atmospherics/unary/reactor_gas_node/wrench_act(mob/user, obj/item/I)
var/list/choices = list("West" = WEST, "East" = EAST, "South" = SOUTH, "North" = NORTH)
var/selected = tgui_input_list(user, "Select a direction for the connector.", "Connector Direction", choices)
if(!selected)
return ITEM_INTERACT_COMPLETE
if(!I.use_tool(src, user, 3 SECONDS, volume = I.tool_volume))
return ITEM_INTERACT_COMPLETE
if(!Adjacent(user))
to_chat(user, SPAN_WARNING("You moved away before construction was finished!"))
return ITEM_INTERACT_COMPLETE
dir = choices[selected]
initialize_directions = dir
for(var/obj/machinery/atmospherics/target in get_step(src, dir))
if(target.initialize_directions & get_dir(target,src))
node = target
break
form_link(FALSE)
initialize_atmos_network()
update_icon()
return ITEM_INTERACT_COMPLETE
/obj/machinery/atmospherics/unary/reactor_gas_node/proc/form_link(silent = FALSE)
linked_reactor = null
var/turf/T = get_step(src, REVERSE_DIR(dir))
for(var/obj/machinery/atmospherics/fission_reactor/reactor in T)
linked_reactor = reactor
for(var/obj/structure/filler/filler in T)
if(istype(filler.parent, /obj/machinery/atmospherics/fission_reactor))
linked_reactor = filler.parent
if(silent)
return
if(!linked_reactor)
playsound(src, 'sound/machines/buzz-sigh.ogg', 30, TRUE)
audible_message(SPAN_INFO("The gas node buzzes as it fails to connect to a reactor."))
else
playsound(src, 'sound/machines/ping.ogg', 30, TRUE)
audible_message(SPAN_INFO("The gas node pings as it connects to the reactor."))
/obj/machinery/atmospherics/unary/reactor_gas_node/multitool_act(mob/living/user, obj/item/I)
to_chat(user, SPAN_INFORMATION("You begin to reverse the gas flow direction..."))
if(do_after_once(user, 1 SECONDS, TRUE, src, allow_moving = FALSE))
intake_vent = !intake_vent
if(intake_vent)
name = "Reactor Gas Intake"
else
name = "Reactor Gas Extractor"
return ..()
#undef MINIMUM_MOLES
@@ -0,0 +1,398 @@
// MARK: Reactor Power Output
/obj/machinery/power/reactor_power
name = "reactor output terminal"
desc = "A bundle of heavy watt power cables for managing power output from the reactor."
icon_state = "term"
plane = FLOOR_PLANE
layer = WIRE_TERMINAL_LAYER // A bit above wires
resistance_flags = INDESTRUCTIBLE
var/obj/machinery/atmospherics/fission_reactor/linked_reactor
/obj/machinery/power/reactor_power/Initialize(mapload)
. = ..()
return INITIALIZE_HINT_LATELOAD
// Needs lateload to prevent reactor not being initialized yet and thus not able to set the link.
/obj/machinery/power/reactor_power/LateInitialize()
. = ..()
linked_reactor = GLOB.main_fission_reactor
/obj/machinery/power/reactor_power/process()
if(linked_reactor && linked_reactor.can_create_power)
produce_direct_power(linked_reactor.final_power)
// MARK: Monitor
/obj/machinery/computer/fission_monitor
name = "NGCR monitoring console"
desc = "Used to monitor the Nanotrasen Gas Cooled Fission Reactor."
icon_keyboard = "power_key"
icon_screen = "smmon_0"
circuit = /obj/item/circuitboard/fission_monitor
light_color = LIGHT_COLOR_YELLOW
/// Last status of the active reactor for caching purposes
var/last_status
/// Reference to the active reactor
var/obj/machinery/atmospherics/fission_reactor/active
/// Is this monitor a controller? Affected by visibility from the reactor
var/controller = TRUE
/obj/machinery/computer/fission_monitor/Initialize(mapload)
. = ..()
return INITIALIZE_HINT_LATELOAD
/obj/machinery/computer/fission_monitor/LateInitialize()
. = ..()
active = GLOB.main_fission_reactor
determine_control()
/obj/machinery/computer/fission_monitor/Destroy()
active = null
return ..()
// This can normally never happen, but just in case.
/obj/machinery/computer/fission_monitor/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change)
. = ..()
determine_control()
/obj/machinery/computer/fission_monitor/proc/determine_control()
if(!active)
return
if(active in oview(12, src))
controller = TRUE
else
controller = FALSE
/obj/machinery/computer/fission_monitor/attack_ai(mob/user)
attack_hand(user)
/obj/machinery/computer/fission_monitor/attack_hand(mob/user)
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
ui_interact(user)
/obj/machinery/computer/fission_monitor/ui_state(mob/user)
return GLOB.default_state
/obj/machinery/computer/fission_monitor/process()
if(stat & (NOPOWER|BROKEN))
return FALSE
if(active)
var/new_status = active.get_status()
if(last_status != new_status)
last_status = new_status
icon_screen = "smmon_[last_status]"
update_icon()
return TRUE
/obj/machinery/computer/fission_monitor/multitool_act(mob/living/user, obj/item/I)
if(!I.multitool_check_buffer(user))
return
var/obj/item/multitool/multitool = I
if(istype(multitool.buffer, /obj/machinery/atmospherics/fission_reactor))
active = multitool.buffer
to_chat(user, SPAN_NOTICE("You load the buffer's linking data to [src]."))
/obj/machinery/computer/fission_monitor/ui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ReactorMonitor", name)
ui.open()
return TRUE
/obj/machinery/computer/fission_monitor/ui_data(mob/user)
var/list/data = list()
// If we somehow dont have an engine anymore, handle it here.
if(!active)
return
if(active.stat & BROKEN)
active = null
return
var/datum/gas_mixture/air = active.air_contents
var/power_kilowatts = round((active.final_power / 1000), 1)
data["venting"] = active.venting
data["NGCR_integrity"] = active.get_integrity()
data["NGCR_power"] = power_kilowatts
data["NGCR_ambienttemp"] = air.temperature()
data["NGCR_ambientpressure"] = air.return_pressure()
data["NGCR_coefficient"] = active.reactivity_multiplier
if(active.control_lockout)
data["NGCR_throttle"] = 0
else
data["NGCR_throttle"] = 100 - active.desired_power
data["NGCR_operatingpower"] = 100 - active.operating_power
var/list/gasdata = list()
var/TM = air.total_moles()
if(TM)
gasdata.Add(list(list("name" = "Oxygen", "amount" = air.oxygen(), "portion" = round(100 * air.oxygen() / TM, 0.01))))
gasdata.Add(list(list("name" = "Carbon Dioxide", "amount" = air.carbon_dioxide(), "portion" = round(100 * air.carbon_dioxide() / TM, 0.01))))
gasdata.Add(list(list("name" = "Nitrogen", "amount" = air.nitrogen(), "portion" = round(100 * air.nitrogen() / TM, 0.01))))
gasdata.Add(list(list("name" = "Plasma", "amount" = air.toxins(), "portion" = round(100 * air.toxins() / TM, 0.01))))
gasdata.Add(list(list("name" = "Nitrous Oxide", "amount" = air.sleeping_agent(), "portion" = round(100 * air.sleeping_agent() / TM, 0.01))))
gasdata.Add(list(list("name" = "Agent B", "amount" = air.agent_b(), "portion" = round(100 * air.agent_b() / TM, 0.01))))
gasdata.Add(list(list("name" = "Hydrogen", "amount" = air.hydrogen(), "portion" = round(100 * air.hydrogen() / TM, 0.01))))
gasdata.Add(list(list("name" = "Water Vapor", "amount" = air.water_vapor(), "portion" = round(100 * air.water_vapor() / TM, 0.01))))
else
gasdata.Add(list(list("name" = "Oxygen", "amount" = 0, "portion" = 0)))
gasdata.Add(list(list("name" = "Carbon Dioxide", "amount" = 0,"portion" = 0)))
gasdata.Add(list(list("name" = "Nitrogen", "amount" = 0,"portion" = 0)))
gasdata.Add(list(list("name" = "Plasma", "amount" = 0,"portion" = 0)))
gasdata.Add(list(list("name" = "Nitrous Oxide", "amount" = 0,"portion" = 0)))
gasdata.Add(list(list("name" = "Agent B", "amount" = 0,"portion" = 0)))
gasdata.Add(list(list("name" = "Hydrogen", "amount" = 0,"portion" = 0)))
gasdata.Add(list(list("name" = "Water Vapor", "amount" = 0,"portion" = 0)))
data["gases"] = gasdata
data["controlling"] = controller
return data
/obj/machinery/computer/fission_monitor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(..())
return
if(stat & (BROKEN|NOPOWER))
return
if(action == "set_throttle")
if(!controller)
visible_message(SPAN_WARNING("Error: Reactor is out of sight from laser guidance control."))
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE)
return
var/temp_number = text2num(params["NGCR_throttle"])
active.desired_power = 100 - temp_number
if(action == "toggle_vent")
if(!controller)
visible_message(SPAN_WARNING("Error: Reactor is out of sight from laser guidance control."))
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE)
return
if(active.vent_lockout)
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE)
visible_message(SPAN_WARNING("ERROR: Vent servos unresponsive. Manual closure required."))
else
active.venting = !active.venting
// MARK: Slag
/obj/item/slag
name = "corium slag"
desc = "A large clump of active nuclear fuel fused with structural reactor metals."
icon = 'icons/effects/effects.dmi'
icon_state = "big_molten"
move_resist = MOVE_FORCE_STRONG // Massive chunk of metal slag, shouldnt be moving it without carrying.
w_class = WEIGHT_CLASS_HUGE
force = 15
throwforce = 10
/obj/item/slag/Initialize(mapload)
. = ..()
scatter_atom()
var/datum/component/inherent_radioactivity/rad_component = AddComponent(/datum/component/inherent_radioactivity, 5000, 5000, 5000, 2)
START_PROCESSING(SSradiation, rad_component)
START_PROCESSING(SSprocessing, src)
/obj/item/slag/process()
. = ..()
radiation_pulse(src, 500, ALPHA_RAD)
radiation_pulse(src, 500, BETA_RAD)
radiation_pulse(src, 500, GAMMA_RAD)
// MARK: Starter Grenade
/obj/item/grenade/nuclear_starter
name = "Neutronic Agitator"
desc = "A throwable device capable of inducing an artificial startup in rod chambers. Won't do anything for chambers not positioned correctly, or chambers without any rods inserted."
/obj/item/grenade/nuclear_starter/deconstruct(disassembled)
qdel(src)
/obj/item/grenade/nuclear_starter/prime()
playsound(src.loc, 'sound/weapons/bsg_explode.ogg', 50, TRUE, -3)
var/obj/effect/temp_visual/neutronic/warp = new(loc)
warp.pixel_x += 16
warp.pixel_y += 16
warp.transform = matrix().Scale(0.01, 0.01)
animate(warp, time = 0.5 SECONDS, transform = matrix().Scale(1, 1))
var/list/chamber_list = list()
for(var/obj/machinery/atmospherics/reactor_chamber/chamber in range(3, loc))
chamber_list += chamber
for(var/obj/machinery/atmospherics/reactor_chamber/chamber in chamber_list)
if(chamber.chamber_state == CHAMBER_DOWN && chamber.held_rod)
chamber.operational = TRUE
chamber.update_icon(UPDATE_OVERLAYS)
for(var/obj/machinery/atmospherics/reactor_chamber/chamber in chamber_list)
if(chamber.check_status())
chamber.requirements_met = TRUE
else
chamber.requirements_met = FALSE
chamber.update_icon(UPDATE_OVERLAYS)
qdel(src)
/obj/effect/temp_visual/neutronic
icon = 'icons/effects/light_352.dmi'
icon_state = "light"
plane = GRAVITY_PULSE_PLANE
appearance_flags = PIXEL_SCALE|LONG_GLIDE
duration = 0.5 SECONDS
pixel_x = -176
pixel_y = -176
// MARK: Rad Proof Pool
/turf/simulated/floor/plasteel/reactor_pool
name = "holding pool"
icon = 'icons/obj/fission/pool.dmi'
icon_state = "pool_round"
footstep = FOOTSTEP_WATER
barefootstep = FOOTSTEP_WATER
clawfootstep = FOOTSTEP_WATER
heavyfootstep = FOOTSTEP_WATER
/// Holds our pool controller
var/obj/machinery/poolcontroller/linkedcontroller
/// Holds our effect overlay
var/obj/item/effect/pool_overlay/effect
/turf/simulated/floor/plasteel/reactor_pool/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_ATOM_INITIALIZED_ON, PROC_REF(initialized_on))
return INITIALIZE_HINT_LATELOAD
/turf/simulated/floor/plasteel/reactor_pool/LateInitialize()
. = ..()
effect = new(src)
/turf/simulated/floor/plasteel/reactor_pool/crowbar_act(mob/user, obj/item/I)
return
/turf/simulated/floor/plasteel/reactor_pool/proc/initialized_on(atom/A)
SIGNAL_HANDLER // COMSIG_ATOM_INITIALIZED_ON
if(!linkedcontroller)
return
if(istype(A, /obj/effect/decal/cleanable)) // Better a typecheck than looping through thousands of turfs everyday
linkedcontroller.decalinpool += A
/turf/simulated/floor/plasteel/reactor_pool/Entered(atom/movable/AM, atom/OldLoc)
. = ..()
if(!linkedcontroller)
return
if(ismob(AM))
linkedcontroller.mobinpool += AM
/turf/simulated/floor/plasteel/reactor_pool/Exited(atom/movable/AM, direction)
. = ..()
if(!linkedcontroller)
return
if(ismob(AM))
linkedcontroller.mobinpool -= AM
/turf/simulated/floor/plasteel/reactor_pool/ChangeTurf(turf/simulated/floor/T, defer_change, keep_icon, ignore_air, copy_existing_baseturf)
QDEL_NULL(effect)
. = ..()
/turf/simulated/floor/plasteel/reactor_pool/Destroy()
QDEL_NULL(effect)
. = ..()
/turf/simulated/floor/plasteel/reactor_pool/wall
icon_state = "pool_wall_round"
/turf/simulated/floor/plasteel/reactor_pool/wall/ladder
icon_state = "ladder_wall_round"
/turf/simulated/floor/plasteel/reactor_pool/wall/filter
icon_state = "filter_wall_round"
/turf/simulated/floor/plasteel/reactor_pool/square
icon_state = "pool_sharp_square"
/obj/structure/railing/pool_lining
name = "pool lining"
icon = 'icons/obj/fission/pool.dmi'
icon_state = "poolborder"
flags = ON_BORDER | NODECONSTRUCT | INDESTRUCTIBLE
max_integrity = 200
/obj/structure/railing/pool_lining/ex_act(severity)
if(severity == EXPLODE_HEAVY || severity == EXPLODE_DEVASTATE)
qdel(src)
/obj/item/effect/pool_overlay
name = "holding pool"
desc = "water"
icon = 'icons/misc/beach.dmi'
icon_state = "seadeep"
alpha = 75
layer = ABOVE_ALL_MOB_LAYER
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
anchored = TRUE
/obj/structure/railing/corner/pool_corner
name = "pool lining"
icon = 'icons/obj/fission/pool.dmi'
icon_state = "bordercorner"
/obj/structure/railing/corner/pool_corner/inner
icon_state = "innercorner"
/obj/machinery/poolcontroller/invisible/nuclear
srange = 6
deep_water = TRUE
/obj/machinery/poolcontroller/invisible/nuclear/Initialize(mapload)
var/contents_loop = linked_area
if(!linked_area)
contents_loop = range(srange, src)
for(var/turf/simulated/floor/plasteel/reactor_pool/T in contents_loop)
T.linkedcontroller = src
linkedturfs += T
return ..()
/obj/machinery/poolcontroller/invisible/nuclear/Destroy()
for(var/turf/simulated/floor/plasteel/reactor_pool/W in linkedturfs)
if(W.linkedcontroller == src)
W.linkedcontroller = null
return ..()
/obj/machinery/poolcontroller/invisible/nuclear/processMob()
for(var/mob/M in mobinpool)
if(!istype(get_turf(M), /turf/simulated/floor/plasteel/reactor_pool))
mobinpool -= M
continue
M.clean_blood(radiation_clean = TRUE)
if(isliving(M))
var/mob/living/L = M
L.ExtinguishMob()
L.adjust_fire_stacks(-20) //Douse ourselves with water to avoid fire more easily
if(ishuman(M))
handleDrowning(M)
// MARK: Fab upgrade
/obj/item/rod_fabricator_upgrade
name = "Nuclear Fabricator Upgrade"
desc = "A design disk containing a dizzying amount of designs and improvements for nuclear rod fabrication."
icon = 'icons/obj/module.dmi'
icon_state = "datadisk5"
drop_sound = 'sound/items/handling/disk_drop.ogg'
pickup_sound = 'sound/items/handling/disk_pickup.ogg'
new_attack_chain = TRUE
// MARK: Chamber Doors
/obj/effect/temp_visual/chamber_closing
icon = 'icons/obj/fission/reactor_chamber.dmi'
icon_state = "doors_closing"
duration = 0.7 SECONDS
layer = ABOVE_ALL_MOB_LAYER + 0.03
@@ -0,0 +1,546 @@
/obj/item/nuclear_rod
name = "Nuclear Control Rod"
desc = ABSTRACT_TYPE_DESC
icon = 'icons/obj/fission/reactor_rods.dmi'
icon_state = "fuel_238"
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE
w_class = WEIGHT_CLASS_HUGE
force = 15
throwforce = 10
/// The path of the object required to fabricate this rod. leave null for nothing
var/required_object
/// How much durability is left before the rod is useless
var/durability
/// The maximum amount of durability for this rod. Used for percentage calculations
var/max_durability = 3000
/// How fast does this rod degrade? higher = faster
var/degradation_speed = 1
/// How much heat does this rod add by default
var/heat_amount = 0
/// How does this rod affect its neighbors heating
var/heat_amp_mod = 1
/// Holds the current heat mod after durability loss
var/current_heat_mod
/// How much power does this rod add by default in watts
var/power_amount = 0
/// How does this rod affect its neighbors power production
var/power_amp_mod = 1
/// Holds the current power mod after durability loss
var/current_power_mod
/// How much Alpha Rad is emitted by this rod
var/alpha_rad = 0
/// How much Beta Rad is emitted by this rod
var/beta_rad = 0
/// How much Gamma Rad is emitted by this rod
var/gamma_rad = 0
/// What items need to be adjacent to this rod for it to function properly
var/list/adjacent_requirements = list()
/// Modifies the reactor's minimum operating temperature.
var/minimum_temp_modifier = 0
/// Modified the reactor's overheat threshold
var/reactor_overheat_modifier = 0
/// holds our component to modify
var/datum/component/inherent_radioactivity/rad_component
/// Is this rod craftable at all via fabricators, or do they require other means?
var/craftable = FALSE
/// Does this rod require a science-upgraded fabricator?
var/upgrade_required = FALSE
/obj/item/nuclear_rod/Initialize(mapload)
. = ..()
durability = max_durability
/obj/item/nuclear_rod/examine(mob/user)
. = ..()
if(length(adjacent_requirements))
var/list/templist = list()
for(var/obj/item/nuclear_rod/requirement as anything in adjacent_requirements)
templist += initial(requirement.name)
var/requirement_list = english_list(templist, and_text = ", ")
. += "This rod has the following neighbor requirements: [requirement_list]"
else
. += "This rod has no neighbor requirements."
/obj/item/nuclear_rod/proc/get_durability_mod()
var/temp_mod
temp_mod = clamp(1.5 * (durability / max_durability) - 0.25, 0.25, 1)
return temp_mod
/obj/item/nuclear_rod/proc/calc_stat_decrease()
// Formula: y = (x * A) + (1 - A)
var/durability_stat = get_durability_mod()
current_power_mod = (power_amp_mod * durability_stat) + (1 - durability_stat)
current_heat_mod = (heat_amp_mod * durability_stat) + (1 - durability_stat)
/obj/item/nuclear_rod/proc/start_rads(power_modifier = 1)
var/new_alpha_rad = alpha_rad * power_modifier
var/new_beta_rad = beta_rad * power_modifier
var/new_gamma_rad = gamma_rad * power_modifier
rad_component = AddComponent(/datum/component/inherent_radioactivity, new_alpha_rad, new_beta_rad, new_gamma_rad, 1)
START_PROCESSING(SSradiation, rad_component)
/obj/item/nuclear_rod/proc/stop_rads()
if(!rad_component)
return
rad_component.RemoveComponent()
QDEL_NULL(rad_component)
/obj/item/nuclear_rod/proc/change_rad_intensity(power_modifier = 1)
rad_component.radioactivity_alpha = alpha_rad * power_modifier
rad_component.radioactivity_beta = beta_rad * power_modifier
rad_component.radioactivity_gamma = gamma_rad * power_modifier
/obj/item/nuclear_rod/proc/check_rad_shield()
var/turf/T = get_turf(src)
if(!T || !loc)
stop_rads()
return
if(istype(T, /turf/simulated/floor/plasteel/reactor_pool))
if(!rad_component)
return
else
stop_rads()
else if(istype(loc, /obj/machinery/atmospherics/reactor_chamber))
stop_rads()
else if(!rad_component)
start_rads()
/obj/item/nuclear_rod/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change)
. = ..()
check_rad_shield()
/obj/item/nuclear_rod/fuel
name = "any fuel rod"
alpha_rad = 50
/// the amount of cycles needed to complete enrichment. 30 = ~1 minute
var/enrichment_cycles = 25
/// the total power amp mod needed to enrich
var/power_enrich_threshold = 0
/// How far we have progressed from to power enrichment
var/power_enrich_progress = 0
/// What power enrichment results in
var/power_enrich_result
/// the total heat amp mod needed to enrich
var/heat_enrich_threshold = 0
/// How far we have progressed from to power enrichment
var/heat_enrich_progress = 0
/// What heat enrichment results in
var/heat_enrich_result
/obj/item/nuclear_rod/fuel/Initialize(mapload)
. = ..()
if(!istype(loc, /obj/structure/closet/crate))
check_rad_shield()
/obj/item/nuclear_rod/fuel/proc/enrich(power_mod, heat_mod)
var/successful_enrichment = FALSE
if(power_enrich_result)
if(power_mod > power_enrich_threshold && power_enrich_progress < enrichment_cycles)
power_enrich_progress++
successful_enrichment = TRUE
if(heat_enrich_result)
if(heat_mod > heat_enrich_threshold && heat_enrich_progress < enrichment_cycles)
heat_enrich_progress++
successful_enrichment = TRUE
return successful_enrichment
// MARK: Fuel Rods
/obj/item/nuclear_rod/fuel/uranium_238
name = "uranium 238 fuel rod"
desc = "A standard fuel rod for most NGCR reactors. Has just barely enough Uranium 235 to be useful."
heat_amount = 5
power_amount = 20 KW
heat_amp_mod = 1.8
power_amp_mod = 1.1
alpha_rad = 200
beta_rad = 100
heat_enrich_threshold = 10 // all uranium rods surrounding: 1.8 x 1.8 x 1.8 x 1.8
power_enrich_threshold = 6.4 // all graphite rods surrounding: 1.6 x 1.6 x 1.6 x 1.6
heat_enrich_result = /obj/item/nuclear_rod/fuel/weak_thorium
power_enrich_result = /obj/item/nuclear_rod/fuel/weak_plutonium
adjacent_requirements = list(/obj/item/nuclear_rod/moderator)
craftable = TRUE
materials = list(MAT_METAL = 2000, MAT_URANIUM = 1000)
/obj/item/nuclear_rod/fuel/weak_thorium
name = "weak thorium fuel rod"
desc = "A specialized fuel rod refined from uranium 238. This rod will last longer than normal, and won't generate as much heat."
icon_state = "fuel_weakthor"
heat_amount = 5
power_amount = 20 KW
heat_amp_mod = 1.6
power_amp_mod = 1.1
max_durability = 5000
beta_rad = 100
gamma_rad = 100
power_enrich_threshold = 8
power_enrich_result = /obj/item/nuclear_rod/fuel/uranium_235
adjacent_requirements = list(
/obj/item/nuclear_rod/moderator,
/obj/item/nuclear_rod/coolant,
)
/obj/item/nuclear_rod/fuel/weak_plutonium
name = "weak plutonium fuel rod"
desc = "A specialized fuel rod refined from uranium 238. This rod produces twice as much power as standard uranium 238 fuel, but has higher operating requirements."
icon_state = "fuel_weakplut"
heat_amount = 10
power_amount = 40 KW
heat_amp_mod = 1.6
power_amp_mod = 1.1
max_durability = 3500
gamma_rad = 100
heat_enrich_threshold = 14
heat_enrich_result = /obj/item/nuclear_rod/fuel/uranium_235
adjacent_requirements = list(
/obj/item/nuclear_rod/fuel,
/obj/item/nuclear_rod/moderator,
/obj/item/nuclear_rod/coolant,
)
/obj/item/nuclear_rod/fuel/uranium_235
name = "uranium 235 fuel rod"
desc = "An advanced fuel rod for most NGCR reactors, formed from high-density uranium 235 isotopes."
icon_state = "fuel_235"
heat_amount = 20
power_amount = 50 KW
heat_amp_mod = 2.2
power_amp_mod = 1.3
max_durability = 5000
alpha_rad = 150
beta_rad = 100
heat_enrich_threshold = 25
power_enrich_threshold = 18
heat_enrich_result = /obj/item/nuclear_rod/fuel/thorium_salts
power_enrich_result = /obj/item/nuclear_rod/fuel/enriched_plutonium
origin_tech = "toxins=2"
craftable = TRUE
upgrade_required = TRUE
adjacent_requirements = list(
/obj/item/nuclear_rod/coolant/plasma_injector,
/obj/item/nuclear_rod/moderator,
/obj/item/nuclear_rod/moderator,
)
materials = list(MAT_METAL = 4000, MAT_URANIUM = 4000)
/obj/item/nuclear_rod/fuel/thorium_salts
name = "thorium salts fuel rod"
desc = "A specialized fuel rod refined from uranium 235. While this rod doesn't have any notable power boosts, its amazingly large integrity makes it virtually impossible to deplete in a single shift, if one can manage its heat."
icon_state = "fuel_richthor"
heat_amount = 40
power_amount = 35 KW
heat_amp_mod = 2.2
power_amp_mod = 1.3
max_durability = 15000
beta_rad = 250
adjacent_requirements = list(
/obj/item/nuclear_rod/moderator,
/obj/item/nuclear_rod/fuel/uranium_235,
/obj/item/nuclear_rod/fuel,
)
/obj/item/nuclear_rod/fuel/enriched_plutonium
name = "enriched plutonium fuel rod"
desc = "A specialized fuel rod refined from uranium 235. This rod is extremely powerful, boasting high power outputs and moderate durability. However, its heat presents an exceptional danger."
icon_state = "fuel_richplut"
heat_amount = 60
power_amount = 75 KW
heat_amp_mod = 4
power_amp_mod = 1.6
max_durability = 5000
beta_rad = 250
power_enrich_threshold = 25
power_enrich_result = /obj/item/nuclear_rod/fuel/americium
adjacent_requirements = list(
/obj/item/nuclear_rod/moderator/plasma_agitator,
/obj/item/nuclear_rod/fuel/thorium_salts,
)
/obj/item/nuclear_rod/fuel/supermatter
name = "supermatter fuel rod"
desc = "A dangerous fuel rod made entirely of supermatter, contained safely in a specialized housing case. Due to its unusual properties, it completely neutralizes any potential power from nearby rods."
icon_state = "fuel_sm"
heat_amount = 1200
power_amount = 800 KW
heat_amp_mod = 8
power_amp_mod = 0.1
max_durability = INFINITY
gamma_rad = 300
adjacent_requirements = list(
/obj/item/nuclear_rod/coolant/steam_hammerjet,
/obj/item/nuclear_rod/fuel,
/obj/item/nuclear_rod/moderator,
)
/obj/item/nuclear_rod/fuel/americium
name = "americium fuel rod"
desc = "A specialized fuel rod refined from enriched plutonium. A pinnacle of power generation, this rod's power generation is nearly unmatched if one can tame its vicious heat output."
icon_state = "fuel_americium"
heat_amount = 100
power_amount = 200 KW
heat_amp_mod = 6
power_amp_mod = 1.6
max_durability = 4000
gamma_rad = 300
adjacent_requirements = list(
/obj/item/nuclear_rod/fuel,
/obj/item/nuclear_rod/fuel,
)
/obj/item/nuclear_rod/fuel/bananium
name = "bananium fuel rod"
desc = "The funniest of all fuel rods with no solidified properties. Who knows what you might get out of it!"
icon_state = "fuel_clown"
gamma_rad = 300
craftable = TRUE
upgrade_required = TRUE
materials = list(MAT_TITANIUM = 2000, MAT_BANANIUM = 2000)
/obj/item/nuclear_rod/fuel/bananium/Initialize(mapload)
max_durability = rand(1000, 10000)
power_amp_mod = rand(1, 40) / 10
heat_amp_mod = rand(5, 80) / 10
power_amount = rand(10 KW, 200 KW)
heat_amount = rand(10, 500)
return ..()
/obj/item/nuclear_rod/fuel/meltdown
name = "meltdown rod"
desc = "A Syndicate-crafted rod capable of generating massive amounts of heat, leading to an eventual meltdown."
icon_state = "fuel_syndie"
heat_amount = 2000
max_durability = INFINITY
minimum_temp_modifier = 4000 // BIG hot
reactor_overheat_modifier = -400
alpha_rad = 250
beta_rad = 250
gamma_rad = 250
// MARK: Moderator Rods
/obj/item/nuclear_rod/moderator
name = "any moderator rod"
icon_state = "mod_water"
/obj/item/nuclear_rod/moderator/heavy_water
name = "heavy water moderator"
desc = "A basic moderation rod filled with a variant of water comprised of deuterium instead of hydrogen atoms."
heat_amp_mod = 1.1
power_amp_mod = 1.4
craftable = TRUE
materials = list(MAT_METAL = 2000, MAT_GLASS = 1000)
/obj/item/nuclear_rod/moderator/graphite
name = "graphite moderator"
desc = "A nuclear moderation rod comprised primarily of layered graphite. A staple of fission reactor operation through the ages."
icon_state = "mod_graphite"
heat_amp_mod = 1.3
power_amp_mod = 1.6
craftable = TRUE
materials = list(MAT_METAL = 4000, MAT_PLASMA = 2000)
adjacent_requirements = list(/obj/item/nuclear_rod/coolant)
/obj/item/nuclear_rod/moderator/titanium
name = "titanium moderator"
desc = "A nuclear moderation rod comprised primarily of cast titanium. For what it lacks in power amplification, it makes up for in versatility and durability."
icon_state = "mod_titanium"
max_durability = 5000
heat_amp_mod = 1.1
power_amp_mod = 1.3
craftable = TRUE
materials = list(MAT_METAL = 2000, MAT_TITANIUM = 2000)
/obj/item/nuclear_rod/moderator/plasma_agitator
name = "plasma agitator"
desc = "A specialized moderator rod capable of inducing higher fission rates in fuel rods through a series of micro-burns. It doesn't last long."
icon_state = "mod_plasma"
max_durability = 2250
heat_amount = 20
heat_amp_mod = 5
power_amp_mod = 3
adjacent_requirements = list(
/obj/item/nuclear_rod/fuel,
/obj/item/nuclear_rod/fuel,
/obj/item/nuclear_rod/moderator,
)
/obj/item/nuclear_rod/moderator/aluminum_reflector
name = "liquid aluminum plate reflector"
desc = "A specialized moderator rod for amplifying the power output of nearby fuel rods. However, the temperature of the liquid aluminum will force the reactor to run hot."
icon_state = "mod_aluminium"
max_durability = 6000
power_amount = -15 KW
heat_amp_mod = 5
power_amp_mod = 3
minimum_temp_modifier = 400
reactor_overheat_modifier = 100
adjacent_requirements = list(
/obj/item/nuclear_rod/coolant/nitrogen_circulator,
/obj/item/nuclear_rod/moderator,
)
/obj/item/nuclear_rod/moderator/bluespace_agitator
name = "bluespace crystal agitator"
desc = "An advanced moderator rod that will pull extra neutrons out of bluespace to bombard local fuel rods. The result is a massive increase of power and heat generation. It is exceptionally versatile; however, its power requirements limit its uses."
icon_state = "mod_bluespace"
max_durability = 4000
power_amount = -30 KW
heat_amp_mod = 12
power_amp_mod = 5
upgrade_required = TRUE
craftable = TRUE
materials = list(MAT_METAL = 2000, MAT_TITANIUM = 1000, MAT_BLUESPACE = 1000)
/obj/item/nuclear_rod/moderator/diamond_plate
name = "diamond reflector plates"
desc = "An advanced moderator rod that can reflect nearly all neutrons back to their point of origin. Simple, stable, reliable."
icon_state = "mod_diamond"
max_durability = 6000
heat_amp_mod = 6.5
power_amp_mod = 3.3
reactor_overheat_modifier = 100
craftable = TRUE
upgrade_required = TRUE
materials = list(MAT_METAL = 2000, MAT_TITANIUM = 1000, MAT_DIAMOND = 1000)
adjacent_requirements = list(
/obj/item/nuclear_rod/fuel,
/obj/item/nuclear_rod/fuel,
/obj/item/nuclear_rod/fuel,
)
/obj/item/nuclear_rod/moderator/platinum_plating
name = "platinum reflector plating"
desc = "An advanced moderator similar to diamond plates, but improved with precious space metals."
icon_state = "mod_platinum"
max_durability = 8000
heat_amp_mod = 8
power_amp_mod = 3.9
reactor_overheat_modifier = 300
adjacent_requirements = list(/obj/item/nuclear_rod/fuel/americium)
/// MARK: Coolant Rods
/obj/item/nuclear_rod/coolant
name = "any coolant rod"
icon_state = "coolant_water"
/obj/item/nuclear_rod/coolant/light_water
name = "light water circulator"
desc = "A basic coolant rod that circulates distilled water through critical reactor components."
heat_amount = -10
power_amount = -10 KW
reactor_overheat_modifier = 25
craftable = TRUE
adjacent_requirements = list(/obj/item/nuclear_rod/moderator)
materials = list(MAT_METAL = 2000, MAT_GLASS = 1000)
/obj/item/nuclear_rod/coolant/co2_regulator
name = "carbon dioxide regulator"
desc = "A specialized coolant rod filled with carbon dioxide gas, capable of regulating temperature spikes in fuel rods. However, it's very energy inefficient."
icon_state = "coolant_carbon"
heat_amount = -4
heat_amp_mod = 0.6
power_amount = -15 KW
craftable = TRUE
adjacent_requirements = list(/obj/item/nuclear_rod/moderator)
materials = list(MAT_METAL = 2000, MAT_PLASMA = 2000, MAT_GLASS = 1000)
/obj/item/nuclear_rod/coolant/plasma_injector
name = "plasma injector"
desc = "A specialized coolant rod filled with gaseous plasma. By taking advantage of plasma's unique heat-absorbent properties, small amounts injected around fuel rods neutralize excess heat. However, the tank runs out quickly this way."
icon_state = "coolant_plasma"
max_durability = 1900
heat_amp_mod = 0.5
power_amp_mod = 1.5
craftable = TRUE
adjacent_requirements = list(/obj/item/nuclear_rod/coolant)
materials = list(MAT_METAL = 2000, MAT_PLASMA = 2000, MAT_GLASS = 1000)
/obj/item/nuclear_rod/coolant/nitrogen_circulator
name = "nitrogen circulator"
desc = "A specialized coolant rod filled with nitrogen gas. While not as powerful as similar alternatives, this rod is exceptionally stable and will last longer."
icon_state = "coolant_nitrogen"
max_durability = 3500
heat_amount = -10
power_amp_mod = 0.9
heat_amp_mod = 0.7
craftable = TRUE
reactor_overheat_modifier = 50
power_amount = -5 KW
materials = list(MAT_METAL = 2000, MAT_PLASMA = 2000, MAT_GLASS = 1000)
/obj/item/nuclear_rod/coolant/molten_salt
name = "molten salt circulator"
desc = "A specialized coolant rod that circulates molten salts through the core of the reactor. Despite forcing the reactor to run exceptionally hot, this rod provides top-notch cooling potential above its resting temperature."
icon_state = "coolant_salt"
power_amount = -20 KW
heat_amount = -60
heat_amp_mod = 0.8
max_durability = 8000
minimum_temp_modifier = 750
reactor_overheat_modifier = 100
materials = list(MAT_METAL = 2000, MAT_PLASMA = 2000, MAT_GLASS = 1000)
adjacent_requirements = list(
/obj/item/nuclear_rod/coolant/nitrogen_circulator,
/obj/item/nuclear_rod/moderator,
/obj/item/nuclear_rod/fuel,
/obj/item/nuclear_rod/fuel,
)
/obj/item/nuclear_rod/coolant/steam_hammerjet
name = "steam hammerjet"
desc = "A specialized coolant rod that injects distilled steam throughout the reactor's critical components. Although it makes the reactor run warm, it's very good at suppressing heat buildup."
icon_state = "coolant_steam"
power_amount = -10 KW
heat_amount = -40
heat_amp_mod = 0.4
max_durability = 6000
minimum_temp_modifier = 450
reactor_overheat_modifier = 100
adjacent_requirements = list(
/obj/item/nuclear_rod/coolant/light_water,
/obj/item/nuclear_rod/coolant/light_water,
)
/obj/item/nuclear_rod/coolant/bluespace_displacer
name = "bluespace heat displacer"
desc = "An advanced coolant rod capable of pulling heat directly out of neighboring rods and sending it... somewhere."
icon_state = "coolant_bluespace"
power_amount = -40 KW
heat_amount = -100
heat_amp_mod = 0.8
power_amp_mod = 1.3
max_durability = INFINITY
reactor_overheat_modifier = 200
craftable = TRUE
upgrade_required = TRUE
materials = list(MAT_METAL = 2000, MAT_PLASMA = 2000, MAT_BLUESPACE = 1000)
adjacent_requirements = list(/obj/item/nuclear_rod/moderator/bluespace_agitator)
/obj/item/nuclear_rod/coolant/iridium_conductor
name = "iridium conductor coolant rod"
desc = "A dazzlingly beautiful rod with exceptionally powerful thermal conductivity. A highly sought after piece of equipment for its simplicity and potency."
icon_state = "coolant_iridium"
heat_amp_mod = 0.1
max_durability = 10000
reactor_overheat_modifier = 300
adjacent_requirements = list(
/obj/item/nuclear_rod/moderator/aluminum_reflector,
/obj/item/nuclear_rod/fuel/uranium_235,
)
/obj/item/nuclear_rod/coolant/condensed_spacematter
name = "condensed spacematter coolant rod"
desc = "While it's unknown quite what the rod is filled with, there's no questioning its heat-suppressing efficiency. However, it violently disintegrates in contact with anything that isn't its housing."
icon_state = "coolant_spacematter"
heat_amount = -1500
heat_amp_mod = 0.2
materials = list(MAT_METAL = 6000, MAT_PLASMA = 4000, MAT_TITANIUM = 2000)
craftable = TRUE
upgrade_required = TRUE
adjacent_requirements = list(
/obj/item/nuclear_rod/fuel/enriched_plutonium,
/obj/item/nuclear_rod/fuel/thorium_salts,
)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,470 @@
#define DEFAULT_OPERATION_TIME 10 SECONDS //! The base amount of time needed to craft an item
/// MARK: Centrifuge
/obj/machinery/nuclear_centrifuge
name = "Fuel Enrichment Centrifuge"
desc = "An advanced device capable of separating and collecting fissile materials from enriched fuel rods."
icon = 'icons/obj/fission/reactor_machines.dmi'
icon_state = "centrifuge_empty"
idle_power_consumption = 200
active_power_consumption = 3000
anchored = TRUE
density = TRUE
resistance_flags = FIRE_PROOF | FREEZE_PROOF
armor = list(melee = 25, bullet = 10, laser = 30, energy = 0, bomb = 0, rad = INFINITY, fire = INFINITY, acid = 70)
/// The time it takes for the machine to process a rod
var/work_time
/// The averaged amount of all stock parts
var/average_component_rating
/// The result when we are done operating
var/rod_result
/// Holds the rod object inserted into the machine
var/obj/item/nuclear_rod/held_rod
/// the soundloop we will be using while operating
var/datum/looping_sound/centrifuge/soundloop
COOLDOWN_DECLARE(enrichment_timer)
/obj/machinery/nuclear_centrifuge/Initialize(mapload)
. = ..()
soundloop = new(list(src), FALSE)
component_parts = list()
component_parts += new /obj/item/circuitboard/nuclear_centrifuge(src)
component_parts += new /obj/item/stock_parts/manipulator(src)
component_parts += new /obj/item/stock_parts/manipulator(src)
component_parts += new /obj/item/stock_parts/manipulator(src)
component_parts += new /obj/item/stock_parts/manipulator(src)
RefreshParts()
update_icon(UPDATE_OVERLAYS)
/obj/machinery/nuclear_centrifuge/examine(mob/user)
. = ..()
if(held_rod)
. += SPAN_NOTICE("The current fuel rod may be removed with <b>Alt-Click</b>.")
/obj/machinery/nuclear_centrifuge/Destroy()
QDEL_NULL(soundloop)
return ..()
/obj/machinery/nuclear_centrifuge/RefreshParts()
average_component_rating = 0
for(var/obj/item/stock_parts/manipulator/part in component_parts)
average_component_rating += part.rating
average_component_rating /= 4 // average all 4 components
work_time = DEFAULT_OPERATION_TIME / average_component_rating
/obj/machinery/nuclear_centrifuge/item_interaction(mob/living/user, obj/item/used, list/modifiers)
. = ..()
if(!istype(used, /obj/item/nuclear_rod/fuel))
return CONTINUE_ATTACK
if(stat & NOPOWER)
return ITEM_INTERACT_COMPLETE
if(panel_open)
to_chat(user, SPAN_WARNING("You must close the access panel first!"))
return ITEM_INTERACT_COMPLETE
if(power_state == ACTIVE_POWER_USE) // dont start a new cycle when on
to_chat(user, SPAN_WARNING("There is already a fuel rod being processed!"))
return ITEM_INTERACT_COMPLETE
var/obj/item/nuclear_rod/fuel/rod = used
var/list/enrichment_to_name = list()
var/list/radial_list = list()
var/obj/item/nuclear_rod/fuel/rod_enrichment
if(rod.power_enrich_progress >= rod.enrichment_cycles && rod.power_enrich_result)
rod_enrichment = rod.power_enrich_result
enrichment_to_name["[rod_enrichment::name]"] = rod_enrichment
radial_list["[rod_enrichment::name]"] = image(icon = rod_enrichment::icon, icon_state = rod_enrichment::icon_state)
if(rod.heat_enrich_progress >= rod.enrichment_cycles && rod.heat_enrich_result)
rod_enrichment = rod.heat_enrich_result
enrichment_to_name["[rod_enrichment::name]"] = rod_enrichment
radial_list["[rod_enrichment::name]"] = image(icon = rod_enrichment::icon, icon_state = rod_enrichment::icon_state)
if(!length(radial_list))
to_chat(user, SPAN_WARNING("This rod has no potential for enrichment!"))
return ITEM_INTERACT_COMPLETE
var/enrichment_choice = show_radial_menu(user, src, radial_list, src, radius = 30, require_near = TRUE)
if(!enrichment_choice)
return ITEM_INTERACT_COMPLETE
rod_result = enrichment_to_name[enrichment_choice]
held_rod = rod
user.transfer_item_to(rod, src)
begin_enrichment()
return ITEM_INTERACT_COMPLETE
/obj/machinery/nuclear_centrifuge/AltClick(mob/user, modifiers)
if(!held_rod)
return
if(power_state == ACTIVE_POWER_USE)
to_chat(user, SPAN_WARNING("You cannot remove the fuel rod while the machine is running!"))
return
held_rod.forceMove(get_turf(src))
held_rod = null
icon_state = "centrifuge_empty"
playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
/obj/machinery/nuclear_centrifuge/process()
if(stat & NOPOWER)
if(power_state == ACTIVE_POWER_USE)
abort_enrichment()
return
if(power_state == IDLE_POWER_USE)
return
if(!COOLDOWN_FINISHED(src, enrichment_timer))
return
finish_enrichment()
/obj/machinery/nuclear_centrifuge/screwdriver_act(mob/user, obj/item/I)
. = TRUE
if(held_rod)
to_chat(user, SPAN_WARNING("The machine cannot be opened while it contains a fuel rod!"))
return ITEM_INTERACT_COMPLETE
default_deconstruction_screwdriver(user, "centrifuge_maint", "centrifuge_empty", I)
/obj/machinery/nuclear_centrifuge/proc/begin_enrichment()
power_state = ACTIVE_POWER_USE
icon_state = "centrifuge_on"
COOLDOWN_START(src, enrichment_timer, work_time)
soundloop.start()
/obj/machinery/nuclear_centrifuge/proc/abort_enrichment()
power_state = IDLE_POWER_USE
icon_state = "centrifuge_full"
playsound(src, 'sound/machines/buzz-sigh.ogg', 30, TRUE)
soundloop.stop()
/obj/machinery/nuclear_centrifuge/proc/finish_enrichment()
icon_state = "centrifuge_full"
playsound(src, 'sound/machines/ping.ogg', 30, TRUE)
power_state = IDLE_POWER_USE
var/new_rod = new rod_result(contents)
rod_result = null
QDEL_NULL(held_rod)
held_rod = new_rod
soundloop.stop()
// MARK: Rod Fabricator
/obj/machinery/nuclear_rod_fabricator
name = "Nuclear Fuel Rod Fabricator"
desc = "A highly specialized fabricator for crafting nuclear rods."
icon = 'icons/obj/fission/reactor_machines.dmi'
icon_state = "rod_fab"
idle_power_consumption = 50
active_power_consumption = 3000
density = TRUE
resistance_flags = FIRE_PROOF | FREEZE_PROOF
armor = list(melee = 25, bullet = 10, laser = 30, energy = 0, bomb = 0, rad = INFINITY, fire = INFINITY, acid = 70)
/// Our holder for materials
var/datum/component/material_container/materials
/// How fast do we operate and/or do we get extra rods
var/efficiency_coeff = 1
/// The list for carrying fuel rods
var/list/category_fuel = list()
/// The list for carrying moderator rods
var/list/category_moderator = list()
/// The list for carrying coolant rods
var/list/category_coolant = list()
/// Is the rod fabricator currently upgraded from science
var/upgraded = FALSE
/// What is the current item being produced
var/schematic
/// The time it takes for the machine to process a rod
var/work_time
COOLDOWN_DECLARE(fabrication_timer)
/obj/machinery/nuclear_rod_fabricator/upgraded
upgraded = TRUE
/obj/machinery/nuclear_rod_fabricator/Initialize(mapload)
. = ..()
materials = AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TRANQUILLITE, MAT_TITANIUM, MAT_BLUESPACE, MAT_PLASTIC), 0, TRUE, /obj/item/stack, CALLBACK(src, PROC_REF(is_insertion_ready)), CALLBACK(src, PROC_REF(AfterMaterialInsert)))
materials.precise_insertion = TRUE
component_parts = list()
component_parts += new /obj/item/circuitboard/nuclear_rod_fabricator(src)
component_parts += new /obj/item/stock_parts/matter_bin(src)
component_parts += new /obj/item/stock_parts/matter_bin(src)
component_parts += new /obj/item/stock_parts/manipulator(src)
component_parts += new /obj/item/stock_parts/manipulator(src)
RefreshParts()
create_designs()
/obj/machinery/nuclear_rod_fabricator/RefreshParts()
var/temp_coeff = 12
var/average_component_rating = 0
for(var/obj/item/stock_parts/manipulator/M in component_parts)
temp_coeff -= M.rating
average_component_rating += M.rating
work_time = DEFAULT_OPERATION_TIME / average_component_rating
efficiency_coeff = clamp(temp_coeff / 10, 0.05, 1)
temp_coeff = 0
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
temp_coeff += M.rating
materials.max_amount = temp_coeff * 75000
/obj/machinery/nuclear_rod_fabricator/attack_ghost(mob/user)
return attack_hand(user)
/obj/machinery/nuclear_rod_fabricator/proc/is_insertion_ready(mob/user)
if(panel_open)
to_chat(user, SPAN_WARNING("You can't load [src] while it's opened!"))
return FALSE
if(stat & BROKEN)
to_chat(user, SPAN_WARNING("[src] is broken."))
return FALSE
if(stat & NOPOWER)
to_chat(user, SPAN_WARNING("[src] has no power."))
return FALSE
return TRUE
/obj/machinery/nuclear_rod_fabricator/proc/AfterMaterialInsert(type_inserted, id_inserted, amount_inserted)
var/stack_name
if(ispath(type_inserted, /obj/item/stack/ore/bluespace_crystal))
stack_name = "bluespace"
use_power(MINERAL_MATERIAL_AMOUNT / 10)
else
var/obj/item/stack/S = type_inserted
stack_name = initial(S.name)
use_power(min(1000, (amount_inserted / 100)))
add_overlay("protolathe_[stack_name]")
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, cut_overlay), "protolathe_[stack_name]"), 10)
/obj/machinery/nuclear_rod_fabricator/proc/check_mat(obj/item/nuclear_rod/being_built, M)
var/A = materials.amount(M)
if(!A)
visible_message(SPAN_WARNING("Something has gone very wrong. Alert a developer."))
return
else
A /= max(1, (being_built.materials[M] * efficiency_coeff))
return A
/obj/machinery/nuclear_rod_fabricator/item_interaction(mob/living/user, obj/item/used, list/modifiers)
if(istype(used, /obj/item/storage/part_replacer))
return ..()
if(panel_open)
to_chat(user, SPAN_WARNING("You can't load [src] while the maintenance panel is opened."))
return ITEM_INTERACT_COMPLETE
if(istype(used, /obj/item/rod_fabricator_upgrade))
upgraded = TRUE
create_designs()
user.drop_item(used)
qdel(used)
return ITEM_INTERACT_COMPLETE
return ..()
/obj/machinery/nuclear_rod_fabricator/crowbar_act(mob/living/user, obj/item/I)
if(!panel_open)
return
. = TRUE
materials.retrieve_all()
default_deconstruction_crowbar(user, I)
/obj/machinery/nuclear_rod_fabricator/on_deconstruction()
if(upgraded)
new /obj/item/rod_fabricator_upgrade(loc)
return ..()
/obj/machinery/nuclear_rod_fabricator/proc/create_designs()
category_fuel = list()
category_moderator = list()
category_coolant = list()
for(var/obj/rod_path as anything in subtypesof(/obj/item/nuclear_rod))
if(initial(rod_path.desc) == ABSTRACT_TYPE_DESC)
continue
var/datum/nuclear_rod_design/D = new /datum/nuclear_rod_design()
D.build_metadata_list(rod_path)
if(!D.metadata["craftable"])
continue
if(D.metadata["upgrade_required"] && !upgraded)
continue
if(ispath(rod_path, /obj/item/nuclear_rod/fuel))
category_fuel += D
else if(ispath(rod_path, /obj/item/nuclear_rod/moderator))
category_moderator += D
else if(ispath(rod_path, /obj/item/nuclear_rod/coolant))
category_coolant += D
/obj/machinery/nuclear_rod_fabricator/ui_data(mob/user)
var/list/data = list()
data["fuel_rods"] = list()
for(var/datum/nuclear_rod_design/D in category_fuel)
data["fuel_rods"] += list(D.metadata)
data["moderator_rods"] = list()
for(var/datum/nuclear_rod_design/D in category_moderator)
data["moderator_rods"] += list(D.metadata)
data["coolant_rods"] = list()
for(var/datum/nuclear_rod_design/D in category_coolant)
data["coolant_rods"] += list(D.metadata)
// Add available resources from the material container
data["resources"] = list()
if(materials)
// Get all material types that the fabricator supports
var/list/supported_materials = list(
MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA,
MAT_URANIUM, MAT_TITANIUM, MAT_BLUESPACE, MAT_PLASTIC, MAT_BANANIUM, MAT_TRANQUILLITE
)
for(var/mat_id in supported_materials)
var/amount = materials.amount(mat_id)
if(amount > 0)
var/sheets = round(amount / MINERAL_MATERIAL_AMOUNT)
var/display_name = CallMaterialName(mat_id)
data["resources"][display_name] = list(
"amount" = amount,
"sheets" = sheets,
"id" = mat_id
)
return data
/obj/machinery/nuclear_rod_fabricator/attack_hand(mob/user)
ui_interact(user)
/obj/machinery/nuclear_rod_fabricator/interact(mob/user)
. = ..()
if(panel_open)
to_chat(user, SPAN_WARNING("You can't access [src] while it's opened!"))
return
/obj/machinery/nuclear_rod_fabricator/ui_state(mob/user)
return GLOB.default_state
/obj/machinery/nuclear_rod_fabricator/ui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "NuclearRodFabricator", name)
ui.open()
/obj/machinery/nuclear_rod_fabricator/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(..())
return
switch(action)
if("fabricate_rod")
var/rod_type_path = text2path(params["type_path"])
if(!rod_type_path)
return FALSE
var/datum/nuclear_rod_design/selected_design
for(var/datum/nuclear_rod_design/D in category_fuel + category_moderator + category_coolant)
if(D.type_path == rod_type_path)
selected_design = D
break
if(!selected_design)
return FALSE
if(power_state == ACTIVE_POWER_USE)
to_chat(usr, SPAN_WARNING("A rod is already being fabricated!"))
return FALSE
// Check if we have enough materials
var/obj/item/nuclear_rod/temp_rod = new rod_type_path()
var/list/required_materials = temp_rod.materials
qdel(temp_rod)
if(!required_materials || !length(required_materials))
to_chat(usr, SPAN_WARNING("This rod design has no material requirements defined - please create an issue report!"))
return FALSE
for(var/mat_id in required_materials)
var/required_amount = required_materials[mat_id] * efficiency_coeff
if(materials.amount(mat_id) < required_amount)
to_chat(usr, SPAN_WARNING("Not enough materials! Need [required_amount] units of [mat_id]!"))
return FALSE
// Spend materials
var/list/materials_to_use = list()
for(var/mat_id in required_materials)
materials_to_use[mat_id] = required_materials[mat_id] * efficiency_coeff
if(!materials.use_amount(materials_to_use))
to_chat(usr, SPAN_WARNING("Failed to deduct materials!"))
return FALSE
// Begin Process
begin_fabrication(rod_type_path)
return TRUE
if("eject_material")
var/material_id = params["id"]
var/amount = params["amount"]
if(!material_id || !materials.materials[material_id])
return FALSE
var/desired_sheets = 0
if(amount == "custom")
var/datum/material/M = materials.materials[material_id]
var/max_sheets = round(M.amount / MINERAL_MATERIAL_AMOUNT)
if(max_sheets <= 0)
to_chat(usr, SPAN_WARNING("Not enough [M.name] to eject!"))
return FALSE
desired_sheets = tgui_input_number(usr, "How many sheets do you want to eject?", "Ejecting [M.name]", 1, max_sheets, 1)
if(isnull(desired_sheets))
return FALSE
else
desired_sheets = text2num(amount)
desired_sheets = max(0, round(desired_sheets))
if(desired_sheets > 0)
materials.retrieve_sheets(desired_sheets, material_id, get_turf(src))
to_chat(usr, SPAN_NOTICE("[src] ejects [desired_sheets] sheets."))
return TRUE
return FALSE
/obj/machinery/nuclear_rod_fabricator/screwdriver_act(mob/user, obj/item/I)
. = TRUE
if(power_state == ACTIVE_POWER_USE)
to_chat(user, SPAN_WARNING("The machine cannot be opened while it is operating!"))
return ITEM_INTERACT_COMPLETE
default_deconstruction_screwdriver(user, "rod_fab_maint", "rod_fab", I)
/obj/machinery/nuclear_rod_fabricator/proc/begin_fabrication(rod_type_path)
power_state = ACTIVE_POWER_USE
icon_state = "rod_fab_on"
COOLDOWN_START(src, fabrication_timer, work_time)
schematic = rod_type_path
/obj/machinery/nuclear_rod_fabricator/proc/finish_fabrication()
power_state = IDLE_POWER_USE
icon_state = "rod_fab"
var/obj/item/nuclear_rod/new_rod = new schematic(get_turf(src))
src.visible_message(SPAN_NOTICE("[src] fabricates \a [new_rod.name]."))
playsound(src, 'sound/machines/ping.ogg', 50, TRUE)
/obj/machinery/nuclear_rod_fabricator/proc/abort_fabrication()
power_state = IDLE_POWER_USE
icon_state = "rod_fab"
playsound(src, 'sound/machines/buzz-sigh.ogg', 30, TRUE)
/obj/machinery/nuclear_rod_fabricator/process()
if(stat & NOPOWER)
if(power_state == ACTIVE_POWER_USE)
abort_fabrication()
return
if(power_state == IDLE_POWER_USE)
return
if(!COOLDOWN_FINISHED(src, fabrication_timer))
return
finish_fabrication()
#undef DEFAULT_OPERATION_TIME
@@ -0,0 +1,810 @@
#define CHAMBER_HEAT_DAMAGE 15 //! How much damage reactor chambers do when on.
/obj/machinery/atmospherics/reactor_chamber
name = "rod housing chamber"
desc = "A chamber used to house nuclear rods of various types to facilitate a fission reaction."
icon = 'icons/obj/fission/reactor_chamber.dmi'
icon_state = "chamber_down"
layer = BELOW_OBJ_LAYER
pass_flags_self = PASSTAKE
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF | FREEZE_PROOF
max_integrity = 400
armor = list(melee = 80, bullet = 30, laser = 30, energy = 10, bomb = 40, rad = INFINITY, fire = INFINITY, acid = INFINITY) // Fairly robust
idle_power_consumption = 100
flags_2 = NO_MALF_EFFECT_2
/// Each reactor chamber can only be linked to a single reactor, if somehow theres two.
var/obj/machinery/atmospherics/fission_reactor/linked_reactor
/// Holds the specific rod inserted into the chamber
var/obj/item/nuclear_rod/held_rod
/// Is the chamber up, down, or open
var/chamber_state = 1
/// Has the requirements for the rod inside this chamber been met?
var/requirements_met = FALSE
/// Is the rod chamber actively running and providing its effects
var/operational = FALSE
/// Holds the list of linked neighbors
var/list/neighbors = list()
/// Skip this chamber when building links
var/skip_link = FALSE
/// The total amount of heat produced by this chamber
var/heat_total
/// The total amount of power produced by this rod
var/power_total
/// Is the chamber currently in an enrichment process
var/enriching = FALSE
/// Has the chamber been welded shut. Uh oh!
var/welded = FALSE
/// Holds the current accumulated power mod value from its neighbors
var/power_mod_total = 1
/// Holds the current accumulated heat mod value from its neighbors
var/heat_mod_total = 1
/// A simple binary to prevent open/close spam mucking up the anims
var/lockout = FALSE
/// Holds our durability bar overlay level. Updates overlays if it changes
var/durability_level = 0
/// Holds our previous overlay.
var/previous_durability_level
/obj/machinery/atmospherics/reactor_chamber/Initialize(mapload)
. = ..()
dupe_check()
component_parts = list()
component_parts += new /obj/item/circuitboard/machine/reactor_chamber(src)
component_parts += new /obj/item/stock_parts/manipulator(src)
component_parts += new /obj/item/stack/sheet/mineral/plastitanium(src, 2)
component_parts += new /obj/item/stack/sheet/metal(src, 2)
component_parts += new /obj/item/stack/cable_coil(src, 5)
RefreshParts()
update_icon(UPDATE_OVERLAYS)
RegisterSignal(src, COMSIG_PARENT_EXAMINE, PROC_REF(deep_examine))
return INITIALIZE_HINT_LATELOAD
// Needs to be late so it does not initialize before the reactor or the other neighbors are ready
/obj/machinery/atmospherics/reactor_chamber/LateInitialize()
. = ..()
find_link()
update_icon(UPDATE_OVERLAYS)
/obj/machinery/atmospherics/reactor_chamber/uranium
/obj/machinery/atmospherics/reactor_chamber/uranium/Initialize(mapload)
. = ..()
held_rod = new /obj/item/nuclear_rod/fuel/uranium_238(src)
/obj/machinery/atmospherics/reactor_chamber/heavy_water
/obj/machinery/atmospherics/reactor_chamber/heavy_water/Initialize(mapload)
. = ..()
held_rod = new /obj/item/nuclear_rod/moderator/heavy_water(src)
/obj/machinery/atmospherics/reactor_chamber/examine(mob/user)
. = ..()
. += SPAN_NOTICE("[src] can be sealed/unsealed from its base with a lit welder using harm intent, but only while the chamber is lowered.")
. += SPAN_NOTICE("Alt+click to open and close the shielding while the chamber is raised.")
. += SPAN_NOTICE("Click on the chamber while it is closed to raise and lower it.")
if(isobserver(user))
// observers get regular examine + nested multitool info
var/list/deep_info = get_deep_examine_info()
if(length(deep_info))
. += chat_box_examine(deep_info.Join("<br>"))
/obj/machinery/atmospherics/reactor_chamber/on_deconstruction()
desync()
if(held_rod) // We shouldnt be able to decon with this in, but just in case
if(held_rod.reactor_overheat_modifier)
linked_reactor.update_overheat_threshold(-held_rod.reactor_overheat_modifier)
held_rod.forceMove(loc)
held_rod = null
return ..()
/obj/machinery/atmospherics/reactor_chamber/Destroy()
if(held_rod && held_rod.reactor_overheat_modifier)
linked_reactor.update_overheat_threshold(-held_rod.reactor_overheat_modifier)
QDEL_NULL(held_rod)
if(linked_reactor)
desync()
UnregisterSignal(src, COMSIG_PARENT_EXAMINE)
return ..()
/obj/machinery/atmospherics/reactor_chamber/update_icon_state()
return
/obj/machinery/atmospherics/reactor_chamber/update_overlays()
. = ..()
overlays.Cut()
if(welded)
var/mutable_appearance/weld_overlay = mutable_appearance(layer = BELOW_OBJ_LAYER + 0.03)
weld_overlay.icon_state = "welded"
. += weld_overlay
if(chamber_state == CHAMBER_OPEN)
var/mutable_appearance/cover_icon = mutable_appearance(layer = ABOVE_ALL_MOB_LAYER + 0.02)
cover_icon.icon = icon
cover_icon.icon_state = "door_open"
. += cover_icon
if(!held_rod)
return
if(chamber_state == CHAMBER_OPEN)
var/mutable_appearance/rod_overlay = mutable_appearance(layer = ABOVE_ALL_MOB_LAYER + 0.01)
rod_overlay.icon = icon
if(istype(held_rod, /obj/item/nuclear_rod/fuel))
rod_overlay.icon_state = "fuel_overlay"
if(istype(held_rod, /obj/item/nuclear_rod/coolant))
rod_overlay.icon_state = "coolant_overlay"
if(istype(held_rod, /obj/item/nuclear_rod/moderator))
rod_overlay.icon_state = "moderator_overlay"
. += rod_overlay
var/mutable_appearance/state_overlay = mutable_appearance(layer = BELOW_OBJ_LAYER + 0.01)
state_overlay.icon = icon
if(chamber_state == CHAMBER_DOWN)
if(enriching)
state_overlay.icon_state = "blue"
else if(requirements_met)
if(operational)
state_overlay.icon_state = "green"
else
state_overlay.icon_state = "orange"
else
if(operational)
state_overlay.icon_state = "orange"
else
state_overlay.icon_state = "red"
var/mutable_appearance/display_overlay = mutable_appearance(layer = BELOW_OBJ_LAYER + 0.01)
if(istype(held_rod, /obj/item/nuclear_rod/fuel))
display_overlay.icon_state = "display_fuel"
if(istype(held_rod, /obj/item/nuclear_rod/moderator))
display_overlay.icon_state = "display_moderator"
if(istype(held_rod, /obj/item/nuclear_rod/coolant))
display_overlay.icon_state = "display_coolant"
. += display_overlay
if(chamber_state == CHAMBER_OVERLOAD_IDLE)
if(held_rod && istype(held_rod, /obj/item/nuclear_rod/fuel))
state_overlay.icon_state = "orange"
else
state_overlay.icon_state = "red"
if(chamber_state == CHAMBER_OVERLOAD_ACTIVE)
state_overlay.icon_state = "overload"
. += state_overlay
var/mutable_appearance/durability_overlay = mutable_appearance(icon, layer = BELOW_OBJ_LAYER + 0.01)
durability_overlay.icon_state = "dur_[previous_durability_level]"
. += durability_overlay
/// Check for multiple on a tile and nuke it
/obj/machinery/atmospherics/reactor_chamber/proc/dupe_check()
var/obj/machinery/atmospherics/reactor_chamber/chamber = locate() in range(0, src)
if(chamber && chamber != src)
visible_message(SPAN_WARNING("[src] has no room to deploy and breaks apart!"))
chamber.deconstruct()
/obj/machinery/atmospherics/reactor_chamber/attack_hand(mob/user)
if(!user)
return
if(linked_reactor && linked_reactor.admin_intervention)
to_chat(user, SPAN_WARNING("An unusual force prevents you from moving the chamber!"))
return
if(stat & NOPOWER)
to_chat(user, SPAN_WARNING("The chamber's locks wont disengage without power!"))
return
if(!is_mecha_occupant(user))
add_fingerprint(user)
switch(chamber_state)
if(CHAMBER_DOWN, CHAMBER_OVERLOAD_IDLE)
if(!Adjacent(user))
return
if(welded)
to_chat(user, SPAN_WARNING("[src] is welded shut. It wont budge!"))
return
if(!density_check(user))
return
var/delay = 1 SECONDS
if(linked_reactor && !linked_reactor.offline)
delay = 8 SECONDS
if(!is_mecha_occupant(user)) // Mech users are unaffected
burn_handler(user)
if(do_after_once(user, delay, target = src, allow_moving = FALSE))
if(!Adjacent(user)) // For mecha users
return
if(density_check(user))
raise()
return
if(CHAMBER_UP)
if(!density_check(user))
return
if(do_after_once(user, 2 SECONDS, target = src, allow_moving = FALSE))
if(chamber_state != CHAMBER_UP) // So that we cant lower while in the open state
return
if(density_check(user))
lower()
return
if(CHAMBER_OPEN)
if(issilicon(user)) // Handled seperately. Dont pull out this way
return
if(!held_rod)
to_chat(user, SPAN_WARNING("There is no rod inside of the chamber to remove!"))
return
if(user.put_in_hands(held_rod))
held_rod.add_fingerprint(user)
held_rod = null
playsound(loc, 'sound/machines/podopen.ogg', 50, TRUE)
update_icon(UPDATE_OVERLAYS)
return
to_chat(user, SPAN_WARNING("Your hands are currently full!"))
return
if(CHAMBER_OVERLOAD_ACTIVE)
to_chat(user, SPAN_ALERT("The chamber lockdowns have been engaged, preventing it from being raised!"))
return
update_icon(UPDATE_OVERLAYS)
/obj/machinery/atmospherics/reactor_chamber/AltClick(mob/user, modifiers)
if(!Adjacent(user) || lockout)
return
if(linked_reactor && linked_reactor.admin_intervention)
to_chat(user, SPAN_WARNING("An unusual force prevents you from manipulating the chamber!"))
return
if(chamber_state == CHAMBER_UP)
if(!lockout)
open()
return
if(chamber_state == CHAMBER_OPEN)
if(panel_open == TRUE)
to_chat(user, SPAN_WARNING("You must close the maintenance panel before the chamber can be sealed!"))
return
if(!lockout)
close()
return
/obj/machinery/atmospherics/reactor_chamber/proc/density_check(mob/user)
for(var/atom/thing in get_turf(src))
if(thing == src)
continue
if(thing.density)
to_chat(user, SPAN_WARNING("The chamber is being blocked from opening!"))
return FALSE
return TRUE
/obj/machinery/atmospherics/reactor_chamber/item_interaction(mob/living/user, obj/item/used, list/modifiers)
if(issilicon(user) && get_dist(src, user) > 1)
attack_hand(user)
return ITEM_INTERACT_COMPLETE
if(istype(used, /obj/item/nuclear_rod))
if(chamber_state == CHAMBER_OPEN)
if(held_rod)
to_chat(user, SPAN_WARNING("There is already a rod inside of the chamber!"))
return ITEM_INTERACT_COMPLETE
if(panel_open)
to_chat(user, SPAN_WARNING("The open maintenance panel prevents the rod from slotting inside!"))
return ITEM_INTERACT_COMPLETE
if(user.transfer_item_to(used, src, force = TRUE))
held_rod = used
playsound(loc, 'sound/machines/podclose.ogg', 50, TRUE)
update_icon(UPDATE_OVERLAYS)
return ITEM_INTERACT_COMPLETE
/obj/machinery/atmospherics/reactor_chamber/screwdriver_act(mob/living/user, obj/item/I)
if(!I.use_tool(src, user, 0, volume = 0))
return
. = TRUE
if(chamber_state != CHAMBER_OPEN)
to_chat(user, SPAN_ALERT("[src] must be raised and opened first!"))
return
if(linked_reactor && !linked_reactor.offline)
to_chat(user, SPAN_ALERT("The safety locks prevent maintenance while the reactor is on!"))
return
if(held_rod)
to_chat(user, SPAN_ALERT("You cannot reach the maintenance panel if there is a rod inside!"))
return
default_deconstruction_screwdriver(user, "chamber_maint", "chamber_open", I)
/obj/machinery/atmospherics/reactor_chamber/crowbar_act(mob/living/user, obj/item/I)
. = TRUE
default_deconstruction_crowbar(user, I)
/obj/machinery/atmospherics/reactor_chamber/welder_act(mob/living/user, obj/item/I)
if(user.a_intent == INTENT_HARM)
if(chamber_state == CHAMBER_OVERLOAD_IDLE || chamber_state == CHAMBER_OVERLOAD_ACTIVE)
to_chat(user, SPAN_WARNING("You probably shouldn't try to weld it right now."))
return ITEM_INTERACT_COMPLETE
if(chamber_state != CHAMBER_DOWN)
return ITEM_INTERACT_COMPLETE
to_chat(user, SPAN_WARNING("You begin [welded ? "unwelding" : "welding"] [src]"))
if(!I.use_tool(src, user, (6 SECONDS) * I.toolspeed, volume = I.tool_volume))
return ITEM_INTERACT_COMPLETE
if(welded)
unweld()
else
weld_shut()
update_icon(UPDATE_OVERLAYS)
return ITEM_INTERACT_COMPLETE
if(obj_integrity < max_integrity)
to_chat(user, SPAN_WARNING("You begin repairing [src]."))
if(!I.use_tool(src, user, (3 SECONDS) * I.toolspeed, volume = I.tool_volume))
return ITEM_INTERACT_COMPLETE
obj_integrity = max_integrity // Lets make sure we can keep these healthy if need be
else
to_chat(user, SPAN_WARNING("[src] is not in need of repair."))
return ITEM_INTERACT_COMPLETE
/obj/machinery/atmospherics/reactor_chamber/multitool_act(mob/living/user, obj/item/I)
. = TRUE
show_deep_examine(user)
/obj/machinery/atmospherics/reactor_chamber/proc/get_deep_examine_info()
if(chamber_state != CHAMBER_DOWN)
return null
if(!held_rod)
return list(SPAN_WARNING("There is no nuclear rod inside this housing chamber."))
if(!linked_reactor)
return list(SPAN_WARNING("This chamber is not connected to a reactor."))
var/operating_rate = linked_reactor.operating_rate()
var/durability_mod = held_rod.get_durability_mod()
var/list/message = list()
message += SPAN_NOTICE("[held_rod] is currently contained within this chamber.")
message += ""
if(held_rod.durability == 0)
message += SPAN_NOTICE("The rod has been fully depleted and rendered inert.")
return message
else
message += SPAN_NOTICE("Rod integrity is at [(held_rod.durability / held_rod.max_durability) * 100]%.")
message += ""
if(power_total && operational)
message += SPAN_NOTICE("The chamber is currently producing [(power_total * operating_rate * durability_mod) / 1000] KiloWatts of energy.")
message += SPAN_NOTICE("The chamber has a power modifier of [power_mod_total].")
else
message += SPAN_NOTICE("The chamber is producing no power.")
if(istype(held_rod, /obj/item/nuclear_rod/fuel))
var/obj/item/nuclear_rod/fuel/rod = held_rod
if(rod.power_enrich_progress >= rod.enrichment_cycles && rod.power_enrich_result)
message += SPAN_NOTICE("[held_rod] has been power enriched")
else
message += SPAN_NOTICE("[held_rod] has not yet finished a power enrichment process.")
message += ""
if(heat_total)
message += SPAN_NOTICE("The chamber is currently producing [heat_total * HEAT_MODIFIER * operating_rate * durability_mod] joules of heat.")
message += SPAN_NOTICE("The chamber has a heat modifier of [heat_mod_total].")
else
message += SPAN_NOTICE("The chamber is producing no heat.")
if(istype(held_rod, /obj/item/nuclear_rod/fuel))
var/obj/item/nuclear_rod/fuel/rod = held_rod
if(rod.heat_enrich_progress >= rod.enrichment_cycles && rod.heat_enrich_result)
message += SPAN_NOTICE("[held_rod] has been heat enriched")
else
message += SPAN_NOTICE("[held_rod] has not yet finished a heat enrichment process.")
return message
/obj/machinery/atmospherics/reactor_chamber/proc/show_deep_examine(mob/user)
var/list/info = get_deep_examine_info()
if(!info)
return ITEM_INTERACT_COMPLETE
to_chat(user, chat_box_examine(info.Join("<br>")))
return ITEM_INTERACT_COMPLETE
/obj/machinery/atmospherics/reactor_chamber/proc/deep_examine(datum/source, mob/user, list/examine_list)
SIGNAL_HANDLER // COMSIG_PARENT_EXAMINE
show_deep_examine(user)
/obj/machinery/atmospherics/reactor_chamber/proc/raise(playsound = TRUE)
chamber_state = CHAMBER_UP
icon_state = "chamber_up_anim"
lockout = TRUE
addtimer(CALLBACK(src, PROC_REF(finish_raise_anim)), 0.7 SECONDS)
density = TRUE
operational = FALSE
enriching = FALSE
requirements_met = FALSE
layer = ABOVE_MOB_LAYER
power_total = 0
check_minimum_modifier()
if(held_rod && held_rod.reactor_overheat_modifier)
linked_reactor.update_overheat_threshold(-held_rod.reactor_overheat_modifier)
if(playsound)
playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
if(istype(held_rod, /obj/item/nuclear_rod/fuel))
if(linked_reactor.offline)
held_rod.start_rads()
else
held_rod.start_rads(linked_reactor.reactivity_multiplier)
update_icon()
for(var/obj/machinery/atmospherics/reactor_chamber/chamber in neighbors)
if(!chamber.held_rod)
continue
if(chamber.check_status())
chamber.requirements_met = TRUE
else
chamber.requirements_met = FALSE
/obj/machinery/atmospherics/reactor_chamber/proc/finish_raise_anim()
lockout = FALSE
icon_state = "chamber_up"
/obj/machinery/atmospherics/reactor_chamber/proc/lower(playsound = TRUE)
density = FALSE
layer = BELOW_OBJ_LAYER
if(playsound)
playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
if(linked_reactor && linked_reactor.safety_override)
chamber_state = CHAMBER_OVERLOAD_IDLE
icon_state = "chamber_overload"
if(linked_reactor.check_overload_ready())
linked_reactor.set_overload()
update_icon()
return
chamber_state = CHAMBER_DOWN
icon_state = "chamber_down_anim"
addtimer(CALLBACK(src, PROC_REF(finish_down_anim)), 1.3 SECONDS)
if(!held_rod)
update_icon()
return
held_rod.stop_rads()
if(held_rod.reactor_overheat_modifier)
linked_reactor.update_overheat_threshold(held_rod.reactor_overheat_modifier)
previous_durability_level = clamp(ROUND_UP(((held_rod.durability / held_rod.max_durability) * 5) - 0.8), 0, 5)
if(check_status())
requirements_met = TRUE
else
requirements_met = FALSE
check_minimum_modifier()
update_icon()
/obj/machinery/atmospherics/reactor_chamber/proc/finish_down_anim()
icon_state = "chamber_down"
/obj/machinery/atmospherics/reactor_chamber/proc/close(playsound = TRUE)
chamber_state = CHAMBER_UP
new /obj/effect/temp_visual/chamber_closing(loc)
addtimer(CALLBACK(src, PROC_REF(finish_closing)), 0.5 SECONDS)
lockout = TRUE
if(playsound)
playsound(loc, 'sound/machines/switch.ogg', 50, TRUE)
/obj/machinery/atmospherics/reactor_chamber/proc/finish_closing()
lockout = FALSE
icon_state = "chamber_up"
update_icon(UPDATE_OVERLAYS)
/obj/machinery/atmospherics/reactor_chamber/proc/open(playsound = TRUE)
chamber_state = CHAMBER_OPEN
icon_state = "chamber_open"
var/cover_icon = mutable_appearance(icon, icon_state = "doors_opening", layer = ABOVE_ALL_MOB_LAYER + 0.02)
add_overlay(cover_icon)
lockout = TRUE
addtimer(CALLBACK(src, PROC_REF(finish_opening)), 0.5 SECONDS)
if(playsound)
playsound(loc, 'sound/machines/switch.ogg', 50, TRUE)
update_icon(UPDATE_OVERLAYS)
/obj/machinery/atmospherics/reactor_chamber/proc/finish_opening()
lockout = FALSE
/obj/machinery/atmospherics/reactor_chamber/proc/set_idle_overload()
if(chamber_state == CHAMBER_DOWN)
chamber_state = CHAMBER_OVERLOAD_IDLE
icon_state = "chamber_overload"
if(welded)
welded = FALSE
operational = FALSE
enriching = FALSE
requirements_met = FALSE
update_icon(UPDATE_OVERLAYS)
/obj/machinery/atmospherics/reactor_chamber/proc/set_active_overload()
chamber_state = CHAMBER_OVERLOAD_ACTIVE
icon_state = "chamber_down"
update_icon(UPDATE_OVERLAYS)
/// Gets the neighbors of the current chamber, and adds itself to its neighbors. can prompt a cascade of linking
/obj/machinery/atmospherics/reactor_chamber/proc/get_neighbors()
for(var/direction in GLOB.cardinal)
var/obj/machinery/atmospherics/reactor_chamber/chamber = locate() in get_step(src, direction)
if(!chamber)
continue
if(chamber.linked_reactor && chamber.linked_reactor != linked_reactor) // If for some god forsaken reason we have two
continue
if((chamber in neighbors) || (src in chamber.neighbors))
continue
neighbors += chamber
chamber.neighbors += src
if(!chamber.linked_reactor)
chamber.linked_reactor = linked_reactor
linked_reactor.connected_chambers += chamber
chamber.get_neighbors()
/// Removes the chamber from neighbor from its neighbors, and forces them to run status checks
/obj/machinery/atmospherics/reactor_chamber/proc/desync()
if(length(neighbors))
for(var/obj/machinery/atmospherics/reactor_chamber/chamber in neighbors)
chamber.neighbors -= src
neighbors.Cut()
if(linked_reactor)
linked_reactor.connected_chambers -= src
linked_reactor.clear_reactor_network(restart = TRUE)
/// Forms the two-way link between the reactor and the chamber, then searches for valid neighbors.
/obj/machinery/atmospherics/reactor_chamber/proc/form_link(obj/machinery/atmospherics/fission_reactor/reactor)
if(linked_reactor || skip_link) // Prevent duplicate linking or unwanted chambers
return
linked_reactor = reactor
linked_reactor.connected_chambers |= src
get_neighbors()
/// Searches for a valid reactor or linked chamber nearby
/obj/machinery/atmospherics/reactor_chamber/proc/find_link()
if(linked_reactor) // We already have a linked reactor
return
var/turf/nearby_turf
for(var/direction in GLOB.cardinal)
nearby_turf = get_step(src, direction)
var/obj/machinery/atmospherics/fission_reactor/reactor = locate() in nearby_turf
if(reactor)
form_link(reactor)
return TRUE
var/obj/structure/filler/filler = locate() in nearby_turf
if(filler &&istype(filler.parent, /obj/machinery/atmospherics/fission_reactor))
form_link(filler.parent)
return TRUE
var/obj/machinery/atmospherics/reactor_chamber/chamber = locate() in nearby_turf
if(chamber &&chamber.linked_reactor)
form_link(chamber.linked_reactor)
return TRUE
return FALSE
/// Validates that all rod requirements are being met
/obj/machinery/atmospherics/reactor_chamber/proc/check_status()
if(!held_rod)
return FALSE
var/list/temp_requirements = list()
temp_requirements += held_rod.adjacent_requirements // A temporary modable holder
if(!temp_requirements)
return TRUE
for(var/obj/machinery/atmospherics/reactor_chamber/chamber in neighbors)
if(!chamber.operational)
continue
if(chamber.held_rod.type in temp_requirements)
temp_requirements -= chamber.held_rod.type
continue
for(var/requirement in temp_requirements)
if(chamber.held_rod.type in typesof(requirement))
temp_requirements -= requirement
break
if(!length(temp_requirements))
return TRUE
return FALSE
/obj/machinery/atmospherics/reactor_chamber/process()
if(!linked_reactor)
if(find_link())
get_neighbors()
return
if(linked_reactor.admin_intervention)
return
if(!held_rod)
return
if(chamber_state != CHAMBER_DOWN) // We should only process reactor info when down
return
durability_level = clamp(ROUND_UP(((held_rod.durability / held_rod.max_durability) * 5) - 0.8), 0, 5)
if(durability_level != previous_durability_level)
previous_durability_level = durability_level
update_icon(UPDATE_OVERLAYS)
if(!linked_reactor.offline)
held_rod.calc_stat_decrease() // Only need to re-calc durability loss when the chamber is down and reactor is online
if(linked_reactor && linked_reactor.safety_override && !linked_reactor.control_lockout) // we only remove control lockout when the others are ready
if(chamber_state == CHAMBER_OVERLOAD_IDLE && istype(held_rod, /obj/item/nuclear_rod/fuel))
set_active_overload() // For latejoiners
if(operational && held_rod.durability <= 0)
requirements_met = FALSE
update_icon(UPDATE_OVERLAYS)
return
if(!requirements_met && !operational)
if(check_status())
requirements_met = TRUE
update_icon(UPDATE_OVERLAYS)
return
if(requirements_met && !operational)
if(prob(20))
operational = TRUE
update_icon(UPDATE_OVERLAYS)
return
if(!requirements_met && operational) // If it loses requirements, it wont immediately turn off
if(istype(held_rod, /obj/item/nuclear_rod/coolant))
if(prob(15)) // Higher rates of coolant rod failures once they're already on. Good luck.
operational = FALSE
update_icon(UPDATE_OVERLAYS)
else if(prob(1))
enriching = FALSE
operational = FALSE
update_icon(UPDATE_OVERLAYS)
return
/obj/machinery/atmospherics/reactor_chamber/process_atmos()
if(!held_rod || !linked_reactor || linked_reactor.offline)
return
if(chamber_state != CHAMBER_OPEN && chamber_state != CHAMBER_UP)
return
if(linked_reactor.admin_intervention)
return
var/datum/milla_safe/chamber_process/milla = new()
milla.invoke_async(src)
/datum/milla_safe/chamber_process
/datum/milla_safe/chamber_process/on_run(obj/machinery/atmospherics/reactor_chamber/chamber)
var/turf/T = get_turf(chamber)
var/datum/gas_mixture/environment = get_turf_air(T)
if(isnull(T)) // We have a null turf...something is wrong, stop processing this entity.
return PROCESS_KILL
if(!istype(chamber.loc, /turf)) // How in the FUCK did we manage this
return // Yeah just stop.
if(T.density)
var/turf/did_it_melt = T.ChangeTurf(T.baseturf)
if(!did_it_melt.density) // In case some joker finds way to place these on indestructible walls
chamber.visible_message(SPAN_WARNING("[chamber] melts through [T]!"))
return
var/heat_capacity = environment.heat_capacity()
var/heat_change = max(chamber.heat_total / heat_capacity) * HEAT_MODIFIER // the hotter the rod, the hotter the air
var/temp = environment.temperature()
if(chamber.chamber_state == CHAMBER_UP) // Its not fully exposed yet, and heating the reactor
heat_change *= 0.25
heat_change = max(heat_change, 1) // Always heat up at least a little
environment.set_temperature(temp + heat_change)
/// Calculate how much heat and energy we should be making
/obj/machinery/atmospherics/reactor_chamber/proc/calculate_stats(operating_rate = 0)
power_total = (held_rod.power_amount * operating_rate)
heat_total = (held_rod.heat_amount * operating_rate)
power_mod_total = 1
heat_mod_total = 1
for(var/obj/machinery/atmospherics/reactor_chamber/chamber in neighbors)
if(!chamber.held_rod || chamber.chamber_state == CHAMBER_OPEN)
continue
if(istype(chamber.held_rod, /obj/item/nuclear_rod/coolant) && !chamber.operational) // Do not apply negative heat gen on coolant when not on.
heat_mod_total *= 1
else if(held_rod.heat_amount > 0) // Do not multiply negative heat.
heat_mod_total *= chamber.held_rod.current_heat_mod // We generate heat even when its not operational
if(operational && chamber.chamber_state == CHAMBER_DOWN)
if(held_rod.power_amount > 0) // Do not multiply negative power.
power_mod_total *= chamber.held_rod.current_power_mod
power_total *= power_mod_total
heat_total *= heat_mod_total
/obj/machinery/atmospherics/reactor_chamber/proc/eject_rod()
raise(FALSE)
open(FALSE)
var/datum/effect_system/smoke_spread/bad/smoke = new()
smoke.set_up(5, FALSE, loc)
smoke.start()
var/rad_type = pick(ALPHA_RAD, BETA_RAD, GAMMA_RAD)
for(var/turf/T in view(2, loc))
T.contaminate_atom(src, 300, rad_type)
var/distance_traveled = rand(10, 60)
var/angle = rand(0, 360)
var/turf/end = get_turf_in_angle(angle, loc, distance_traveled)
var/obj/effect/immovablerod/nuclear_rod/nuclear_rod = new(loc, end)
var/matrix/M = new
M.Turn(angle)
nuclear_rod.transform = M
nuclear_rod.icon = held_rod.icon
nuclear_rod.icon_state = held_rod.icon_state
nuclear_rod.held_rod = held_rod
held_rod.forceMove(src)
held_rod = null
update_icon(UPDATE_OVERLAYS)
playsound(src, 'sound/effects/bang.ogg', 70, TRUE)
audible_message(SPAN_USERDANGER("POW!"))
/obj/machinery/atmospherics/reactor_chamber/proc/weld_shut()
welded = TRUE
playsound(loc, 'sound/items/welder2.ogg', 60, TRUE)
update_icon(UPDATE_OVERLAYS)
/obj/machinery/atmospherics/reactor_chamber/proc/unweld()
welded = FALSE
playsound(loc, 'sound/items/welder2.ogg', 60, TRUE)
update_icon(UPDATE_OVERLAYS)
/obj/machinery/atmospherics/reactor_chamber/proc/burn_handler(mob/user)
var/burn_damage = CHAMBER_HEAT_DAMAGE
if(linked_reactor.check_overheating()) // Ouch, even hotter!
burn_damage *= 2
if(istype(user, /mob/living/carbon/human))
var/mob/living/carbon/human/H = user
if(H.gloves)
var/obj/item/clothing/gloves/G = H.gloves
if(G.max_heat_protection_temperature)
burn_damage *= 0.5
else if(HAS_TRAIT(H, TRAIT_RESISTHEAT) || HAS_TRAIT(H, TRAIT_RESISTHEATHANDS))
burn_damage *= 0.5
var/obj/item/organ/external/affecting = H.get_organ("[user.hand ? "l" : "r" ]_hand")
if(affecting.receive_damage(0, burn_damage)) // Burn damage to them fingers
H.UpdateDamageIcon()
H.updatehealth()
else if(isliving(user))
var/mob/living/L = user
if(issilicon(L)) // More resistant by default
burn_damage *= 0.5
L.adjustFireLoss(burn_damage)
/obj/machinery/atmospherics/reactor_chamber/proc/check_minimum_modifier()
if(!linked_reactor)
return
if(!held_rod)
return
if(!held_rod.minimum_temp_modifier)
return
if(held_rod.minimum_temp_modifier >= linked_reactor.minimum_operating_temp)
linked_reactor.update_minimum_temp()
/obj/effect/immovablerod/nuclear_rod
name = "\improper Nuclear Coolant Rod"
desc = "Getting hit by this might make you wish you got radiation sickness instead."
notify = FALSE
var/obj/held_rod
/// Lets not break the reactor with this.
/obj/effect/immovablerod/nuclear_rod/clong_thing(atom/victim)
if(istype(victim, /obj/machinery/atmospherics/fission_reactor))
return
if(istype(victim, /obj/structure/filler))
var/obj/structure/filler/filler = victim
if(istype(filler.parent, /obj/machinery/atmospherics/fission_reactor))
return
if(istype(victim, /obj/machinery/atmospherics/reactor_chamber))
return
if(isobj(victim) && victim.density)
victim.ex_act(EXPLODE_HEAVY)
else if(ismob(victim))
if(ishuman(victim))
var/mob/living/carbon/human/H = victim
H.visible_message(SPAN_DANGER("[H.name] is penetrated by an ejected coolant rod!"),
SPAN_USERDANGER("The rod penetrates you!"),
SPAN_DANGER("You hear a CLANG!"))
H.adjustBruteLoss(100) // Not as strong as a normal rod
if(victim.density || prob(20)) // We want to hit more things than a normal rod though
victim.ex_act(EXPLODE_HEAVY)
/obj/effect/immovablerod/nuclear_rod/Move()
. = ..()
if(loc == end)
qdel(src)
/obj/effect/immovablerod/nuclear_rod/Destroy()
held_rod.forceMove(get_turf(src))
return ..()
#undef CHAMBER_HEAT_DAMAGE