Ports R-UST from Baystation12 + small admin debug verb

This commit is contained in:
silveryferret
2017-07-19 01:39:12 -04:00
parent 60e945248a
commit 7567726c07
27 changed files with 2172 additions and 12 deletions

View File

@@ -158,6 +158,17 @@
default_type = "osmium"
apply_colour = 1
//R-UST port
// Fusion fuel.
/obj/item/stack/material/deuterium
name = "deuterium"
icon_state = "sheet-silver"
default_type = "deuterium"
apply_colour = 1
/obj/item/stack/material/deuterium/fifty
amount = 50
/obj/item/stack/material/steel
name = DEFAULT_WALL_MATERIAL
icon_state = "sheet-metal"

View File

@@ -69,6 +69,7 @@ var/list/name_to_material
var/flags = 0 // Various status modifiers.
var/sheet_singular_name = "sheet"
var/sheet_plural_name = "sheets"
var/is_fusion_fuel
// Shards/tables/structures
var/shard_type = SHARD_SHRAPNEL // Path of debris object.
@@ -97,6 +98,7 @@ var/list/name_to_material
var/conductive = 1 // Objects with this var add CONDUCTS to flags on spawn.
var/conductivity = null // How conductive the material is. Iron acts as the baseline, at 10.
var/list/composite_material // If set, object matter var will be a list containing these values.
var/luminescence
// Placeholder vars for the time being, todo properly integrate windows/light tiles/rods.
var/created_window
@@ -270,6 +272,22 @@ var/list/name_to_material
sheet_singular_name = "ingot"
sheet_plural_name = "ingots"
//R-UST port
/material/supermatter
name = "supermatter"
icon_colour = "#FFFF00"
radioactivity = 20
stack_type = null
luminescence = 3
ignition_point = PHORON_MINIMUM_BURN_TEMPERATURE
icon_base = "stone"
shard_type = SHARD_SHARD
hardness = 30
door_icon_base = "stone"
sheet_singular_name = "crystal"
sheet_plural_name = "crystals"
is_fusion_fuel = 1
/material/phoron
name = "phoron"
stack_type = /obj/item/stack/material/phoron
@@ -567,6 +585,16 @@ var/list/name_to_material
stack_origin_tech = list(TECH_MATERIAL = 5)
sheet_singular_name = "ingot"
sheet_plural_name = "ingots"
is_fusion_fuel = 1
/material/deuterium
name = "deuterium"
stack_type = /obj/item/stack/material/deuterium
icon_colour = "#999999"
stack_origin_tech = list(TECH_MATERIAL = 3)
sheet_singular_name = "ingot"
sheet_plural_name = "ingots"
is_fusion_fuel = 1
/material/mhydrogen
name = "mhydrogen"
@@ -574,6 +602,7 @@ var/list/name_to_material
icon_colour = "#E6C5DE"
stack_origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 6, TECH_MAGNET = 5)
conductivity = 100
is_fusion_fuel = 1
/material/platinum
name = "platinum"

View File

@@ -0,0 +1,83 @@
// temperature of the core of the sun
#define FUSION_HEAT_CAP 1.57e7
#define SETUP_OK 1 // All good
#define SETUP_WARNING 2 // Something that shouldn't happen happened, but it's not critical so we will continue
#define SETUP_ERROR 3 // Something bad happened, and it's important so we won't continue setup.
#define SETUP_DELAYED 4 // Wait for other things first.
/datum/admins/proc/setup_fusion()
set category = "Debug"
set name = "Setup Fusion Core"
set desc = "Allows you to start the R-UST engine."
if (!istype(src,/datum/admins))
src = usr.client.holder
if (!istype(src,/datum/admins))
to_chat(usr, "Error: you are not an admin!")
return
if(!(locate(/obj/machinery/power/fusion_core/mapped) in world))
to_chat(usr, "This map is not appropriate for this verb.")
return
var/response = input(usr, "Are you sure?", "Engine setup") as null|anything in list("No", "Yes")
if(!response || response == "No")
return
var/errors = 0
var/warnings = 0
var/success = 0
log_and_message_admins("## FUSION CORE SETUP - Setup initiated by [usr].")
for(var/obj/machinery/fusion_fuel_injector/mapped/injector in machines)
injector.cur_assembly = new /obj/item/weapon/fuel_assembly/deuterium(injector)
injector.BeginInjecting()
var/obj/machinery/power/fusion_core/mapped/core = locate() in machines
if(core.jumpstart(15000))
var/list/delayed_objects = list()
// SETUP PHASE
for(var/obj/effect/engine_setup/S in world)
var/result = S.activate(0)
switch(result)
if(SETUP_OK)
success++
continue
if(SETUP_WARNING)
warnings++
continue
if(SETUP_ERROR)
errors++
log_and_message_admins("## FUSION CORE SETUP - Error encountered! Aborting.")
break
if(SETUP_DELAYED)
delayed_objects.Add(S)
continue
if(!errors)
for(var/obj/effect/engine_setup/S in delayed_objects)
var/result = S.activate(1)
switch(result)
if(SETUP_OK)
success++
continue
if(SETUP_WARNING)
warnings++
continue
if(SETUP_ERROR)
errors++
log_and_message_admins("## FUSION CORE SETUP - Error encountered! Aborting.")
break
else
log_and_message_admins("## FUSION CORE SETUP - Error encountered! Aborting.")
errors++
log_and_message_admins("## FUSION CORE SETUP - Setup completed with [errors] errors, [warnings] warnings and [success] successful steps.")
#undef SETUP_OK
#undef SETUP_WARNING
#undef SETUP_ERROR
#undef SETUP_DELAYED

View File

@@ -0,0 +1,131 @@
/*
TODO README
*/
var/list/fusion_cores = list()
#define MAX_FIELD_STR 1000
#define MIN_FIELD_STR 1
/obj/machinery/power/fusion_core
name = "\improper R-UST Mk. 8 Tokamak core"
desc = "An enormous solenoid for generating extremely high power electromagnetic fields. It includes a kinetic energy harvester."
icon = 'icons/obj/machines/power/fusion.dmi'
icon_state = "core0"
density = 1
use_power = 1
idle_power_usage = 50
active_power_usage = 500 //multiplied by field strength
anchored = 0
var/obj/effect/fusion_em_field/owned_field
var/field_strength = 1//0.01
var/id_tag
/obj/machinery/power/fusion_core/mapped
anchored = 1
/obj/machinery/power/fusion_core/initialize()
. = ..()
connect_to_network()
fusion_cores += src
/obj/machinery/power/fusion_core/Destroy()
for(var/obj/machinery/computer/fusion_core_control/FCC in machines)
FCC.connected_devices -= src
if(FCC.cur_viewed_device == src)
FCC.cur_viewed_device = null
fusion_cores -= src
return ..()
/obj/machinery/power/fusion_core/process()
if((stat & BROKEN) || !powernet || !owned_field)
Shutdown()
/obj/machinery/power/fusion_core/Topic(href, href_list)
if(..())
return 1
if(href_list["str"])
var/dif = text2num(href_list["str"])
field_strength = min(max(field_strength + dif, MIN_FIELD_STR), MAX_FIELD_STR)
active_power_usage = 500 * field_strength
if(owned_field)
owned_field.ChangeFieldStrength(field_strength)
/obj/machinery/power/fusion_core/proc/Startup()
if(owned_field)
return
owned_field = new(loc, src)
owned_field.ChangeFieldStrength(field_strength)
icon_state = "core1"
use_power = 2
. = 1
/obj/machinery/power/fusion_core/proc/Shutdown(var/force_rupture)
if(owned_field)
icon_state = "core0"
if(force_rupture || owned_field.plasma_temperature > 1000)
owned_field.Rupture()
else
owned_field.RadiateAll()
qdel(owned_field)
owned_field = null
use_power = 1
/obj/machinery/power/fusion_core/proc/AddParticles(var/name, var/quantity = 1)
if(owned_field)
owned_field.AddParticles(name, quantity)
. = 1
/obj/machinery/power/fusion_core/bullet_act(var/obj/item/projectile/Proj)
if(owned_field)
. = owned_field.bullet_act(Proj)
/obj/machinery/power/fusion_core/proc/set_strength(var/value)
value = Clamp(value, MIN_FIELD_STR, MAX_FIELD_STR)
field_strength = value
active_power_usage = 5 * value
if(owned_field)
owned_field.ChangeFieldStrength(value)
/obj/machinery/power/fusion_core/attack_hand(var/mob/user)
if(!Adjacent(user)) // As funny as it was for the AI to hug-kill the tokamak field from a distance...
return
visible_message("<span class='notice'>\The [user] hugs \the [src] to make it feel better!</span>")
if(owned_field)
Shutdown()
/obj/machinery/power/fusion_core/attackby(var/obj/item/W, var/mob/user)
if(owned_field)
to_chat(user,"<span class='warning'>Shut \the [src] off first!</span>")
return
if(ismultitool(W))
var/new_ident = input("Enter a new ident tag.", "Fusion Core", id_tag) as null|text
if(new_ident && user.Adjacent(src))
id_tag = new_ident
return
else if(iswrench(W))
anchored = !anchored
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
if(anchored)
user.visible_message("[user.name] secures [src.name] to the floor.", \
"You secure the [src.name] to the floor.", \
"You hear a ratchet")
else
user.visible_message("[user.name] unsecures [src.name] from the floor.", \
"You unsecure the [src.name] from the floor.", \
"You hear a ratchet")
return
return ..()
/obj/machinery/power/fusion_core/proc/jumpstart(var/field_temperature)
field_strength = 501 // Generally a good size.
Startup()
if(!owned_field)
return FALSE
owned_field.plasma_temperature = field_temperature
return TRUE

View File

@@ -0,0 +1,176 @@
/obj/machinery/computer/fusion_core_control
name = "\improper R-UST Mk. 8 core control"
icon = 'icons/obj/machines/power/fusion.dmi'
icon_state = "core_control"
light_color = COLOR_ORANGE
var/id_tag
var/scan_range = 25
var/list/connected_devices = list()
var/obj/machinery/power/fusion_core/cur_viewed_device
/obj/machinery/computer/fusion_core_control/attackby(var/obj/item/thing, var/mob/user)
if(ismultitool(thing))
var/new_ident = input("Enter a new ident tag.", "Core Control", id_tag) as null|text
if(new_ident && user.Adjacent(src))
id_tag = new_ident
cur_viewed_device = null
return
else
return ..()
/obj/machinery/computer/fusion_core_control/attack_ai(mob/user)
attack_hand(user)
/obj/machinery/computer/fusion_core_control/attack_hand(mob/user)
add_fingerprint(user)
interact(user)
/obj/machinery/computer/fusion_core_control/interact(mob/user)
if(!cur_viewed_device || !check_core_status(cur_viewed_device))
cur_viewed_device = null
if(!id_tag)
to_chat(user, "<span class='warning'>This console has not been assigned an ident tag. Please contact your system administrator or conduct a manual update with a standard multitool.</span>")
return
if(cur_viewed_device && (cur_viewed_device.id_tag != id_tag || get_dist(src, cur_viewed_device) > scan_range))
cur_viewed_device = null
var/dat = "<B>Core Control #[id_tag]</B><BR>"
if(cur_viewed_device)
dat += {"
<a href='?src=\ref[src];goto_scanlist=1'>Back to overview</a><hr>
Device ident '[cur_viewed_device.id_tag]' <span style='color: [cur_viewed_device.owned_field ? "green" : "red"]'>[cur_viewed_device.owned_field ? "active" : "inactive"].</span><br>
<b>Power status:</b> [cur_viewed_device.avail()]/[cur_viewed_device.active_power_usage] W<br>
<hr>
<a href='?src=\ref[src];toggle_active=1'>Bring field [cur_viewed_device.owned_field ? "offline" : "online"].</a><br>
<hr>
<b>Field power density (W.m<sup>-3</sup>):</b><br>
<a href='?src=\ref[src];str=-1000'>----</a>
<a href='?src=\ref[src];str=-100'>--- </a>
<a href='?src=\ref[src];str=-10'>-- </a>
<a href='?src=\ref[src];str=-1'>- </a>
<a href='?src=\ref[src];str=0'>[cur_viewed_device.field_strength]</a>
<a href='?src=\ref[src];str=1'>+ </a>
<a href='?src=\ref[src];str=10'>++ </a>
<a href='?src=\ref[src];str=100'>+++ </a>
<a href='?src=\ref[src];str=1000'>++++</a><hr>
"}
if(cur_viewed_device.owned_field)
dat += {"
<b>Approximate field diameter (m):</b> [cur_viewed_device.owned_field.size]<br>
<b>Field instability:</b> [cur_viewed_device.owned_field.percent_unstable * 100]%<br>
<b>Plasma temperature:</b> [cur_viewed_device.owned_field.plasma_temperature + 295]K<hr>
<b>Fuel:</b><br>
<table><tr><th><b>Name</b></th><th><b>Amount</b></th></tr>
"}
for(var/reagent in cur_viewed_device.owned_field.dormant_reactant_quantities)
dat += "<tr><td>[reagent]</td><td>[cur_viewed_device.owned_field.dormant_reactant_quantities[reagent]]</td></tr>"
dat += "</table><hr>"
else
connected_devices.Cut()
for(var/obj/machinery/power/fusion_core/C in fusion_cores)
if(C.id_tag == id_tag && get_dist(src, C) <= scan_range)
connected_devices += C
for(var/obj/machinery/power/fusion_core/C in gyrotrons)
if(C.id_tag == id_tag && get_dist(src, C) <= scan_range)
connected_devices += C
if(connected_devices.len)
dat += {"
<b>Connected EM field generators:</b><hr>
<table>
<tr>
<th><b>Device tag</b></th>
<th><b>Status</b></th>
<th><b>Controls</b></th>
</tr>
"}
for(var/obj/machinery/power/fusion_core/C in connected_devices)
var/status
var/can_access = 1
if(!check_core_status(C))
status = "<span style='color: red'>Unresponsive</span>"
can_access = 0
else if(C.avail() < C.active_power_usage)
status = "<span style='color: orange'>Underpowered</span>"
else
status = "<span style='color: green'>Good</span>"
dat += {"
<tr>
<td>[C.id_tag]</td>
<td>[status]</td>
"}
if(!can_access)
dat += {"
<td><span style='color: red'>ERROR</span></td>
"}
else
dat += {"
<td><a href=?src=\ref[src];access_device=[connected_devices.Find(C)]'>ACCESS</a></td>
"}
dat += {"
</tr>
"}
else
dat += "<span style='color: red'>No electromagnetic field generators connected.</span>"
var/datum/browser/popup = new(user, "fusion_control", name, 500, 400, src)
popup.set_content(dat)
popup.open()
user.set_machine(src)
/obj/machinery/computer/fusion_core_control/Topic(href, href_list)
. = ..()
if(.)
return
if(href_list["access_device"])
var/idx = Clamp(text2num(href_list["toggle_active"]), 1, connected_devices.len)
cur_viewed_device = connected_devices[idx]
updateUsrDialog()
return 1
//All HREFs from this point on require a device anyways.
if(!cur_viewed_device || !check_core_status(cur_viewed_device) || cur_viewed_device.id_tag != id_tag || get_dist(src, cur_viewed_device) > scan_range)
return
if(href_list["goto_scanlist"])
cur_viewed_device = null
updateUsrDialog()
return 1
if(href_list["toggle_active"])
if(!cur_viewed_device.Startup()) //Startup() whilst the device is active will return null.
cur_viewed_device.Shutdown()
updateUsrDialog()
return 1
if(href_list["str"])
var/val = text2num(href_list["str"])
if(!val) //Value is 0, which is manual entering.
cur_viewed_device.set_strength(input("Enter the new field power density (W.m^-3)", "Fusion Control", cur_viewed_device.field_strength) as num)
else
cur_viewed_device.set_strength(cur_viewed_device.field_strength + val)
updateUsrDialog()
return 1
//Returns 1 if the machine can be interacted with via this console.
/obj/machinery/computer/fusion_core_control/proc/check_core_status(var/obj/machinery/power/fusion_core/C)
if(isnull(C))
return
if(C.stat & BROKEN)
return
if(C.idle_power_usage > C.avail())
return
. = 1

View File

@@ -0,0 +1,494 @@
#define FUSION_ENERGY_PER_K 20
/obj/effect/fusion_em_field
name = "electromagnetic field"
desc = "A coruscating, barely visible field of energy. It is shaped like a slightly flattened torus."
icon = 'icons/obj/machines/power/fusion.dmi'
icon_state = "emfield_s1"
alpha = 50
layer = 4
light_color = COLOR_BLUE
var/size = 1
var/energy = 0
var/plasma_temperature = 0
var/radiation = 0
var/field_strength = 0.01
var/tick_instability = 0
var/percent_unstable = 0
var/obj/machinery/power/fusion_core/owned_core
var/list/dormant_reactant_quantities = list()
var/list/particle_catchers = list()
var/list/ignore_types = list(
/obj/item/projectile,
/obj/effect,
/obj/fire,
/obj/structure/cable,
/obj/machinery/atmospherics,
/obj/machinery/air_sensor,
/mob/observer/dead
)
var/light_min_range = 2
var/light_min_power = 3
var/light_max_range = 10
var/light_max_power = 10
var/last_range
var/last_power
/obj/effect/fusion_em_field/New(loc, var/obj/machinery/power/fusion_core/new_owned_core)
..()
set_light(light_min_range,light_min_power)
last_range = light_min_range
last_power = light_min_power
owned_core = new_owned_core
if(!owned_core)
qdel(src)
//create the gimmicky things to handle field collisions
var/obj/effect/fusion_particle_catcher/catcher
catcher = new (locate(src.x,src.y,src.z))
catcher.parent = src
catcher.SetSize(1)
particle_catchers.Add(catcher)
catcher = new (locate(src.x-1,src.y,src.z))
catcher.parent = src
catcher.SetSize(3)
particle_catchers.Add(catcher)
catcher = new (locate(src.x+1,src.y,src.z))
catcher.parent = src
catcher.SetSize(3)
particle_catchers.Add(catcher)
catcher = new (locate(src.x,src.y+1,src.z))
catcher.parent = src
catcher.SetSize(3)
particle_catchers.Add(catcher)
catcher = new (locate(src.x,src.y-1,src.z))
catcher.parent = src
catcher.SetSize(3)
particle_catchers.Add(catcher)
catcher = new (locate(src.x-2,src.y,src.z))
catcher.parent = src
catcher.SetSize(5)
particle_catchers.Add(catcher)
catcher = new (locate(src.x+2,src.y,src.z))
catcher.parent = src
catcher.SetSize(5)
particle_catchers.Add(catcher)
catcher = new (locate(src.x,src.y+2,src.z))
catcher.parent = src
catcher.SetSize(5)
particle_catchers.Add(catcher)
catcher = new (locate(src.x,src.y-2,src.z))
catcher.parent = src
catcher.SetSize(5)
particle_catchers.Add(catcher)
catcher = new (locate(src.x-3,src.y,src.z))
catcher.parent = src
catcher.SetSize(7)
particle_catchers.Add(catcher)
catcher = new (locate(src.x+3,src.y,src.z))
catcher.parent = src
catcher.SetSize(7)
particle_catchers.Add(catcher)
catcher = new (locate(src.x,src.y+3,src.z))
catcher.parent = src
catcher.SetSize(7)
particle_catchers.Add(catcher)
catcher = new (locate(src.x,src.y-3,src.z))
catcher.parent = src
catcher.SetSize(7)
particle_catchers.Add(catcher)
processing_objects.Add(src)
/obj/effect/fusion_em_field/process()
//make sure the field generator is still intact
if(!owned_core || QDELETED(owned_core))
qdel(src)
return
// Take some gas up from our environment.
var/added_particles = FALSE
var/datum/gas_mixture/uptake_gas = owned_core.loc.return_air()
if(uptake_gas)
uptake_gas = uptake_gas.remove_by_flag(XGM_GAS_FUSION_FUEL, rand(50,100))
if(uptake_gas && uptake_gas.total_moles)
for(var/gasname in uptake_gas.gas)
if(uptake_gas.gas[gasname]*10 > dormant_reactant_quantities[gasname])
AddParticles(gasname, uptake_gas.gas[gasname]*10)
uptake_gas.adjust_gas(gasname, -(uptake_gas.gas[gasname]), update=FALSE)
added_particles = TRUE
if(added_particles)
uptake_gas.update_values()
//let the particles inside the field react
React()
// Dump power to our powernet.
owned_core.add_avail(FUSION_ENERGY_PER_K * plasma_temperature)
// Energy decay.
if(plasma_temperature >= 1)
var/lost = plasma_temperature*0.01
radiation += lost
plasma_temperature -= lost
//handle some reactants formatting
for(var/reactant in dormant_reactant_quantities)
var/amount = dormant_reactant_quantities[reactant]
if(amount < 1)
dormant_reactant_quantities.Remove(reactant)
else if(amount >= 1000000)
var/radiate = rand(3 * amount / 4, amount / 4)
dormant_reactant_quantities[reactant] -= radiate
radiation += radiate
var/use_range
var/use_power
if(plasma_temperature <= 6000)
use_range = light_min_range
use_power = light_min_power
else if(plasma_temperature >= 25000)
use_range = light_max_range
use_power = light_max_power
else
var/temp_mod = ((plasma_temperature-5000)/20000)
use_range = light_min_range + ceil((light_max_range-light_min_range)*temp_mod)
use_power = light_min_power + ceil((light_max_power-light_min_power)*temp_mod)
if(last_range != use_range || last_power != use_power)
set_light(use_range,use_power)
last_range = use_range
last_power = use_power
check_instability()
Radiate()
if(radiation)
radiation_repository.radiate(src, radiation)
return 1
/obj/effect/fusion_em_field/proc/check_instability()
if(tick_instability > 0)
percent_unstable += (tick_instability*size)/10000
tick_instability = 0
else
if(percent_unstable < 0)
percent_unstable = 0
else
if(percent_unstable > 100)
percent_unstable = 100
if(percent_unstable > 0)
percent_unstable = max(0, percent_unstable-rand(0.01,0.03))
if(percent_unstable >= 1)
owned_core.Shutdown(force_rupture=1)
else
if(percent_unstable > 0.5 && prob(percent_unstable*100))
if(plasma_temperature < 2000)
visible_message("<span class='danger'>\The [src] ripples uneasily, like a disturbed pond.</span>")
else
var/flare
var/fuel_loss
var/rupture
if(percent_unstable < 0.7)
visible_message("<span class='danger'>\The [src] ripples uneasily, like a disturbed pond.</span>")
fuel_loss = prob(5)
else if(percent_unstable < 0.9)
visible_message("<span class='danger'>\The [src] undulates violently, shedding plumes of plasma!</span>")
flare = prob(50)
fuel_loss = prob(20)
rupture = prob(5)
else
visible_message("<span class='danger'>\The [src] is wracked by a series of horrendous distortions, buckling and twisting like a living thing!</span>")
flare = 1
fuel_loss = prob(50)
rupture = prob(25)
if(rupture)
owned_core.Shutdown(force_rupture=1)
else
var/lost_plasma = (plasma_temperature*percent_unstable)
radiation += lost_plasma
if(flare)
radiation += plasma_temperature/2
plasma_temperature -= lost_plasma
if(fuel_loss)
for(var/particle in dormant_reactant_quantities)
var/lost_fuel = dormant_reactant_quantities[particle]*percent_unstable
radiation += lost_fuel
dormant_reactant_quantities[particle] -= lost_fuel
if(dormant_reactant_quantities[particle] <= 0)
dormant_reactant_quantities.Remove(particle)
Radiate()
return
/obj/effect/fusion_em_field/proc/Rupture()
visible_message("<span class='danger'>\The [src] shudders like a dying animal before flaring to eye-searing brightness and rupturing!</span>")
set_light(15, 15, "#CCCCFF")
empulse(get_turf(src), ceil(plasma_temperature/1000), ceil(plasma_temperature/300))
sleep(5)
RadiateAll()
explosion(get_turf(owned_core),-1,-1,8,10) // Blow out all the windows.
return
/obj/effect/fusion_em_field/proc/ChangeFieldStrength(var/new_strength)
var/calc_size = 1
if(new_strength <= 50)
calc_size = 1
else if(new_strength <= 200)
calc_size = 3
else if(new_strength <= 500)
calc_size = 5
else
calc_size = 7
field_strength = new_strength
change_size(calc_size)
/obj/effect/fusion_em_field/proc/AddEnergy(var/a_energy, var/a_plasma_temperature)
energy += a_energy
plasma_temperature += a_plasma_temperature
if(a_energy && percent_unstable > 0)
percent_unstable -= a_energy/10000
if(percent_unstable < 0)
percent_unstable = 0
while(energy >= 100)
energy -= 100
plasma_temperature += 1
/obj/effect/fusion_em_field/proc/AddParticles(var/name, var/quantity = 1)
if(name in dormant_reactant_quantities)
dormant_reactant_quantities[name] += quantity
else if(name != "proton" && name != "electron" && name != "neutron")
dormant_reactant_quantities.Add(name)
dormant_reactant_quantities[name] = quantity
/obj/effect/fusion_em_field/proc/RadiateAll(var/ratio_lost = 1)
// Create our plasma field and dump it into our environment.
var/turf/T = get_turf(src)
if(istype(T))
var/datum/gas_mixture/plasma = new
plasma.adjust_gas("oxygen", (size*100), 0)
plasma.adjust_gas("phoron", (size*100), 0)
plasma.temperature = (plasma_temperature/2)
plasma.update_values()
T.assume_air(plasma)
T.hotspot_expose(plasma_temperature)
plasma = null
// Radiate all our unspent fuel and energy.
for(var/particle in dormant_reactant_quantities)
radiation += dormant_reactant_quantities[particle]
dormant_reactant_quantities.Remove(particle)
radiation += plasma_temperature/2
plasma_temperature = 0
radiation_repository.radiate(src, radiation)
Radiate()
/obj/effect/fusion_em_field/proc/Radiate()
if(istype(loc, /turf))
var/empsev = max(1, min(3, ceil(size/2)))
for(var/atom/movable/AM in range(max(1,Floor(size/2)), loc))
if(AM == src || AM == owned_core || !AM.simulated)
continue
var/skip_obstacle
for(var/ignore_path in ignore_types)
if(istype(AM, ignore_path))
skip_obstacle = TRUE
break
if(skip_obstacle)
continue
log_debug("R-UST DEBUG: [AM] is [AM.type]")
AM.visible_message("<span class='danger'>The field buckles visibly around \the [AM]!</span>")
tick_instability += rand(15,30)
AM.emp_act(empsev)
if(owned_core && owned_core.loc)
var/datum/gas_mixture/environment = owned_core.loc.return_air()
if(environment && environment.temperature < (T0C+1000)) // Putting an upper bound on it to stop it being used in a TEG.
environment.add_thermal_energy(plasma_temperature*20000)
radiation = 0
/obj/effect/fusion_em_field/proc/change_size(var/newsize = 1)
var/changed = 0
switch(newsize)
if(1)
size = 1
icon = 'icons/obj/machines/power/fusion.dmi'
icon_state = "emfield_s1"
pixel_x = 0
pixel_y = 0
//
changed = 1
if(3)
size = 3
icon = 'icons/effects/96x96.dmi'
icon_state = "emfield_s3"
pixel_x = -32 * PIXEL_MULTIPLIER
pixel_y = -32 * PIXEL_MULTIPLIER
//
changed = 3
if(5)
size = 5
icon = 'icons/effects/160x160.dmi'
icon_state = "emfield_s5"
pixel_x = -64 * PIXEL_MULTIPLIER
pixel_y = -64 * PIXEL_MULTIPLIER
//
changed = 5
if(7)
size = 7
icon = 'icons/effects/224x224.dmi'
icon_state = "emfield_s7"
pixel_x = -96 * PIXEL_MULTIPLIER
pixel_y = -96 * PIXEL_MULTIPLIER
//
changed = 7
for(var/obj/effect/fusion_particle_catcher/catcher in particle_catchers)
catcher.UpdateSize()
return changed
//the !!fun!! part
/obj/effect/fusion_em_field/proc/React()
//loop through the reactants in random order
var/list/react_pool = dormant_reactant_quantities.Copy()
//cant have any reactions if there aren't any reactants present
if(react_pool.len)
//determine a random amount to actually react this cycle, and remove it from the standard pool
//this is a hack, and quite nonrealistic :(
for(var/reactant in react_pool)
react_pool[reactant] = rand(Floor(react_pool[reactant]/2),react_pool[reactant])
dormant_reactant_quantities[reactant] -= react_pool[reactant]
if(!react_pool[reactant])
react_pool -= reactant
//loop through all the reacting reagents, picking out random reactions for them
var/list/produced_reactants = new/list
var/list/p_react_pool = react_pool.Copy()
while(p_react_pool.len)
//pick one of the unprocessed reacting reagents randomly
var/cur_p_react = pick(p_react_pool)
p_react_pool.Remove(cur_p_react)
//grab all the possible reactants to have a reaction with
var/list/possible_s_reacts = react_pool.Copy()
//if there is only one of a particular reactant, then it can not react with itself so remove it
possible_s_reacts[cur_p_react] -= 1
if(possible_s_reacts[cur_p_react] < 1)
possible_s_reacts.Remove(cur_p_react)
//loop through and work out all the possible reactions
var/list/possible_reactions = new/list
for(var/cur_s_react in possible_s_reacts)
if(possible_s_reacts[cur_s_react] < 1)
continue
var/decl/fusion_reaction/cur_reaction = get_fusion_reaction(cur_p_react, cur_s_react)
if(cur_reaction && plasma_temperature >= cur_reaction.minimum_energy_level)
possible_reactions.Add(cur_reaction)
//if there are no possible reactions here, abandon this primary reactant and move on
if(!possible_reactions.len)
continue
//split up the reacting atoms between the possible reactions
while(possible_reactions.len)
var/decl/fusion_reaction/cur_reaction = pick(possible_reactions)
possible_reactions.Remove(cur_reaction)
//set the randmax to be the lower of the two involved reactants
var/max_num_reactants = react_pool[cur_reaction.p_react] > react_pool[cur_reaction.s_react] ? \
react_pool[cur_reaction.s_react] : react_pool[cur_reaction.p_react]
if(max_num_reactants < 1)
continue
//make sure we have enough energy
if(plasma_temperature < cur_reaction.minimum_reaction_temperature)
continue
if(plasma_temperature < max_num_reactants * cur_reaction.energy_consumption)
max_num_reactants = round(plasma_temperature / cur_reaction.energy_consumption)
if(max_num_reactants < 1)
continue
//randomly determined amount to react
var/amount_reacting = rand(1, max_num_reactants)
//removing the reacting substances from the list of substances that are primed to react this cycle
//if there aren't enough of that substance (there should be) then modify the reactant amounts accordingly
if( react_pool[cur_reaction.p_react] - amount_reacting >= 0 )
react_pool[cur_reaction.p_react] -= amount_reacting
else
amount_reacting = react_pool[cur_reaction.p_react]
react_pool[cur_reaction.p_react] = 0
//same again for secondary reactant
if(react_pool[cur_reaction.s_react] - amount_reacting >= 0 )
react_pool[cur_reaction.s_react] -= amount_reacting
else
react_pool[cur_reaction.p_react] += amount_reacting - react_pool[cur_reaction.p_react]
amount_reacting = react_pool[cur_reaction.s_react]
react_pool[cur_reaction.s_react] = 0
plasma_temperature -= max_num_reactants * cur_reaction.energy_consumption // Remove the consumed energy.
plasma_temperature += max_num_reactants * cur_reaction.energy_production // Add any produced energy.
radiation += max_num_reactants * cur_reaction.radiation // Add any produced radiation.
tick_instability += max_num_reactants * cur_reaction.instability
// Create the reaction products.
for(var/reactant in cur_reaction.products)
var/success = 0
for(var/check_reactant in produced_reactants)
if(check_reactant == reactant)
produced_reactants[reactant] += cur_reaction.products[reactant] * amount_reacting
success = 1
break
if(!success)
produced_reactants[reactant] = cur_reaction.products[reactant] * amount_reacting
// Handle anything special. If this proc returns true, abort the current reaction.
if(cur_reaction.handle_reaction_special(src))
return
// This reaction is done, and can't be repeated this sub-cycle.
possible_reactions.Remove(cur_reaction.s_react)
// Loop through the newly produced reactants and add them to the pool.
for(var/reactant in produced_reactants)
AddParticles(reactant, produced_reactants[reactant])
// Check whether there are reactants left, and add them back to the pool.
for(var/reactant in react_pool)
AddParticles(reactant, react_pool[reactant])
/obj/effect/fusion_em_field/Destroy()
set_light(0)
RadiateAll()
for(var/obj/effect/fusion_particle_catcher/catcher in particle_catchers)
qdel(catcher)
if(owned_core)
owned_core.owned_field = null
owned_core = null
processing_objects.Remove(src)
. = ..()
/obj/effect/fusion_em_field/bullet_act(var/obj/item/projectile/Proj)
AddEnergy(Proj.damage)
update_icon()
return 0
#undef FUSION_HEAT_CAP

View File

@@ -0,0 +1,67 @@
/obj/item/weapon/fuel_assembly
name = "fuel rod assembly"
icon = 'icons/obj/machines/power/fusion.dmi'
icon_state = "fuel_assembly"
layer = 4
var/material_name
var/percent_depleted = 1
var/list/rod_quantities = list()
var/fuel_type = "composite"
var/fuel_colour
var/radioactivity = 0
var/const/initial_amount = 300
/obj/item/weapon/fuel_assembly/New(var/newloc, var/_material, var/_colour)
fuel_type = _material
fuel_colour = _colour
..(newloc)
/obj/item/weapon/fuel_assembly/initialize()
. = ..()
var/material/material = get_material_by_name(fuel_type)
if(istype(material))
name = "[material.use_name] fuel rod assembly"
desc = "A fuel rod for a fusion reactor. This one is made from [material.use_name]."
fuel_colour = material.icon_colour
fuel_type = material.use_name
if(material.radioactivity)
radioactivity = material.radioactivity
desc += " It is warm to the touch."
processing_objects += src
if(material.luminescence)
set_light(material.luminescence, material.luminescence, material.icon_colour)
else
name = "[fuel_type] fuel rod assembly"
desc = "A fuel rod for a fusion reactor. This one is made from [fuel_type]."
icon_state = "blank"
var/image/I = image(icon, "fuel_assembly")
I.color = fuel_colour
overlays += list(I, image(icon, "fuel_assembly_bracket"))
rod_quantities[fuel_type] = initial_amount
/obj/item/weapon/fuel_assembly/process()
if(!radioactivity)
return PROCESS_KILL
if(istype(loc, /turf))
radiation_repository.radiate(src, max(1,ceil(radioactivity/30)))
/obj/item/weapon/fuel_assembly/Destroy()
processing_objects -= src
return ..()
// Mapper shorthand.
/obj/item/weapon/fuel_assembly/deuterium/New(var/newloc)
..(newloc, "deuterium")
/obj/item/weapon/fuel_assembly/tritium/New(var/newloc)
..(newloc, "tritium")
/obj/item/weapon/fuel_assembly/phoron/New(var/newloc)
..(newloc, "phoron")
/obj/item/weapon/fuel_assembly/supermatter/New(var/newloc)
..(newloc, "supermatter")

View File

@@ -0,0 +1,54 @@
/obj/machinery/fusion_fuel_compressor
name = "fuel compressor"
icon = 'icons/obj/machines/power/fusion.dmi'
icon_state = "fuel_compressor1"
density = 1
anchored = 1
layer = 4
/obj/machinery/fusion_fuel_compressor/MouseDrop_T(var/atom/movable/target, var/mob/user)
if(user.incapacitated() || !user.Adjacent(src))
return
return do_special_fuel_compression(target, user)
/obj/machinery/fusion_fuel_compressor/proc/do_special_fuel_compression(var/obj/item/thing, var/mob/user)
if(istype(thing) && thing.reagents && thing.reagents.total_volume && thing.is_open_container())
if(thing.reagents.reagent_list.len > 1)
to_chat(user, "<span class='warning'>The contents of \the [thing] are impure and cannot be used as fuel.</span>")
return 1
if(thing.reagents.total_volume < 50)
to_chat(user, "<span class='warning'>You need at least fifty units of material to form a fuel rod.</span>")
return 1
var/datum/reagent/R = thing.reagents.reagent_list[1]
visible_message("<span class='notice'>\The [src] compresses the contents of \the [thing] into a new fuel assembly.</span>")
var/obj/item/weapon/fuel_assembly/F = new(get_turf(src), R.id, R.color)
thing.reagents.remove_reagent(R.id, R.volume)
user.put_in_hands(F)
else if(istype(thing, /obj/machinery/power/supermatter/shard))
var/obj/item/weapon/fuel_assembly/F = new(get_turf(src), "supermatter")
visible_message("<span class='notice'>\The [src] compresses the \[thing] into a new fuel assembly.</span>")
qdel(thing)
user.put_in_hands(F)
return 1
return 0
/obj/machinery/fusion_fuel_compressor/attackby(var/obj/item/thing, var/mob/user)
if(istype(thing, /obj/item/stack/material))
var/obj/item/stack/material/M = thing
var/material/mat = M.get_material()
if(!mat.is_fusion_fuel)
to_chat(user, "<span class='warning'>It would be pointless to make a fuel rod out of [mat.use_name].</span>")
return
if(M.get_amount() < 25)
to_chat(user, "<span class='warning'>You need at least 25 [mat.sheet_plural_name] to make a fuel rod.</span>")
return
var/obj/item/weapon/fuel_assembly/F = new(get_turf(src), mat.name)
visible_message("<span class='notice'>\The [src] compresses the [mat.use_name] into a new fuel assembly.</span>")
M.use(25)
user.put_in_hands(F)
else if(do_special_fuel_compression(thing, user))
return
return ..()

View File

@@ -0,0 +1,102 @@
/obj/machinery/computer/fusion_fuel_control
name = "fuel injection control computer"
icon = 'icons/obj/machines/power/fusion.dmi'
icon_state = "fuel"
var/id_tag
var/scan_range = 25
/obj/machinery/computer/fusion_fuel_control/attack_ai(mob/user)
attack_hand(user)
/obj/machinery/computer/fusion_fuel_control/attack_hand(mob/user)
add_fingerprint(user)
interact(user)
/obj/machinery/computer/fusion_fuel_control/interact(var/mob/user)
if(stat & (BROKEN|NOPOWER))
user.unset_machine()
user << browse(null, "window=fuel_control")
return
if (!istype(user, /mob/living/silicon) && get_dist(src, user) > 1)
user.unset_machine()
user << browse(null, "window=fuel_control")
return
if(!id_tag)
to_chat(user, "<span class='warning'>This console has not been assigned an ident tag. Please contact your system administrator or conduct a manual update with a standard multitool.</span>")
return
var/dat = "<B>Reactor Core Fuel Control #[id_tag]</B><BR>"
dat += {"
<hr>
<table border=1 width='100%'>
<tr>
<td><b>Contains</b></td>
<td><b>Assembly</b></td>
<td><b>Remaining</b></td>
</tr>"}
for(var/obj/machinery/fusion_fuel_injector/I in fuel_injectors)
if(!id_tag || !I.id_tag || I.id_tag != id_tag || get_dist(src, I) > scan_range)
continue
dat += "<tr>"
if(I.stat & (BROKEN|NOPOWER))
dat += "<td><span class='danger'>ERROR</span></td>"
dat += "<td><span class='danger'>ERROR</span></td>"
dat += "<td><span class='danger'>ERROR</span></td>"
else
dat += "<td>[I.cur_assembly ? I.cur_assembly.fuel_type : "NONE"]</td>"
if(I.cur_assembly)
dat += "<td><a href='?src=\ref[src];toggle_injecting=\ref[I]'>\[[I.injecting ? "Halt injecting" : "Begin injecting"]\]</a></td>"
else
dat += "<td>None</td>"
if(I.cur_assembly)
dat += "<td>[I.cur_assembly.percent_depleted * 100]%</td>"
else
dat += "<td>NA</td>"
dat += "</tr>"
dat += {"</table><hr>
<A href='?src=\ref[src];refresh=1'>Refresh</A>
<A href='?src=\ref[src];close=1'>Close</A><BR>"}
var/datum/browser/popup = new(user, "fuel_control", "Fusion Fuel Control Console", 800, 400, src)
popup.set_content(dat)
popup.open()
user.set_machine(src)
/obj/machinery/computer/fusion_fuel_control/Topic(href, href_list)
if(..())
return 1
if(href_list["toggle_injecting"])
var/obj/machinery/fusion_fuel_injector/I = locate(href_list["toggle_injecting"])
if(I.id_tag != id_tag || get_dist(src, I) > scan_range)
return
if(istype(I))
if(I.injecting)
I.StopInjecting()
else
I.BeginInjecting()
if( href_list["close"] )
usr << browse(null, "window=fuel_control")
usr.unset_machine()
updateDialog()
/obj/machinery/computer/fusion_fuel_control/attackby(var/obj/item/W, var/mob/user)
if(ismultitool(W))
var/new_ident = input("Enter a new ident tag.", "Fuel Control", id_tag) as null|text
if(new_ident && user.Adjacent(src))
id_tag = new_ident
return
return ..()

View File

@@ -0,0 +1,153 @@
var/list/fuel_injectors = list()
/obj/machinery/fusion_fuel_injector
name = "fuel injector"
icon = 'icons/obj/machines/power/fusion.dmi'
icon_state = "injector0"
density = 1
anchored = 0
req_access = list(access_engine)
use_power = 1
idle_power_usage = 10
active_power_usage = 500
var/fuel_usage = 0.0001
var/id_tag
var/injecting = 0
var/obj/item/weapon/fuel_assembly/cur_assembly
/obj/machinery/fusion_fuel_injector/New()
..()
fuel_injectors += src
tag = null
/obj/machinery/fusion_fuel_injector/Destroy()
if(cur_assembly)
cur_assembly.forceMove(get_turf(src))
cur_assembly = null
fuel_injectors -= src
return ..()
/obj/machinery/fusion_fuel_injector/mapped
anchored = 1
/obj/machinery/fusion_fuel_injector/process()
if(injecting)
if(stat & (BROKEN|NOPOWER))
StopInjecting()
else
Inject()
/obj/machinery/fusion_fuel_injector/attackby(obj/item/W, mob/user)
if(ismultitool(W))
var/new_ident = input("Enter a new ident tag.", "Fuel Injector", id_tag) as null|text
if(new_ident && user.Adjacent(src))
id_tag = new_ident
return
if(istype(W, /obj/item/weapon/fuel_assembly))
if(injecting)
to_chat(user, "<span class='warning'>Shut \the [src] off before playing with the fuel rod!</span>")
return
if(cur_assembly)
cur_assembly.forceMove(get_turf(src))
visible_message("<span class='notice'>\The [user] swaps \the [src]'s [cur_assembly] for \a [W].</span>")
else
visible_message("<span class='notice'>\The [user] inserts \a [W] into \the [src].</span>")
user.drop_from_inventory(W)
W.forceMove(src)
if(cur_assembly)
cur_assembly.forceMove(get_turf(src))
user.put_in_hands(cur_assembly)
cur_assembly = W
return
if(iswrench(W))
if(injecting)
to_chat(user, "<span class='warning'>Shut \the [src] off first!</span>")
return
anchored = !anchored
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
if(anchored)
user.visible_message("\The [user] secures \the [src] to the floor.")
else
user.visible_message("\The [user] unsecures \the [src] from the floor.")
return
return ..()
/obj/machinery/fusion_fuel_injector/attack_hand(mob/user)
if(injecting)
to_chat(user, "<span class='warning'>Shut \the [src] off before playing with the fuel rod!</span>")
return
if(cur_assembly)
cur_assembly.forceMove(get_turf(src))
user.put_in_hands(cur_assembly)
visible_message("<span class='notice'>\The [user] removes \the [cur_assembly] from \the [src].</span>")
cur_assembly = null
return
else
to_chat(user, "<span class='warning'>There is no fuel rod in \the [src].</span>")
return
/obj/machinery/fusion_fuel_injector/proc/BeginInjecting()
if(!injecting && cur_assembly)
icon_state = "injector1"
injecting = 1
use_power = 1
/obj/machinery/fusion_fuel_injector/proc/StopInjecting()
if(injecting)
injecting = 0
icon_state = "injector0"
use_power = 0
/obj/machinery/fusion_fuel_injector/proc/Inject()
if(!injecting)
return
if(cur_assembly)
var/amount_left = 0
for(var/reagent in cur_assembly.rod_quantities)
if(cur_assembly.rod_quantities[reagent] > 0)
var/amount = cur_assembly.rod_quantities[reagent] * fuel_usage
var/numparticles = round(amount * 1000)
if(numparticles < 1)
numparticles = 1
var/obj/effect/accelerated_particle/A = new/obj/effect/accelerated_particle(get_turf(src), dir)
A.particle_type = reagent
A.additional_particles = numparticles - 1
A.move(1)
if(cur_assembly)
cur_assembly.rod_quantities[reagent] -= amount
amount_left += cur_assembly.rod_quantities[reagent]
if(cur_assembly)
cur_assembly.percent_depleted = amount_left / cur_assembly.initial_amount
flick("injector-emitting",src)
else
StopInjecting()
/obj/machinery/fusion_fuel_injector/verb/rotate_clock()
set category = "Object"
set name = "Rotate Generator (Clockwise)"
set src in view(1)
if (usr.incapacitated() || usr.restrained() || anchored)
return
src.dir = turn(src.dir, -90)
/obj/machinery/fusion_fuel_injector/verb/rotate_anticlock()
set category = "Object"
set name = "Rotate Generator (Counter-clockwise)"
set src in view(1)
if (usr.incapacitated() || usr.restrained() || anchored)
return
src.dir = turn(src.dir, 90)

View File

@@ -0,0 +1,89 @@
/obj/item/weapon/circuitboard/fusion_core_control
name = "circuit board (fusion core controller)"
build_path = /obj/machinery/computer/fusion_core_control
origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4)
/obj/item/weapon/circuitboard/fusion_fuel_compressor
name = "circuit board (fusion fuel compressor)"
build_path = /obj/machinery/fusion_fuel_compressor
board_type = "machine"
origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 4, TECH_MATERIAL = 4)
req_components = list(
/obj/item/weapon/stock_parts/manipulator/pico = 2,
/obj/item/weapon/stock_parts/matter_bin/super = 2,
/obj/item/weapon/stock_parts/console_screen = 1,
/obj/item/stack/cable_coil = 5
)
/obj/item/weapon/circuitboard/fusion_fuel_control
name = "circuit board (fusion fuel controller)"
build_path = /obj/machinery/computer/fusion_fuel_control
origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4)
/obj/item/weapon/circuitboard/gyrotron_control
name = "circuit board (gyrotron controller)"
build_path = /obj/machinery/computer/gyrotron_control
origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4)
/obj/item/weapon/circuitboard/fusion_core
name = "internal circuitry (fusion core)"
build_path = /obj/machinery/power/fusion_core
board_type = "machine"
origin_tech = list(TECH_BLUESPACE = 2, TECH_MAGNET = 4, TECH_POWER = 4)
req_components = list(
/obj/item/weapon/stock_parts/manipulator/pico = 2,
/obj/item/weapon/stock_parts/micro_laser/ultra = 1,
/obj/item/weapon/stock_parts/subspace/crystal = 1,
/obj/item/weapon/stock_parts/console_screen = 1,
/obj/item/stack/cable_coil = 5
)
/obj/item/weapon/circuitboard/fusion_injector
name = "internal circuitry (fusion fuel injector)"
build_path = /obj/machinery/fusion_fuel_injector
board_type = "machine"
origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 4, TECH_MATERIAL = 4)
req_components = list(
/obj/item/weapon/stock_parts/manipulator/pico = 2,
/obj/item/weapon/stock_parts/scanning_module/phasic = 1,
/obj/item/weapon/stock_parts/matter_bin/super = 1,
/obj/item/weapon/stock_parts/console_screen = 1,
/obj/item/stack/cable_coil = 5
)
/datum/design/circuit/fusion
name = "fusion core control console"
id = "fusion_core_control"
build_path = /obj/item/weapon/circuitboard/fusion_core_control
sort_string = "LAAAD"
req_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 3, TECH_MATERIAL = 3)
/datum/design/circuit/fusion/fuel_compressor
name = "fusion fuel compressor"
id = "fusion_fuel_compressor"
build_path = /obj/item/weapon/circuitboard/fusion_fuel_compressor
sort_string = "LAAAE"
/datum/design/circuit/fusion/fuel_control
name = "fusion fuel control console"
id = "fusion_fuel_control"
build_path = /obj/item/weapon/circuitboard/fusion_fuel_control
sort_string = "LAAAF"
/datum/design/circuit/fusion/gyrotron_control
name = "gyrotron control console"
id = "gyrotron_control"
build_path = /obj/item/weapon/circuitboard/gyrotron_control
sort_string = "LAAAG"
/datum/design/circuit/fusion/core
name = "fusion core"
id = "fusion_core"
build_path = /obj/item/weapon/circuitboard/fusion_core
sort_string = "LAAAH"
/datum/design/circuit/fusion/injector
name = "fusion fuel injector"
id = "fusion_injector"
build_path = /obj/item/weapon/circuitboard/fusion_injector
sort_string = "LAAAI"

View File

@@ -0,0 +1,41 @@
/obj/effect/fusion_particle_catcher
icon = 'icons/effects/effects.dmi'
density = 1
anchored = 1
invisibility = 101
var/obj/effect/fusion_em_field/parent
var/mysize = 0
light_color = COLOR_BLUE
/obj/effect/fusion_particle_catcher/Destroy()
. =..()
parent.particle_catchers -= src
parent = null
/obj/effect/fusion_particle_catcher/proc/SetSize(var/newsize)
name = "collector [newsize]"
mysize = newsize
UpdateSize()
/obj/effect/fusion_particle_catcher/proc/AddParticles(var/name, var/quantity = 1)
if(parent && parent.size >= mysize)
parent.AddParticles(name, quantity)
return 1
return 0
/obj/effect/fusion_particle_catcher/proc/UpdateSize()
if(parent.size >= mysize)
density = 1
name = "collector [mysize] ON"
else
density = 0
name = "collector [mysize] OFF"
/obj/effect/fusion_particle_catcher/bullet_act(var/obj/item/projectile/Proj)
parent.AddEnergy(Proj.damage)
update_icon()
return 0
/obj/effect/fusion_particle_catcher/CanPass(var/atom/movable/mover, var/turf/target, var/height=0, var/air_group=0)
return ismob(mover)

View File

@@ -0,0 +1,164 @@
var/list/fusion_reactions
/decl/fusion_reaction
var/p_react = "" // Primary reactant.
var/s_react = "" // Secondary reactant.
var/minimum_energy_level = 1
var/energy_consumption = 0
var/energy_production = 0
var/radiation = 0
var/instability = 0
var/list/products = list()
var/minimum_reaction_temperature = 100
/decl/fusion_reaction/proc/handle_reaction_special(var/obj/effect/fusion_em_field/holder)
return 0
proc/get_fusion_reaction(var/p_react, var/s_react, var/m_energy)
if(!fusion_reactions)
fusion_reactions = list()
for(var/rtype in typesof(/decl/fusion_reaction) - /decl/fusion_reaction)
var/decl/fusion_reaction/cur_reaction = new rtype()
if(!fusion_reactions[cur_reaction.p_react])
fusion_reactions[cur_reaction.p_react] = list()
fusion_reactions[cur_reaction.p_react][cur_reaction.s_react] = cur_reaction
if(!fusion_reactions[cur_reaction.s_react])
fusion_reactions[cur_reaction.s_react] = list()
fusion_reactions[cur_reaction.s_react][cur_reaction.p_react] = cur_reaction
if(fusion_reactions.Find(p_react))
var/list/secondary_reactions = fusion_reactions[p_react]
if(secondary_reactions.Find(s_react))
return fusion_reactions[p_react][s_react]
// Material fuels
// deuterium
// tritium
// phoron
// supermatter
// Virtual fuels
// helium-3
// lithium-6
// boron-11
// Basic power production reactions.
/decl/fusion_reaction/deuterium_deuterium
p_react = "deuterium"
s_react = "deuterium"
energy_consumption = 1
energy_production = 2
// Advanced production reactions (todo)
/decl/fusion_reaction/deuterium_helium
p_react = "deuterium"
s_react = "helium-3"
energy_consumption = 1
energy_production = 5
radiation = 2
/decl/fusion_reaction/deuterium_tritium
p_react = "deuterium"
s_react = "tritium"
energy_consumption = 1
energy_production = 1
products = list("helium-3" = 1)
instability = 0.5
radiation = 3
/decl/fusion_reaction/deuterium_lithium
p_react = "deuterium"
s_react = "lithium"
energy_consumption = 2
energy_production = 0
radiation = 3
products = list("tritium"= 1)
instability = 1
// Unideal/material production reactions
/decl/fusion_reaction/oxygen_oxygen
p_react = "oxygen"
s_react = "oxygen"
energy_consumption = 10
energy_production = 0
instability = 5
radiation = 5
products = list("silicon"= 1)
/decl/fusion_reaction/iron_iron
p_react = "iron"
s_react = "iron"
products = list("silver" = 1, "gold" = 1, "platinum" = 1) // Not realistic but w/e
energy_consumption = 10
energy_production = 0
instability = 2
minimum_reaction_temperature = 10000
/decl/fusion_reaction/phoron_hydrogen
p_react = "hydrogen"
s_react = "phoron"
energy_consumption = 10
energy_production = 0
instability = 5
products = list("mydrogen" = 1)
minimum_reaction_temperature = 8000
// VERY UNIDEAL REACTIONS.
/decl/fusion_reaction/phoron_supermatter
p_react = "supermatter"
s_react = "phoron"
energy_consumption = 0
energy_production = 5
radiation = 20
instability = 20
/decl/fusion_reaction/phoron_supermatter/handle_reaction_special(var/obj/effect/fusion_em_field/holder)
wormhole_event()
var/turf/origin = get_turf(holder)
holder.Rupture()
qdel(holder)
var/radiation_level = rand(100, 200)
// Copied from the SM for proof of concept. //Not any more --Cirra //Use the whole z proc --Leshana
radiation_repository.z_radiate(locate(1, 1, holder.z), radiation_level, 1)
for(var/mob/living/mob in living_mob_list)
var/turf/T = get_turf(mob)
if(T && (holder.z == T.z))
if(istype(mob, /mob/living/carbon/human))
var/mob/living/carbon/human/H = mob
H.hallucination += rand(100,150)
for(var/obj/machinery/fusion_fuel_injector/I in range(world.view, origin))
if(I.cur_assembly && I.cur_assembly.fuel_type == "supermatter")
explosion(get_turf(I), 1, 2, 3)
spawn(5)
if(I && I.loc)
qdel(I)
sleep(5)
explosion(origin, 1, 2, 5)
return 1
// High end reactions.
/decl/fusion_reaction/boron_hydrogen
p_react = "boron"
s_react = "hydrogen"
minimum_energy_level = FUSION_HEAT_CAP * 0.5
energy_consumption = 3
energy_production = 15
radiation = 3
instability = 3
/decl/fusion_reaction/hydrogen_hydrogen
p_react = "hydrogen"
s_react = "hydrogen"
minimum_energy_level = FUSION_HEAT_CAP * 0.75
energy_consumption = 0
energy_production = 20
radiation = 5
instability = 5

View File

@@ -0,0 +1,57 @@
var/list/gyrotrons = list()
/obj/machinery/power/emitter/gyrotron
name = "gyrotron"
icon = 'icons/obj/machines/power/fusion.dmi'
desc = "It is a heavy duty industrial gyrotron suited for powering fusion reactors."
icon_state = "emitter-off"
req_access = list(access_engine)
use_power = 1
active_power_usage = 50000
var/id_tag
var/rate = 3
var/mega_energy = 1
/obj/machinery/power/emitter/gyrotron/anchored
anchored = 1
state = 2
/obj/machinery/power/emitter/gyrotron/initialize()
gyrotrons += src
active_power_usage = mega_energy * 50000
. = ..()
/obj/machinery/power/emitter/gyrotron/Destroy()
gyrotrons -= src
return ..()
/obj/machinery/power/emitter/gyrotron/process()
active_power_usage = mega_energy * 50000
. = ..()
/obj/machinery/power/emitter/gyrotron/get_rand_burst_delay()
return rate * 10
/obj/machinery/power/emitter/gyrotron/get_burst_delay()
return rate * 10
/obj/machinery/power/emitter/gyrotron/get_emitter_beam()
var/obj/item/projectile/beam/emitter/E = ..()
E.damage = mega_energy * 50
return E
/obj/machinery/power/emitter/gyrotron/update_icon()
if (active && powernet && avail(active_power_usage))
icon_state = "emitter-on"
else
icon_state = "emitter-off"
/obj/machinery/power/emitter/gyrotron/attackby(var/obj/item/W, var/mob/user)
if(ismultitool(W))
var/new_ident = input("Enter a new ident tag.", "Gyrotron", id_tag) as null|text
if(new_ident && user.Adjacent(src))
id_tag = new_ident
return
return ..()

View File

@@ -0,0 +1,97 @@
/obj/machinery/computer/gyrotron_control
name = "gyrotron control console"
icon = 'icons/obj/machines/power/fusion.dmi'
icon_state = "engine"
light_color = COLOR_BLUE
var/id_tag
var/scan_range = 25
/obj/machinery/computer/gyrotron_control/attack_ai(var/mob/user)
attack_hand(user)
/obj/machinery/computer/gyrotron_control/attack_hand(var/mob/user)
add_fingerprint(user)
interact(user)
/obj/machinery/computer/gyrotron_control/interact(var/mob/user)
if(!id_tag)
to_chat(user, "<span class='warning'>This console has not been assigned an ident tag. Please contact your system administrator or conduct a manual update with a standard multitool.</span>")
return
var/dat = "<td><b>Gyrotron controller #[id_tag]</b>"
dat = "<table><tr>"
dat += "<td><b>Mode</b></td>"
dat += "<td><b>Fire Delay</b></td>"
dat += "<td><b>Power</b></td>"
dat += "</tr>"
for(var/obj/machinery/power/emitter/gyrotron/G in gyrotrons)
if(!G || G.id_tag != id_tag || get_dist(src, G) > scan_range)
continue
dat += "<tr>"
if(G.state != 2 || (G.stat & (NOPOWER | BROKEN))) //Error data not found.
dat += "<td><span style='color: red'>ERROR</span></td>"
dat += "<td><span style='color: red'>ERROR</span></td>"
dat += "<td><span style='color: red'>ERROR</span></td>"
else
dat += "<td><a href='?src=\ref[src];machine=\ref[G];toggle=1'>[G.active ? "Emitting" : "Standing By"]</a></td>"
dat += "<td><a href='?src=\ref[src];machine=\ref[G];modifyrate=1'>[G.rate]</a></td>"
dat += "<td><a href='?src=\ref[src];machine=\ref[G];modifypower=1'>[G.mega_energy]</a></td>"
dat += "</tr></table>"
var/datum/browser/popup = new(user, "gyrotron_controller_[id_tag]", "Gyrotron Remote Control Console", 500, 400, src)
popup.set_content(dat)
popup.open()
add_fingerprint(user)
user.set_machine(src)
/obj/machinery/computer/gyrotron_control/Topic(var/href, var/list/href_list)
. = ..()
if(.)
return
if(stat & (NOPOWER | BROKEN))
return
var/obj/machinery/power/emitter/gyrotron/G = locate(href_list["machine"])
if(!G || G.id_tag != id_tag || get_dist(src, G) > scan_range)
return
if(href_list["modifypower"])
var/new_val = input("Enter new emission power level (1 - 50)", "Modifying power level", G.mega_energy) as num
if(!new_val)
to_chat(usr, "<span class='warning'>That's not a valid number.</span>")
return 1
G.mega_energy = Clamp(new_val, 1, 50)
G.active_power_usage = G.mega_energy * 1500
updateUsrDialog()
return 1
if(href_list["modifyrate"])
var/new_val = input("Enter new emission delay between 1 and 10 seconds.", "Modifying emission rate", G.rate) as num
if(!new_val)
to_chat(usr, "<span class='warning'>That's not a valid number.</span>")
return 1
G.rate = Clamp(new_val, 1, 10)
updateUsrDialog()
return 1
if(href_list["toggle"])
G.activate(usr)
updateUsrDialog()
return 1
return 0
/obj/machinery/computer/gyrotron_control/attackby(var/obj/item/W, var/mob/user)
if(ismultitool(W))
var/new_ident = input("Enter a new ident tag.", "Gyrotron Control", id_tag) as null|text
if(new_ident && user.Adjacent(src))
id_tag = new_ident
return
return ..()

View File

@@ -75,7 +75,7 @@
src.active = 1
user << "You turn on [src]."
src.shot_number = 0
src.fire_delay = 100
src.fire_delay = get_initial_fire_delay()
message_admins("Emitter turned on by [key_name(user, user.client)](<A HREF='?_src_=holder;adminmoreinfo=\ref[user]'>?</A>) in ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)",0,1)
log_game("Emitter turned on by [user.ckey]([user]) in ([x],[y],[z])")
investigate_log("turned <font color='green'>on</font> by [user.key]","singulo")
@@ -119,10 +119,10 @@
src.last_shot = world.time
if(src.shot_number < burst_shots)
src.fire_delay = 2
src.fire_delay = get_burst_delay() //R-UST port
src.shot_number ++
else
src.fire_delay = rand(min_burst_delay, max_burst_delay)
src.fire_delay = get_rand_burst_delay() //R-UST port
src.shot_number = 0
//need to calculate the power per shot as the emitter doesn't fire continuously.
@@ -135,7 +135,7 @@
s.set_up(5, 1, src)
s.start()
var/obj/item/projectile/beam/emitter/A = new /obj/item/projectile/beam/emitter( src.loc )
var/obj/item/projectile/beam/emitter/A = get_emitter_beam()
A.damage = round(power_per_shot/EMITTER_DAMAGE_POWER_TRANSFER)
A.launch( get_step(src.loc, src.dir) )
@@ -266,3 +266,16 @@
user << "<span class='danger'>\The [src] is damaged.</span>"
if(77 to 99)
user << "<span class='warning'>\The [src] is slightly damaged.</span>"
//R-UST port
/obj/machinery/power/emitter/proc/get_initial_fire_delay()
return 100
/obj/machinery/power/emitter/proc/get_rand_burst_delay()
return rand(min_burst_delay, max_burst_delay)
/obj/machinery/power/emitter/proc/get_burst_delay()
return 2
/obj/machinery/power/emitter/proc/get_emitter_beam()
return new /obj/item/projectile/beam/emitter(get_turf(src))

View File

@@ -43,6 +43,21 @@
toxmob(A)
if((istype(A,/obj/machinery/the_singularitygen))||(istype(A,/obj/singularity/)))
A:energy += energy
//R-UST port
else if(istype(A,/obj/machinery/power/fusion_core))
var/obj/machinery/power/fusion_core/collided_core = A
if(particle_type && particle_type != "neutron")
if(collided_core.AddParticles(particle_type, 1 + additional_particles))
collided_core.owned_field.plasma_temperature += mega_energy
collided_core.owned_field.energy += energy
loc = null
else if(istype(A, /obj/effect/fusion_particle_catcher))
var/obj/effect/fusion_particle_catcher/PC = A
if(particle_type && particle_type != "neutron")
if(PC.parent.owned_core.AddParticles(particle_type, 1 + additional_particles))
PC.parent.plasma_temperature += mega_energy
PC.parent.energy += energy
loc = null
return

View File

@@ -43,6 +43,31 @@
color = "#003333"
strength = 10
//R-UST port
// Produced during deuterium synthesis. Super poisonous, SUPER flammable (doesn't need oxygen to burn).
/datum/reagent/toxin/phoroxygen
name = "Oxyphoron"
id = "oxyphoron"
description = "An exceptionally flammable molecule formed from deuterium synthesis."
strength = 80
var/fire_mult = 30
/datum/reagent/toxin/phoroxygen/touch_mob(var/mob/living/L, var/amount)
if(istype(L))
L.adjust_fire_stacks(amount / fire_mult)
/datum/reagent/toxin/phoroxygen/affect_touch(var/mob/living/carbon/M, var/alien, var/removed)
M.take_organ_damage(0, removed * 0.1) //being splashed directly with oxyphoron causes minor chemical burns
if(prob(10 * fire_mult))
M.pl_effects()
/datum/reagent/toxin/phoroxygen/touch_turf(var/turf/simulated/T)
if(!istype(T))
return
T.assume_gas("oxygen", ceil(volume/2), T20C)
T.assume_gas("phoron", ceil(volume/2), T20C)
remove_self(volume)
/datum/reagent/toxin/spidertoxin
name = "Spidertoxin"
id = "spidertoxin"

View File

@@ -1842,7 +1842,6 @@
required_reagents = list("tea" = 5, "berryjuice" = 1)
result_amount = 6
/datum/chemical_reaction/drinks/sakebomb
name = "Sake Bomb"
id = "sakebomb"
result = "sakebomb"
@@ -1863,7 +1862,6 @@
required_reagents = list("sake" = 2, "vodka" = 2, "tomatojuice" = 1)
result_amount = 5
/datum/chemical_reaction/drinks/tokyorose
name = "Tokyo Rose"
id = "tokyorose"
result = "tokyorose"
@@ -1906,9 +1904,6 @@
result_amount = 3
/datum/chemical_reaction/drinks/euphoria
name = "Euphoria"
id = "euphoria"
result = "euphoria"
required_reagents = list("specialwhiskey" = 1, "cognac" = 2)
result_amount = 3
@@ -1916,7 +1911,6 @@
name = "Xanadu Cannon"
id = "xanaducannon"
result = "xanaducannon"
required_reagents = list("ale" = 1, "dr_gibb" = 1)
result_amount = 2
/datum/chemical_reaction/drinks/debugger
@@ -1945,4 +1939,17 @@
id = "chrysanthemum"
result = "chrysanthemum"
required_reagents = list("sake" = 1, "melonliquor" = 1)
result_amount = 2
result_amount = 2
/datum/chemical_reaction/deuterium
name = "Deuterium"
id = "deuterium"
result = null
required_reagents = list("water" = 10)
catalysts = list("oxyphoron" = 5)
result_amount = 1
/datum/chemical_reaction/deuterium/on_reaction(var/datum/reagents/holder, var/created_volume)
var/turf/T = get_turf(holder.my_atom)
if(istype(T)) new /obj/item/stack/material/deuterium(T, created_volume)
return

View File

@@ -0,0 +1,251 @@
#define SETUP_OK 1 // All good
#define SETUP_WARNING 2 // Something that shouldn't happen happened, but it's not critical so we will continue
#define SETUP_ERROR 3 // Something bad happened, and it's important so we won't continue setup.
#define SETUP_DELAYED 4 // Wait for other things first.
#define ENERGY_NITROGEN 115 // Roughly 8 emitter shots.
#define ENERGY_CARBONDIOXIDE 150 // Roughly 10 emitter shots.
#define ENERGY_PHORON 300 // Roughly 20 emitter shots. Phoron can take more but this is enough to max out both SMESs anyway.
/datum/admins/proc/setup_supermatter()
set category = "Debug"
set name = "Setup Supermatter"
set desc = "Allows you to start the Supermatter engine."
if (!istype(src,/datum/admins))
src = usr.client.holder
if (!istype(src,/datum/admins))
to_chat(usr, "Error: you are not an admin!")
return
var/response = input(usr, "Are you sure? This will start up the engine with selected gas as coolant.", "Engine setup") as null|anything in list("N2", "CO2", "PH", "Abort")
if(!response || response == "Abort")
return
var/errors = 0
var/warnings = 0
var/success = 0
log_and_message_admins("## SUPERMATTER SETUP - Setup initiated by [usr] using coolant type [response].")
// CONFIGURATION PHASE
// Coolant canisters, set types according to response.
for(var/obj/effect/engine_setup/coolant_canister/C in world)
switch(response)
if("N2")
C.canister_type = /obj/machinery/portable_atmospherics/canister/nitrogen/engine_setup/
continue
if("CO2")
C.canister_type = /obj/machinery/portable_atmospherics/canister/carbon_dioxide/engine_setup/
continue
if("PH")
C.canister_type = /obj/machinery/portable_atmospherics/canister/phoron/engine_setup/
continue
for(var/obj/effect/engine_setup/core/C in world)
switch(response)
if("N2")
C.energy_setting = ENERGY_NITROGEN
continue
if("CO2")
C.energy_setting = ENERGY_CARBONDIOXIDE
continue
if("PH")
C.energy_setting = ENERGY_PHORON
continue
for(var/obj/effect/engine_setup/filter/F in world)
F.coolant = response
var/list/delayed_objects = list()
// SETUP PHASE
for(var/obj/effect/engine_setup/S in world)
var/result = S.activate(0)
switch(result)
if(SETUP_OK)
success++
continue
if(SETUP_WARNING)
warnings++
continue
if(SETUP_ERROR)
errors++
log_and_message_admins("## SUPERMATTER SETUP - Error encountered! Aborting.")
break
if(SETUP_DELAYED)
delayed_objects.Add(S)
continue
if(!errors)
for(var/obj/effect/engine_setup/S in delayed_objects)
var/result = S.activate(1)
switch(result)
if(SETUP_OK)
success++
continue
if(SETUP_WARNING)
warnings++
continue
if(SETUP_ERROR)
errors++
log_and_message_admins("## SUPERMATTER SETUP - Error encountered! Aborting.")
break
log_and_message_admins("## SUPERMATTER SETUP - Setup completed with [errors] errors, [warnings] warnings and [success] successful steps.")
return
/obj/effect/engine_setup/
name = "Engine Setup Marker"
desc = "You shouldn't see this."
invisibility = 101
anchored = 1
density = 0
icon = 'icons/mob/screen1.dmi'
icon_state = "x3"
/obj/effect/engine_setup/proc/activate(var/last = 0)
return 1
// Tries to locate a pump, enables it, and sets it to MAX. Triggers warning if unable to locate a pump.
/obj/effect/engine_setup/pump_max/
name = "Pump Setup Marker"
/obj/effect/engine_setup/pump_max/activate()
..()
var/obj/machinery/atmospherics/binary/pump/P = locate() in get_turf(src)
if(!P)
log_and_message_admins("## WARNING: Unable to locate pump at [x] [y] [z]!")
return SETUP_WARNING
P.target_pressure = P.max_pressure_setting
P.use_power = 1
P.update_icon()
return SETUP_OK
// Spawns an empty canister on this turf, if it has a connector port. Triggers warning if unable to find a connector port
/obj/effect/engine_setup/empty_canister/
name = "Empty Canister Marker"
/obj/effect/engine_setup/empty_canister/activate()
..()
var/obj/machinery/atmospherics/portables_connector/P = locate() in get_turf(src)
if(!P)
log_and_message_admins("## WARNING: Unable to locate connector port at [x] [y] [z]!")
return SETUP_WARNING
new/obj/machinery/portable_atmospherics/canister(get_turf(src)) // Canisters automatically connect to connectors in New()
return SETUP_OK
// Spawns a coolant canister on this turf, if it has a connector port.
// Triggers error when unable to locate connector port or when coolant canister type is unset.
/obj/effect/engine_setup/coolant_canister/
name = "Coolant Canister Marker"
var/canister_type = null
/obj/effect/engine_setup/coolant_canister/activate()
..()
var/obj/machinery/atmospherics/portables_connector/P = locate() in get_turf(src)
if(!P)
log_and_message_admins("## ERROR: Unable to locate coolant connector port at [x] [y] [z]!")
return SETUP_ERROR
if(!canister_type)
log_and_message_admins("## ERROR: Canister type unset at [x] [y] [z]!")
return SETUP_ERROR
new canister_type(get_turf(src))
return SETUP_OK
// Energises the supermatter. Errors when unable to locate supermatter.
/obj/effect/engine_setup/core/
name = "Supermatter Core Marker"
var/energy_setting = 0
/obj/effect/engine_setup/core/activate(var/last = 0)
if(!last)
return SETUP_DELAYED
..()
var/obj/machinery/power/supermatter/SM = locate() in get_turf(src)
if(!SM)
log_and_message_admins("## ERROR: Unable to locate supermatter core at [x] [y] [z]!")
return SETUP_ERROR
if(!energy_setting)
log_and_message_admins("## ERROR: Energy setting unset at [x] [y] [z]!")
return SETUP_ERROR
SM.power = energy_setting
return SETUP_OK
// Tries to enable the SMES on max input/output settings. With load balancing it should be fine as long as engine outputs at least ~500kW
/obj/effect/engine_setup/smes/
name = "SMES Marker"
/obj/effect/engine_setup/smes/activate()
..()
var/obj/machinery/power/smes/S = locate() in get_turf(src)
if(!S)
log_and_message_admins("## WARNING: Unable to locate SMES unit at [x] [y] [z]!")
return SETUP_WARNING
S.input_attempt = 1
S.output_attempt = 1
S.input_level = S.input_level_max
S.output_level = S.output_level_max
S.update_icon()
return SETUP_OK
// Sets up filters. This assumes filters are set to filter out N2 back to the core loop by default!
/obj/effect/engine_setup/filter/
name = "Omni Filter Marker"
var/coolant = null
/obj/effect/engine_setup/filter/activate()
..()
var/obj/machinery/atmospherics/omni/filter/F = locate() in get_turf(src)
if(!F)
log_and_message_admins("## WARNING: Unable to locate omni filter at [x] [y] [z]!")
return SETUP_WARNING
if(!coolant)
log_and_message_admins("## WARNING: No coolant type set at [x] [y] [z]!")
return SETUP_WARNING
// Non-nitrogen coolant, adjust the filter's config first.
if(coolant != "N2")
for(var/datum/omni_port/P in F.ports)
if(P.mode != ATM_N2)
continue
if(coolant == "PH")
P.mode = ATM_P
break
else if(coolant == "CO2")
P.mode = ATM_CO2
break
else
log_and_message_admins("## WARNING: Inapropriate filter coolant type set at [x] [y] [z]!")
return SETUP_WARNING
F.rebuild_filtering_list()
F.use_power = 1
F.update_icon()
return SETUP_OK
#undef SETUP_OK
#undef SETUP_WARNING
#undef SETUP_ERROR
#undef SETUP_DELAYED
#undef ENERGY_NITROGEN
#undef ENERGY_CARBONDIOXIDE
#undef ENERGY_PHORON