Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 122 additions & 116 deletions _maps/map_files/YogStation/YogStation.dmm

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions code/__DEFINES/atmospherics.dm
Original file line number Diff line number Diff line change
Expand Up @@ -492,5 +492,11 @@ GLOBAL_LIST_INIT(pipe_paint_colors, list(
"yellow" = rgb(255,198,0)
))

///ROT Miasma
#define MIASMA_CORPSE_MOLES 0.02
#define MIASMA_GIBS_MOLES 0.005

//PIPENET UPDATE STATUS
#define PIPENET_UPDATE_STATUS_DORMANT 0
#define PIPENET_UPDATE_STATUS_REACT_NEEDED 1
#define PIPENET_UPDATE_STATUS_RECONCILE_NEEDED 2
14 changes: 8 additions & 6 deletions code/controllers/subsystem/air.dm
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,9 @@ SUBSYSTEM_DEF(air)
var/timer = TICK_USAGE_REAL
if(currentpart == SSAIR_REBUILD_PIPENETS)
var/list/pipenet_rebuilds = pipenets_needing_rebuilt
for(var/thing in pipenet_rebuilds)
var/obj/machinery/atmospherics/AT = thing
for(var/obj/machinery/atmospherics/AT as() in pipenet_rebuilds)
if(!AT) //If a null somehow shows up here, this next line runtimes and the subsystem dies
continue
AT.build_network()
cost_rebuilds = MC_AVERAGE(cost_rebuilds, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
pipenets_needing_rebuilt.Cut()
Expand Down Expand Up @@ -184,12 +185,13 @@ SUBSYSTEM_DEF(air)
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
var/datum/thing = currentrun[currentrun.len]
var/datum/pipeline/P = currentrun[currentrun.len]
currentrun.len--
if(thing)
thing.process()
if(P)
if(P.update)
P.update = P.reconcile_air()
else
networks.Remove(thing)
networks.Remove(P)
if(MC_TICK_CHECK)
return

Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/items/tanks/tanks.dm
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@

/obj/item/tank/process()
//Allow for reactions
air_contents.react()
air_contents.react(src)
check_status()

/obj/item/tank/proc/check_status()
Expand Down
8 changes: 8 additions & 0 deletions code/modules/admin/verbs/atmosdebug.dm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@
for(var/obj/machinery/atmospherics/pipe/simple/pipe in GLOB.machines)
if(pipe.z && (!pipe.nodes || !pipe.nodes.len || (null in pipe.nodes)))
to_chat(usr, "Unconnected [pipe.name] located at [ADMIN_VERBOSEJMP(pipe)]", confidential=TRUE)

//Erroneous Connections, e.g. duplicate pipes
//This uses pipeline_expansion(), so you can detect some atmos machineries causing problems at pipenet code.
for (var/obj/machinery/atmospherics/AM in GLOB.machines)
for (var/obj/machinery/atmospherics/AMT in AM.pipeline_expansion())
if (!(AM in AMT.pipeline_expansion()))
to_chat(usr, "Errorneous connections around [AM.name]. Duplicate or rogue pipes suspected at or around [ADMIN_VERBOSEJMP(AM)]")


/client/proc/powerdebug()
set category = "Misc.Server Debug"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
air_update_turf()

var/datum/pipeline/parent1 = parents[1]
parent1.update = 1
parent1.update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED

else //external -> output

Expand All @@ -103,7 +103,7 @@
air_update_turf()

var/datum/pipeline/parent2 = parents[2]
parent2.update = 1
parent2.update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED

//Radio remote control

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ It's like a regular ol' straight pipe, but you can turn it on and off.

var/switching = FALSE

/obj/machinery/atmospherics/components/binary/valve/Destroy()
//Should only happen on extreme circumstances
if(on)
//Let's give presumably now-severed pipenets a chance to scramble for what's happening at next SSair fire()
if(parents[1])
parents[1].update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED
if(parents[2])
parents[2].update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED
. = ..()

/obj/machinery/atmospherics/components/binary/valve/update_icon_nopipes(animation = FALSE)
normalize_cardinal_directions()
if(animation)
Expand All @@ -44,6 +54,8 @@ It's like a regular ol' straight pipe, but you can turn it on and off.
parent1.reconcile_air()
investigate_log("was opened by [usr ? key_name(usr) : "a remote signal"]", INVESTIGATE_ATMOS)
investigate_log("was opened by [usr ? key_name(usr) : "a remote signal"]", INVESTIGATE_SUPERMATTER) // yogs - Makes supermatter invest useful
update_icon_nopipes()
update_parents()

/obj/machinery/atmospherics/components/binary/valve/interact(mob/user)
add_fingerprint(usr)
Expand Down
26 changes: 22 additions & 4 deletions code/modules/atmospherics/machinery/components/components_base.dm
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@

/obj/machinery/atmospherics/components/build_network()
for(var/i in 1 to device_type)
if(!parents[i])
if(QDELETED(parents[i]))
parents[i] = new /datum/pipeline()
var/datum/pipeline/P = parents[i]
P.build_pipeline(src)
Expand All @@ -82,10 +82,27 @@
var/i = parents.Find(reference)
reference.other_airs -= airs[i]
reference.other_atmosmch -= src
/**
* We explicitly qdel pipeline when this particular pipeline
* is projected to have no member and cause GC problems.
* We have to do this because components don't qdel pipelines
* while pipes must and will happily wreck and rebuild everything again
* every time they are qdeleted.
*/
if(!(reference.other_atmosmch.len || reference.members.len))
qdel(reference)
parents[i] = null

// We should return every air sharing a parent
/obj/machinery/atmospherics/components/returnPipenetAir(datum/pipeline/reference)
return airs[parents.Find(reference)]
for(var/i in 1 to device_type)
if(parents[i] == reference)
if(.)
if(!islist(.))
. = list(.)
. += airs[i]
else
. = airs[i]

/obj/machinery/atmospherics/components/pipeline_expansion(datum/pipeline/reference)
if(reference)
Expand Down Expand Up @@ -139,9 +156,10 @@
var/datum/pipeline/parent = parents[i]
if(!parent)
WARNING("Component is missing a pipenet! Rebuilding...")
//At pre-SSair_rebuild_pipenets times, not having a parent wasn't supposed to happen
SSair.add_to_rebuild_queue(src)
else
parent.update = 1
continue
parent.update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED

/obj/machinery/atmospherics/components/returnPipenets()
. = list()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,16 +111,16 @@
var/datum/gas_mixture/removed1 = air1.remove(transfer_moles1)
air3.merge(removed1)
var/datum/pipeline/parent1 = parents[1]
parent1.update = TRUE
parent1.update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED

if(transfer_moles2)
var/datum/gas_mixture/removed2 = air2.remove(transfer_moles2)
air3.merge(removed2)
var/datum/pipeline/parent2 = parents[2]
parent2.update = TRUE
parent2.update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED

var/datum/pipeline/parent3 = parents[3]
parent3.update = TRUE
parent3.update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED

/obj/machinery/atmospherics/components/trinary/mixer/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
if(src in node.nodes) //Only if it's actually connected. On-pipe version would is one-sided.
node.disconnect(src)
nodes[1] = null
//Sometimes this gets called more than once per atmos tick; i.e. before the incoming build_network call by SSAIR_REBUILD_PIPENETS, so we check this here.
if(parents[1])
nullifyPipenet(parents[1])

Expand Down
126 changes: 68 additions & 58 deletions code/modules/atmospherics/machinery/datum_pipeline.dm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
var/list/obj/machinery/atmospherics/pipe/members
var/list/obj/machinery/atmospherics/components/other_atmosmch

var/update = TRUE
var/update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED

/datum/pipeline/New()
other_airs = list()
Expand All @@ -23,62 +23,53 @@
C.nullifyPipenet(src)
return ..()

/datum/pipeline/process()
if(update)
update = FALSE
reconcile_air()
update = air.react(src)

/datum/pipeline/proc/build_pipeline(obj/machinery/atmospherics/base)
var/volume = 0
if(istype(base, /obj/machinery/atmospherics/pipe))
var/obj/machinery/atmospherics/pipe/E = base
volume = E.volume
members += E
if(E.air_temporary)
air = E.air_temporary
E.air_temporary = null
else
addMachineryMember(base)
if(!air)
air = new
var/list/possible_expansions = list(base)
while(possible_expansions.len)
for(var/obj/machinery/atmospherics/borderline in possible_expansions)
var/list/result = borderline.pipeline_expansion(src)
if(result && result.len)
for(var/obj/machinery/atmospherics/P in result)
if(istype(P, /obj/machinery/atmospherics/pipe))
var/obj/machinery/atmospherics/pipe/item = P
if(!members.Find(item))

if(item.parent)
var/static/pipenetwarnings = 100
if(pipenetwarnings > 0)
log_mapping("build_pipeline(): [item.type] added to a pipenet while still having one. (pipes leading to the same spot stacking in one turf) around [AREACOORD(item)].")
pipenetwarnings--
if(pipenetwarnings == 0)
log_mapping("build_pipeline(): further messages about pipenets will be suppressed")
members += item
possible_expansions += item

volume += item.volume
item.parent = src

if(item.air_temporary)
air.merge(item.air_temporary)
item.air_temporary = null
else
P.setPipenet(src, borderline)
addMachineryMember(P)

possible_expansions -= borderline

air.set_volume(volume)
if(!QDELETED(base))
var/volume = 0
if(istype(base, /obj/machinery/atmospherics/pipe))
var/obj/machinery/atmospherics/pipe/E = base
volume = E.volume
members += E
if(E.air_temporary)
air = E.air_temporary
E.air_temporary = null
else
addMachineryMember(base)
if(!air)
air = new
var/list/possible_expansions = list(base)
while(possible_expansions.len)
for(var/obj/machinery/atmospherics/borderline in possible_expansions)
var/list/result = borderline.pipeline_expansion(src)
if(result && result.len)
for(var/obj/machinery/atmospherics/P in result)
if(istype(P, /obj/machinery/atmospherics/pipe))
var/obj/machinery/atmospherics/pipe/item = P
if(!members.Find(item))
if(item.parent)
var/static/pipenetwarnings = 10
if(pipenetwarnings > 0)
log_mapping("build_pipeline(): [item.type] added to a pipenet while still having one. (pipes leading to the same spot stacking in one turf) around [AREACOORD(item)].")
pipenetwarnings--
if(pipenetwarnings == 0)
log_mapping("build_pipeline(): further messages about pipenets will be suppressed")
members += item
possible_expansions += item
volume += item.volume
item.parent = src
if(item.air_temporary)
air.merge(item.air_temporary)
item.air_temporary = null
else if(!P.returnPipenet(borderline))
P.setPipenet(src, borderline)
addMachineryMember(P)
possible_expansions -= borderline
air.set_volume(volume)

/datum/pipeline/proc/addMachineryMember(obj/machinery/atmospherics/components/C)
other_atmosmch |= C
var/datum/gas_mixture/G = C.returnPipenetAir(src)
//Yes we are having duplicate references to components with multiple nodes sharing a parent
other_atmosmch += C
var/G = C.returnPipenetAir(src)
if(!G)
stack_trace("addMachineryMember: Null gasmix added to pipeline datum from [C] which is of type [C.type]. Nearby: ([C.x], [C.y], [C.z])")
other_airs |= G
Expand Down Expand Up @@ -116,7 +107,7 @@
other_airs.Add(E.other_airs)
E.members.Cut()
E.other_atmosmch.Cut()
update = TRUE
update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED
qdel(E)

/obj/machinery/atmospherics/proc/addMember(obj/machinery/atmospherics/A)
Expand Down Expand Up @@ -198,7 +189,7 @@
(partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity))

air.set_temperature(air.return_temperature() - heat/total_heat_capacity)
update = TRUE
update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED

/datum/pipeline/proc/return_air()
. = other_airs + air
Expand All @@ -215,8 +206,12 @@
var/datum/pipeline/P = PL[i]
if(!P)
continue
GL += P.other_airs
GL += P.air
GL += P.return_air()
if(P != src)
//If one of the reconciling pipenet requires full reconciliation, we have to comply
update = max(update, P.update)
//This prevents redundant reconciliations, highlander style: there can be only one (to reconcile)
P.update = PIPENET_UPDATE_STATUS_DORMANT
for(var/atmosmch in P.other_atmosmch)
if (istype(atmosmch, /obj/machinery/atmospherics/components/binary/valve))
var/obj/machinery/atmospherics/components/binary/valve/V = atmosmch
Expand All @@ -228,13 +223,28 @@
if(C.connected_device)
GL += C.connected_device.air_contents

//This builds total_gas_mixture, which is the *only* instance of complete total gas of a superpipnet.
var/datum/gas_mixture/total_gas_mixture = new(0)
var/total_volume = 0

for(var/i in GL)
var/datum/gas_mixture/G = i
total_gas_mixture.merge(G)
total_volume += G.return_volume()

total_gas_mixture.set_volume(total_volume)

//Decides what this pipeline should do next tick
//Pipenet air reacts here or your connected canisters won't react properly
if(total_gas_mixture.react(pick(PL)))
//Might need another reaction next time; immediately set this pipenet for next reconcile_air()
. = PIPENET_UPDATE_STATUS_REACT_NEEDED
else
. = PIPENET_UPDATE_STATUS_DORMANT
//Needs no update and didn't even react? This reconcile_air() can return early since no change was made.
//This can only be achieved with self-ending stream of reactions, i.e. pipeline fire that has come to an end.
if(update < PIPENET_UPDATE_STATUS_RECONCILE_NEEDED)
return

if(total_volume > 0)
//Update individual gas_mixtures by volume ratio
Expand Down
Loading