mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-10 10:21:11 +00:00
ZAS updates from Bay in a shitty attempt to fix our lagspikes.
This commit is contained in:
@@ -247,6 +247,7 @@
|
|||||||
#include "code\game\gamemodes\cult\ritual.dm"
|
#include "code\game\gamemodes\cult\ritual.dm"
|
||||||
#include "code\game\gamemodes\cult\runes.dm"
|
#include "code\game\gamemodes\cult\runes.dm"
|
||||||
#include "code\game\gamemodes\cult\talisman.dm"
|
#include "code\game\gamemodes\cult\talisman.dm"
|
||||||
|
#include "code\game\gamemodes\endgame\endgame.dm"
|
||||||
#include "code\game\gamemodes\events\biomass.dm"
|
#include "code\game\gamemodes\events\biomass.dm"
|
||||||
#include "code\game\gamemodes\events\black_hole.dm"
|
#include "code\game\gamemodes\events\black_hole.dm"
|
||||||
#include "code\game\gamemodes\events\clang.dm"
|
#include "code\game\gamemodes\events\clang.dm"
|
||||||
@@ -1430,17 +1431,21 @@
|
|||||||
#include "code\WorkInProgress\Ported\policetape.dm"
|
#include "code\WorkInProgress\Ported\policetape.dm"
|
||||||
#include "code\WorkInProgress\SkyMarshal\officer_stuff.dm"
|
#include "code\WorkInProgress\SkyMarshal\officer_stuff.dm"
|
||||||
#include "code\WorkInProgress\SkyMarshal\Ultralight_procs.dm"
|
#include "code\WorkInProgress\SkyMarshal\Ultralight_procs.dm"
|
||||||
|
#include "code\ZAS\_docs.dm"
|
||||||
|
#include "code\ZAS\_gas_mixture.dm"
|
||||||
#include "code\ZAS\Airflow.dm"
|
#include "code\ZAS\Airflow.dm"
|
||||||
|
#include "code\ZAS\Atom.dm"
|
||||||
#include "code\ZAS\Connection.dm"
|
#include "code\ZAS\Connection.dm"
|
||||||
|
#include "code\ZAS\ConnectionGroup.dm"
|
||||||
|
#include "code\ZAS\ConnectionManager.dm"
|
||||||
|
#include "code\ZAS\Controller.dm"
|
||||||
#include "code\ZAS\Debug.dm"
|
#include "code\ZAS\Debug.dm"
|
||||||
#include "code\ZAS\FEA_gas_mixture.dm"
|
#include "code\ZAS\Diagnostic.dm"
|
||||||
#include "code\ZAS\FEA_system.dm"
|
|
||||||
#include "code\ZAS\Fire.dm"
|
#include "code\ZAS\Fire.dm"
|
||||||
#include "code\ZAS\Functions.dm"
|
|
||||||
#include "code\ZAS\NewSettings.dm"
|
#include "code\ZAS\NewSettings.dm"
|
||||||
#include "code\ZAS\Plasma.dm"
|
#include "code\ZAS\Plasma.dm"
|
||||||
#include "code\ZAS\ZAS_Turfs.dm"
|
#include "code\ZAS\Turf.dm"
|
||||||
#include "code\ZAS\ZAS_Zones.dm"
|
#include "code\ZAS\Zone.dm"
|
||||||
#include "interface\interface.dm"
|
#include "interface\interface.dm"
|
||||||
#include "interface\skin.dmf"
|
#include "interface\skin.dmf"
|
||||||
#include "maps\tgstation.2.1.0.0.1.dmm"
|
#include "maps\tgstation.2.1.0.0.1.dmm"
|
||||||
|
|||||||
@@ -149,10 +149,12 @@ datum/pipeline
|
|||||||
air.merge(air_sample)
|
air.merge(air_sample)
|
||||||
//turf_air already modified by equalize_gases()
|
//turf_air already modified by equalize_gases()
|
||||||
|
|
||||||
|
/*
|
||||||
if(istype(target) && !target.processing && !iscatwalk(target))
|
if(istype(target) && !target.processing && !iscatwalk(target))
|
||||||
if(target.air)
|
if(target.air)
|
||||||
if(target.air.check_tile_graphic())
|
if(target.air.check_tile_graphic())
|
||||||
target.update_visuals(target.air)
|
target.update_visuals(target.air)
|
||||||
|
*/
|
||||||
if(network)
|
if(network)
|
||||||
network.update = 1
|
network.update = 1
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ obj/item/check_airflow_movable(n)
|
|||||||
if(4,5)
|
if(4,5)
|
||||||
if(n < zas_settings.Get(/datum/ZAS_Setting/airflow_medium_pressure)) return 0
|
if(n < zas_settings.Get(/datum/ZAS_Setting/airflow_medium_pressure)) return 0
|
||||||
|
|
||||||
|
/*
|
||||||
//The main airflow code. Called by zone updates.
|
//The main airflow code. Called by zone updates.
|
||||||
//Zones A and B are air zones. n represents the amount of air moved.
|
//Zones A and B are air zones. n represents the amount of air moved.
|
||||||
|
|
||||||
@@ -240,7 +241,7 @@ proc/AirflowSpace(zone/A)
|
|||||||
spawn
|
spawn
|
||||||
if(M) M.GotoAirflowDest(n/10)
|
if(M) M.GotoAirflowDest(n/10)
|
||||||
//Sometimes shit breaks, and M isn't there after the spawn.
|
//Sometimes shit breaks, and M isn't there after the spawn.
|
||||||
|
*/
|
||||||
|
|
||||||
/atom/movable/var/tmp/turf/airflow_dest
|
/atom/movable/var/tmp/turf/airflow_dest
|
||||||
/atom/movable/var/tmp/airflow_speed = 0
|
/atom/movable/var/tmp/airflow_speed = 0
|
||||||
|
|||||||
66
code/ZAS/Atom.dm
Normal file
66
code/ZAS/Atom.dm
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
|
||||||
|
|
||||||
|
/atom/var/pressure_resistance = ONE_ATMOSPHERE
|
||||||
|
|
||||||
|
atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0)
|
||||||
|
//Purpose: Determines if the object (or airflow) can pass this atom.
|
||||||
|
//Called by: Movement, airflow.
|
||||||
|
//Inputs: The moving atom (optional), target turf, "height" and air group
|
||||||
|
//Outputs: Boolean if can pass.
|
||||||
|
|
||||||
|
return (!density || !height || air_group)
|
||||||
|
|
||||||
|
/turf/CanPass(atom/movable/mover, turf/target, height=1.5,air_group=0)
|
||||||
|
if(!target) return 0
|
||||||
|
|
||||||
|
if(istype(mover)) // turf/Enter(...) will perform more advanced checks
|
||||||
|
return !density
|
||||||
|
|
||||||
|
else // Now, doing more detailed checks for air movement and air group formation
|
||||||
|
if(target.blocks_air||blocks_air)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
for(var/obj/obstacle in src)
|
||||||
|
if(!obstacle.CanPass(mover, target, height, air_group))
|
||||||
|
return 0
|
||||||
|
if(target != src)
|
||||||
|
for(var/obj/obstacle in target)
|
||||||
|
if(!obstacle.CanPass(mover, src, height, air_group))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
//Basically another way of calling CanPass(null, other, 0, 0) and CanPass(null, other, 1.5, 1).
|
||||||
|
//Returns:
|
||||||
|
// 0 - Not blocked
|
||||||
|
// AIR_BLOCKED - Blocked
|
||||||
|
// ZONE_BLOCKED - Not blocked, but zone boundaries will not cross.
|
||||||
|
// BLOCKED - Blocked, zone boundaries will not cross even if opened.
|
||||||
|
atom/proc/c_airblock(turf/other)
|
||||||
|
#ifdef ZASDBG
|
||||||
|
ASSERT(isturf(other))
|
||||||
|
#endif
|
||||||
|
return !CanPass(null, other, 0, 0) + 2*!CanPass(null, other, 1.5, 1)
|
||||||
|
|
||||||
|
|
||||||
|
turf/c_airblock(turf/other)
|
||||||
|
#ifdef ZASDBG
|
||||||
|
ASSERT(isturf(other))
|
||||||
|
#endif
|
||||||
|
if(blocks_air)
|
||||||
|
return BLOCKED
|
||||||
|
|
||||||
|
//Z-level handling code. Always block if there isn't an open space.
|
||||||
|
#ifdef ZLEVELS
|
||||||
|
if(other.z != src.z)
|
||||||
|
if(other.z < src.z)
|
||||||
|
if(!istype(src, /turf/simulated/floor/open)) return BLOCKED
|
||||||
|
else
|
||||||
|
if(!istype(other, /turf/simulated/floor/open)) return BLOCKED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var/result = 0
|
||||||
|
for(var/atom/movable/M in contents)
|
||||||
|
result |= M.c_airblock(other)
|
||||||
|
if(result == BLOCKED) return BLOCKED
|
||||||
|
return result
|
||||||
@@ -1,403 +1,165 @@
|
|||||||
|
#define CONNECTION_DIRECT 2
|
||||||
|
#define CONNECTION_SPACE 4
|
||||||
|
#define CONNECTION_INVALID 8
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This object is contained within zone/var/connections. It's generated whenever two turfs from different zones are linked.
|
|
||||||
Indirect connections will not merge the two zones after they reach equilibrium.
|
Overview:
|
||||||
|
Connections are made between turfs by air_master.connect(). They represent a single point where two zones converge.
|
||||||
|
|
||||||
|
Class Vars:
|
||||||
|
A - Always a simulated turf.
|
||||||
|
B - A simulated or unsimulated turf.
|
||||||
|
|
||||||
|
zoneA - The archived zone of A. Used to check that the zone hasn't changed.
|
||||||
|
zoneB - The archived zone of B. May be null in case of unsimulated connections.
|
||||||
|
|
||||||
|
edge - Stores the edge this connection is in. Can reference an edge that is no longer processed
|
||||||
|
after this connection is removed, so make sure to check edge.coefficient > 0 before re-adding it.
|
||||||
|
|
||||||
|
Class Procs:
|
||||||
|
|
||||||
|
mark_direct()
|
||||||
|
Marks this connection as direct. Does not update the edge.
|
||||||
|
Called when the connection is made and there are no doors between A and B.
|
||||||
|
Also called by update() as a correction.
|
||||||
|
|
||||||
|
mark_indirect()
|
||||||
|
Unmarks this connection as direct. Does not update the edge.
|
||||||
|
Called by update() as a correction.
|
||||||
|
|
||||||
|
mark_space()
|
||||||
|
Marks this connection as unsimulated. Updating the connection will check the validity of this.
|
||||||
|
Called when the connection is made.
|
||||||
|
This will not be called as a correction, any connections failing a check against this mark are erased and rebuilt.
|
||||||
|
|
||||||
|
direct()
|
||||||
|
Returns 1 if no doors are in between A and B.
|
||||||
|
|
||||||
|
valid()
|
||||||
|
Returns 1 if the connection has not been erased.
|
||||||
|
|
||||||
|
erase()
|
||||||
|
Called by update() and connection_manager/erase_all().
|
||||||
|
Marks the connection as erased and removes it from its edge.
|
||||||
|
|
||||||
|
update()
|
||||||
|
Called by connection_manager/update_all().
|
||||||
|
Makes numerous checks to decide whether the connection is still valid. Erases it automatically if not.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#define CONNECTION_DIRECT 2
|
|
||||||
#define CONNECTION_INDIRECT 1
|
|
||||||
#define CONNECTION_CLOSED 0
|
|
||||||
|
|
||||||
/connection
|
/connection/var/turf/simulated/A
|
||||||
var/turf/simulated/A
|
/connection/var/turf/simulated/B
|
||||||
var/turf/simulated/B
|
/connection/var/zone/zoneA
|
||||||
|
/connection/var/zone/zoneB
|
||||||
|
|
||||||
var/zone/zone_A
|
/connection/var/connection_edge/edge
|
||||||
var/zone/zone_B
|
|
||||||
|
|
||||||
var/ref_A
|
|
||||||
var/ref_B
|
|
||||||
|
|
||||||
var/indirect = CONNECTION_DIRECT //If the connection is purely indirect, the zones should not join.
|
|
||||||
|
|
||||||
var/last_updated //The tick at which this was last updated.
|
|
||||||
|
|
||||||
var/no_zone_count = 0
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/connection/New(turf/T,turf/O)
|
|
||||||
A = T
|
|
||||||
B = O
|
|
||||||
if(A.zone && B.zone)
|
|
||||||
if(!A.zone.connections) A.zone.connections = list()
|
|
||||||
A.zone.connections += src
|
|
||||||
zone_A = A.zone
|
|
||||||
ref_A = "\ref[A]"
|
|
||||||
|
|
||||||
if(!B.zone.connections) B.zone.connections = list()
|
|
||||||
B.zone.connections += src
|
|
||||||
zone_B = B.zone
|
|
||||||
ref_B = "\ref[B]"
|
|
||||||
|
|
||||||
if(ref_A in air_master.turfs_with_connections)
|
|
||||||
var/list/connections = air_master.turfs_with_connections[ref_A]
|
|
||||||
connections.Add(src)
|
|
||||||
else
|
|
||||||
air_master.turfs_with_connections[ref_A] = list(src)
|
|
||||||
|
|
||||||
if(ref_B in air_master.turfs_with_connections)
|
|
||||||
var/list/connections = air_master.turfs_with_connections[ref_B]
|
|
||||||
connections.Add(src)
|
|
||||||
else
|
|
||||||
air_master.turfs_with_connections[ref_B] = list(src)
|
|
||||||
|
|
||||||
if(A.CanPass(null, B, 0, 0))
|
|
||||||
|
|
||||||
ConnectZones(A.zone, B.zone, 1)
|
|
||||||
|
|
||||||
if(A.HasDoor(B) || B.HasDoor(A))
|
|
||||||
indirect = CONNECTION_INDIRECT
|
|
||||||
|
|
||||||
else
|
|
||||||
ConnectZones(A.zone, B.zone)
|
|
||||||
indirect = CONNECTION_CLOSED
|
|
||||||
|
|
||||||
|
/connection/var/state = 0
|
||||||
|
|
||||||
|
/connection/New(turf/simulated/A, turf/simulated/B)
|
||||||
|
#ifdef ZASDBG
|
||||||
|
ASSERT(air_master.has_valid_zone(A))
|
||||||
|
//ASSERT(air_master.has_valid_zone(B))
|
||||||
|
#endif
|
||||||
|
src.A = A
|
||||||
|
src.B = B
|
||||||
|
zoneA = A.zone
|
||||||
|
if(!istype(B))
|
||||||
|
mark_space()
|
||||||
|
edge = air_master.get_edge(A.zone,B)
|
||||||
|
edge.add_connection(src)
|
||||||
else
|
else
|
||||||
world.log << "Attempted to create connection object for non-zone tiles: [T] ([T.x],[T.y],[T.z]) -> [O] ([O.x],[O.y],[O.z])"
|
zoneB = B.zone
|
||||||
del(src)
|
edge = air_master.get_edge(A.zone,B.zone)
|
||||||
|
edge.add_connection(src)
|
||||||
|
|
||||||
|
/connection/proc/mark_direct()
|
||||||
|
state |= CONNECTION_DIRECT
|
||||||
|
//world << "Marked direct."
|
||||||
|
|
||||||
/connection/Del()
|
/connection/proc/mark_indirect()
|
||||||
//remove connections from master lists.
|
state &= ~CONNECTION_DIRECT
|
||||||
if(ref_B in air_master.turfs_with_connections)
|
//world << "Marked indirect."
|
||||||
var/list/connections = air_master.turfs_with_connections[ref_B]
|
|
||||||
connections.Remove(src)
|
|
||||||
|
|
||||||
if(ref_A in air_master.turfs_with_connections)
|
/connection/proc/mark_space()
|
||||||
var/list/connections = air_master.turfs_with_connections[ref_A]
|
state |= CONNECTION_SPACE
|
||||||
connections.Remove(src)
|
|
||||||
|
|
||||||
//Remove connection from zones.
|
/connection/proc/direct()
|
||||||
if(A)
|
return (state & CONNECTION_DIRECT)
|
||||||
if(A.zone && A.zone.connections)
|
|
||||||
A.zone.connections.Remove(src)
|
|
||||||
if(!A.zone.connections.len)
|
|
||||||
A.zone.connections = null
|
|
||||||
|
|
||||||
if(istype(zone_A) && (!A || A.zone != zone_A))
|
/connection/proc/valid()
|
||||||
if(zone_A.connections)
|
return !(state & CONNECTION_INVALID)
|
||||||
zone_A.connections.Remove(src)
|
|
||||||
if(!zone_A.connections.len)
|
|
||||||
zone_A.connections = null
|
|
||||||
|
|
||||||
if(B)
|
/connection/proc/erase()
|
||||||
if(B.zone && B.zone.connections)
|
edge.remove_connection(src)
|
||||||
B.zone.connections.Remove(src)
|
state |= CONNECTION_INVALID
|
||||||
if(!B.zone.connections.len)
|
//world << "Connection Erased: [state]"
|
||||||
B.zone.connections = null
|
|
||||||
|
|
||||||
if(istype(zone_B) && (!B || B.zone != zone_B))
|
/connection/proc/update()
|
||||||
if(zone_B.connections)
|
//world << "Updated, \..."
|
||||||
zone_B.connections.Remove(src)
|
if(!istype(A,/turf/simulated))
|
||||||
if(!zone_B.connections.len)
|
//world << "Invalid A."
|
||||||
zone_B.connections = null
|
erase()
|
||||||
|
|
||||||
//Disconnect zones while handling unusual conditions.
|
|
||||||
// e.g. loss of a zone on a turf
|
|
||||||
if(A && A.zone && B && B.zone)
|
|
||||||
DisconnectZones(A.zone, B.zone)
|
|
||||||
|
|
||||||
//Finally, preform actual deletion.
|
|
||||||
. = ..()
|
|
||||||
|
|
||||||
|
|
||||||
/connection/proc/ConnectZones(var/zone/zone_1, var/zone/zone_2, open = 0)
|
|
||||||
|
|
||||||
//Sanity checking
|
|
||||||
if(!istype(zone_1) || !istype(zone_2))
|
|
||||||
return
|
return
|
||||||
|
|
||||||
//Handle zones connecting indirectly/directly.
|
var/block_status = air_master.air_blocked(A,B)
|
||||||
if(open)
|
if(block_status & AIR_BLOCKED)
|
||||||
|
//world << "Blocked connection."
|
||||||
//Create the lists if necessary.
|
erase()
|
||||||
if(!zone_1.connected_zones)
|
|
||||||
zone_1.connected_zones = list()
|
|
||||||
|
|
||||||
if(!zone_2.connected_zones)
|
|
||||||
zone_2.connected_zones = list()
|
|
||||||
|
|
||||||
//Increase the number of connections between zones.
|
|
||||||
if(zone_2 in zone_1.connected_zones)
|
|
||||||
zone_1.connected_zones[zone_2]++
|
|
||||||
else
|
|
||||||
zone_1.connected_zones += zone_2
|
|
||||||
zone_1.connected_zones[zone_2] = 1
|
|
||||||
|
|
||||||
if(zone_1 in zone_2.connected_zones)
|
|
||||||
zone_2.connected_zones[zone_1]++
|
|
||||||
else
|
|
||||||
zone_2.connected_zones += zone_1
|
|
||||||
zone_2.connected_zones[zone_1] = 1
|
|
||||||
|
|
||||||
//Handle closed connections.
|
|
||||||
else
|
|
||||||
|
|
||||||
//Create the lists
|
|
||||||
if(!zone_1.closed_connection_zones)
|
|
||||||
zone_1.closed_connection_zones = list()
|
|
||||||
|
|
||||||
if(!zone_2.closed_connection_zones)
|
|
||||||
zone_2.closed_connection_zones = list()
|
|
||||||
|
|
||||||
//Increment the connections.
|
|
||||||
if(zone_2 in zone_1.closed_connection_zones)
|
|
||||||
zone_1.closed_connection_zones[zone_2]++
|
|
||||||
else
|
|
||||||
zone_1.closed_connection_zones += zone_2
|
|
||||||
zone_1.closed_connection_zones[zone_2] = 1
|
|
||||||
|
|
||||||
if(zone_1 in zone_2.closed_connection_zones)
|
|
||||||
zone_2.closed_connection_zones[zone_1]++
|
|
||||||
else
|
|
||||||
zone_2.closed_connection_zones += zone_1
|
|
||||||
zone_2.closed_connection_zones[zone_1] = 1
|
|
||||||
|
|
||||||
|
|
||||||
/connection/proc/DisconnectZones(var/zone/zone_1, var/zone/zone_2)
|
|
||||||
//Sanity checking
|
|
||||||
if(!istype(zone_1) || !istype(zone_2))
|
|
||||||
return
|
return
|
||||||
|
else if(block_status & ZONE_BLOCKED)
|
||||||
if(indirect != CONNECTION_CLOSED)
|
if(direct())
|
||||||
//Handle disconnection of indirectly or directly connected zones.
|
mark_indirect()
|
||||||
if( (zone_1 in zone_2.connected_zones) || (zone_2 in zone_1.connected_zones) )
|
|
||||||
|
|
||||||
//If there are more than one connection, decrement the number of connections
|
|
||||||
//Otherwise, remove all connections between the zones.
|
|
||||||
if(zone_2 in zone_1.connected_zones)
|
|
||||||
if(zone_1.connected_zones[zone_2] > 1)
|
|
||||||
zone_1.connected_zones[zone_2]--
|
|
||||||
else
|
|
||||||
zone_1.connected_zones -= zone_2
|
|
||||||
//remove the list if it is empty
|
|
||||||
if(!zone_1.connected_zones.len)
|
|
||||||
zone_1.connected_zones = null
|
|
||||||
|
|
||||||
//Then do the same for the other zone.
|
|
||||||
if(zone_1 in zone_2.connected_zones)
|
|
||||||
if(zone_2.connected_zones[zone_1] > 1)
|
|
||||||
zone_2.connected_zones[zone_1]--
|
|
||||||
else
|
|
||||||
zone_2.connected_zones -= zone_1
|
|
||||||
if(!zone_2.connected_zones.len)
|
|
||||||
zone_2.connected_zones = null
|
|
||||||
|
|
||||||
else
|
|
||||||
//Handle disconnection of closed zones.
|
|
||||||
if( (zone_1 in zone_2.closed_connection_zones) || (zone_2 in zone_1.closed_connection_zones) )
|
|
||||||
|
|
||||||
//If there are more than one connection, decrement the number of connections
|
|
||||||
//Otherwise, remove all connections between the zones.
|
|
||||||
if(zone_2 in zone_1.closed_connection_zones)
|
|
||||||
if(zone_1.closed_connection_zones[zone_2] > 1)
|
|
||||||
zone_1.closed_connection_zones[zone_2]--
|
|
||||||
else
|
|
||||||
zone_1.closed_connection_zones -= zone_2
|
|
||||||
//remove the list if it is empty
|
|
||||||
if(!zone_1.closed_connection_zones.len)
|
|
||||||
zone_1.closed_connection_zones = null
|
|
||||||
|
|
||||||
//Then do the same for the other zone.
|
|
||||||
if(zone_1 in zone_2.closed_connection_zones)
|
|
||||||
if(zone_2.closed_connection_zones[zone_1] > 1)
|
|
||||||
zone_2.closed_connection_zones[zone_1]--
|
|
||||||
else
|
|
||||||
zone_2.closed_connection_zones -= zone_1
|
|
||||||
if(!zone_2.closed_connection_zones.len)
|
|
||||||
zone_2.closed_connection_zones = null
|
|
||||||
|
|
||||||
|
|
||||||
/connection/proc/Cleanup()
|
|
||||||
|
|
||||||
//Check sanity: existance of turfs
|
|
||||||
if(!A || !B)
|
|
||||||
del src
|
|
||||||
|
|
||||||
//Check sanity: zones are different
|
|
||||||
if(A.zone == B.zone)
|
|
||||||
del src
|
|
||||||
|
|
||||||
//Check sanity: same turfs as before.
|
|
||||||
if(ref_A != "\ref[A]" || ref_B != "\ref[B]")
|
|
||||||
del src
|
|
||||||
|
|
||||||
//Handle zones changing on a turf.
|
|
||||||
if((A.zone && A.zone != zone_A) || (B.zone && B.zone != zone_B))
|
|
||||||
Sanitize()
|
|
||||||
|
|
||||||
//Manage sudden loss of a turfs zone. (e.g. a wall being built)
|
|
||||||
if(!A.zone || !B.zone)
|
|
||||||
no_zone_count++
|
|
||||||
if(no_zone_count >= 5)
|
|
||||||
//world.log << "Connection removed: [A] or [B] missing a zone."
|
|
||||||
del src
|
|
||||||
return 0
|
|
||||||
|
|
||||||
return 1
|
|
||||||
|
|
||||||
|
|
||||||
/connection/proc/CheckPassSanity()
|
|
||||||
//Sanity check, first.
|
|
||||||
Cleanup()
|
|
||||||
|
|
||||||
if(A.zone && B.zone)
|
|
||||||
|
|
||||||
//If no walls are blocking us...
|
|
||||||
if(A.ZAirPass(B))
|
|
||||||
//...we check to see if there is a door in the way...
|
|
||||||
var/door_pass = A.CanPass(null,B,1.5,1)
|
|
||||||
//...and if it is opened.
|
|
||||||
if(door_pass || A.CanPass(null,B,0,0))
|
|
||||||
|
|
||||||
//Make and remove connections to let air pass.
|
|
||||||
if(indirect == CONNECTION_CLOSED)
|
|
||||||
DisconnectZones(A.zone, B.zone)
|
|
||||||
ConnectZones(A.zone, B.zone, 1)
|
|
||||||
|
|
||||||
if(door_pass)
|
|
||||||
indirect = CONNECTION_DIRECT
|
|
||||||
else if(!door_pass)
|
|
||||||
indirect = CONNECTION_INDIRECT
|
|
||||||
|
|
||||||
//The door is instead closed.
|
|
||||||
else if(indirect > CONNECTION_CLOSED)
|
|
||||||
DisconnectZones(A.zone, B.zone)
|
|
||||||
indirect = CONNECTION_CLOSED
|
|
||||||
ConnectZones(A.zone, B.zone)
|
|
||||||
|
|
||||||
//If I can no longer pass air, better delete
|
|
||||||
else
|
else
|
||||||
del src
|
mark_direct()
|
||||||
|
|
||||||
/connection/proc/Sanitize()
|
var/b_is_space = !istype(B,/turf/simulated)
|
||||||
//If the zones change on connected turfs, update it.
|
|
||||||
|
|
||||||
//Both zones changed (wat)
|
if(state & CONNECTION_SPACE)
|
||||||
if(A.zone && A.zone != zone_A && B.zone && B.zone != zone_B)
|
if(!b_is_space)
|
||||||
|
//world << "Invalid B."
|
||||||
//If the zones have gotten swapped
|
erase()
|
||||||
// (do not ask me how, I am just being anal retentive about sanity)
|
|
||||||
if(A.zone == zone_B && B.zone == zone_A)
|
|
||||||
var/turf/temp = B
|
|
||||||
B = A
|
|
||||||
A = temp
|
|
||||||
zone_B = B.zone
|
|
||||||
zone_A = A.zone
|
|
||||||
var/temp_ref = ref_A
|
|
||||||
ref_A = ref_B
|
|
||||||
ref_B = temp_ref
|
|
||||||
return
|
return
|
||||||
|
if(A.zone != zoneA)
|
||||||
//Handle removal of connections from archived zones.
|
//world << "Zone changed, \..."
|
||||||
if(zone_A && zone_A.connections)
|
|
||||||
zone_A.connections.Remove(src)
|
|
||||||
if(!zone_A.connections.len)
|
|
||||||
zone_A.connections = null
|
|
||||||
|
|
||||||
if(zone_B && zone_B.connections)
|
|
||||||
zone_B.connections.Remove(src)
|
|
||||||
if(!zone_B.connections.len)
|
|
||||||
zone_B.connections = null
|
|
||||||
|
|
||||||
if(A.zone)
|
|
||||||
if(!A.zone.connections)
|
|
||||||
A.zone.connections = list()
|
|
||||||
A.zone.connections |= src
|
|
||||||
|
|
||||||
if(B.zone)
|
|
||||||
if(!B.zone.connections)
|
|
||||||
B.zone.connections = list()
|
|
||||||
B.zone.connections |= src
|
|
||||||
|
|
||||||
//If either zone is null, we disconnect the archived ones after cleaning up the connections.
|
|
||||||
if(!A.zone || !B.zone)
|
|
||||||
if(zone_A && zone_B)
|
|
||||||
DisconnectZones(zone_B, zone_A)
|
|
||||||
|
|
||||||
if(!A.zone)
|
if(!A.zone)
|
||||||
zone_A = A.zone
|
erase()
|
||||||
|
//world << "erased."
|
||||||
|
return
|
||||||
|
else
|
||||||
|
edge.remove_connection(src)
|
||||||
|
edge = air_master.get_edge(A.zone, B)
|
||||||
|
edge.add_connection(src)
|
||||||
|
zoneA = A.zone
|
||||||
|
|
||||||
if(!B.zone)
|
//world << "valid."
|
||||||
zone_B = B.zone
|
return
|
||||||
|
|
||||||
|
else if(b_is_space)
|
||||||
|
//world << "Invalid B."
|
||||||
|
erase()
|
||||||
|
return
|
||||||
|
|
||||||
|
if(A.zone == B.zone)
|
||||||
|
//world << "A == B"
|
||||||
|
erase()
|
||||||
|
return
|
||||||
|
|
||||||
|
if(A.zone != zoneA || (zoneB && (B.zone != zoneB)))
|
||||||
|
|
||||||
|
//world << "Zones changed, \..."
|
||||||
|
if(A.zone && B.zone)
|
||||||
|
edge.remove_connection(src)
|
||||||
|
edge = air_master.get_edge(A.zone, B.zone)
|
||||||
|
edge.add_connection(src)
|
||||||
|
zoneA = A.zone
|
||||||
|
zoneB = B.zone
|
||||||
|
else
|
||||||
|
//world << "erased."
|
||||||
|
erase()
|
||||||
return
|
return
|
||||||
|
|
||||||
//Handle diconnection and reconnection of zones.
|
|
||||||
if(zone_A && zone_B)
|
|
||||||
DisconnectZones(zone_A, zone_B)
|
|
||||||
ConnectZones(A.zone, B.zone, indirect)
|
|
||||||
|
|
||||||
//resetting values of archived values.
|
//world << "valid."
|
||||||
zone_B = B.zone
|
|
||||||
zone_A = A.zone
|
|
||||||
|
|
||||||
//The "A" zone changed.
|
|
||||||
else if(A.zone && A.zone != zone_A)
|
|
||||||
|
|
||||||
//Handle connection cleanup
|
|
||||||
if(zone_A)
|
|
||||||
if(zone_A.connections)
|
|
||||||
zone_A.connections.Remove(src)
|
|
||||||
if(!zone_A.connections.len)
|
|
||||||
zone_A.connections = null
|
|
||||||
|
|
||||||
if(A.zone)
|
|
||||||
if(!A.zone.connections)
|
|
||||||
A.zone.connections = list()
|
|
||||||
A.zone.connections |= src
|
|
||||||
|
|
||||||
//If the "A" zone is null, we disconnect the archived ones after cleaning up the connections.
|
|
||||||
if(!A.zone)
|
|
||||||
if(zone_A && zone_B)
|
|
||||||
DisconnectZones(zone_A, zone_B)
|
|
||||||
zone_A = A.zone
|
|
||||||
return
|
|
||||||
|
|
||||||
//Handle diconnection and reconnection of zones.
|
|
||||||
if(zone_A && zone_B)
|
|
||||||
DisconnectZones(zone_A, zone_B)
|
|
||||||
ConnectZones(A.zone, B.zone, indirect)
|
|
||||||
zone_A = A.zone
|
|
||||||
|
|
||||||
//The "B" zone changed.
|
|
||||||
else if(B.zone && B.zone != zone_B)
|
|
||||||
|
|
||||||
//Handle connection cleanup
|
|
||||||
if(zone_B)
|
|
||||||
if(zone_B.connections)
|
|
||||||
zone_B.connections.Remove(src)
|
|
||||||
if(!zone_B.connections.len)
|
|
||||||
zone_B.connections = null
|
|
||||||
|
|
||||||
if(B.zone)
|
|
||||||
if(!B.zone.connections)
|
|
||||||
B.zone.connections = list()
|
|
||||||
B.zone.connections |= src
|
|
||||||
|
|
||||||
//If the "B" zone is null, we disconnect the archived ones after cleaning up the connections.
|
|
||||||
if(!B.zone)
|
|
||||||
if(zone_A && zone_B)
|
|
||||||
DisconnectZones(zone_A, zone_B)
|
|
||||||
zone_B = B.zone
|
|
||||||
return
|
|
||||||
|
|
||||||
//Handle diconnection and reconnection of zones.
|
|
||||||
if(zone_A && zone_B)
|
|
||||||
DisconnectZones(zone_A, zone_B)
|
|
||||||
ConnectZones(A.zone, B.zone, indirect)
|
|
||||||
zone_B = B.zone
|
|
||||||
|
|
||||||
|
|
||||||
#undef CONNECTION_DIRECT
|
|
||||||
#undef CONNECTION_INDIRECT
|
|
||||||
#undef CONNECTION_CLOSED
|
|
||||||
434
code/ZAS/ConnectionGroup.dm
Normal file
434
code/ZAS/ConnectionGroup.dm
Normal file
@@ -0,0 +1,434 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Overview:
|
||||||
|
These are what handle gas transfers between zones and into space.
|
||||||
|
They are found in a zone's edges list and in air_master.edges.
|
||||||
|
Each edge updates every air tick due to their role in gas transfer.
|
||||||
|
They come in two flavors, /connection_edge/zone and /connection_edge/unsimulated.
|
||||||
|
As the type names might suggest, they handle inter-zone and spacelike connections respectively.
|
||||||
|
|
||||||
|
Class Vars:
|
||||||
|
|
||||||
|
A - This always holds a zone. In unsimulated edges, it holds the only zone.
|
||||||
|
|
||||||
|
connecting_turfs - This holds a list of connected turfs, mainly for the sake of airflow.
|
||||||
|
|
||||||
|
coefficent - This is a marker for how many connections are on this edge. Used to determine the ratio of flow.
|
||||||
|
|
||||||
|
connection_edge/zone
|
||||||
|
|
||||||
|
B - This holds the second zone with which the first zone equalizes.
|
||||||
|
|
||||||
|
direct - This counts the number of direct (i.e. with no doors) connections on this edge.
|
||||||
|
Any value of this is sufficient to make the zones mergeable.
|
||||||
|
|
||||||
|
connection_edge/unsimulated
|
||||||
|
|
||||||
|
B - This holds an unsimulated turf which has the gas values this edge is mimicing.
|
||||||
|
|
||||||
|
air - Retrieved from B on creation and used as an argument for the legacy ShareSpace() proc.
|
||||||
|
|
||||||
|
Class Procs:
|
||||||
|
|
||||||
|
add_connection(connection/c)
|
||||||
|
Adds a connection to this edge. Usually increments the coefficient and adds a turf to connecting_turfs.
|
||||||
|
|
||||||
|
remove_connection(connection/c)
|
||||||
|
Removes a connection from this edge. This works even if c is not in the edge, so be careful.
|
||||||
|
If the coefficient reaches zero as a result, the edge is erased.
|
||||||
|
|
||||||
|
contains_zone(zone/Z)
|
||||||
|
Returns true if either A or B is equal to Z. Unsimulated connections return true only on A.
|
||||||
|
|
||||||
|
erase()
|
||||||
|
Removes this connection from processing and zone edge lists.
|
||||||
|
|
||||||
|
tick()
|
||||||
|
Called every air tick on edges in the processing list. Equalizes gas.
|
||||||
|
|
||||||
|
flow(list/movable, differential, repelled)
|
||||||
|
Airflow proc causing all objects in movable to be checked against a pressure differential.
|
||||||
|
If repelled is true, the objects move away from any turf in connecting_turfs, otherwise they approach.
|
||||||
|
A check against vsc.lightest_airflow_pressure should generally be performed before calling this.
|
||||||
|
|
||||||
|
get_connected_zone(zone/from)
|
||||||
|
Helper proc that allows getting the other zone of an edge given one of them.
|
||||||
|
Only on /connection_edge/zone, otherwise use A.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/connection_edge/var/zone/A
|
||||||
|
|
||||||
|
/connection_edge/var/list/connecting_turfs = list()
|
||||||
|
|
||||||
|
/connection_edge/var/coefficient = 0
|
||||||
|
|
||||||
|
/connection_edge/New()
|
||||||
|
CRASH("Cannot make connection edge without specifications.")
|
||||||
|
|
||||||
|
/connection_edge/proc/add_connection(connection/c)
|
||||||
|
coefficient++
|
||||||
|
//world << "Connection added: [type] Coefficient: [coefficient]"
|
||||||
|
|
||||||
|
/connection_edge/proc/remove_connection(connection/c)
|
||||||
|
//world << "Connection removed: [type] Coefficient: [coefficient-1]"
|
||||||
|
coefficient--
|
||||||
|
if(coefficient <= 0)
|
||||||
|
erase()
|
||||||
|
|
||||||
|
/connection_edge/proc/contains_zone(zone/Z)
|
||||||
|
|
||||||
|
/connection_edge/proc/erase()
|
||||||
|
air_master.remove_edge(src)
|
||||||
|
//world << "[type] Erased."
|
||||||
|
|
||||||
|
/connection_edge/proc/tick()
|
||||||
|
|
||||||
|
/connection_edge/proc/flow(list/movable, differential, repelled)
|
||||||
|
for(var/atom/movable/M in movable)
|
||||||
|
//If they're already being tossed, don't do it again.
|
||||||
|
if(M.last_airflow > world.time - zas_settings.Get(/datum/ZAS_Setting/airflow_delay))
|
||||||
|
continue
|
||||||
|
if(M.airflow_speed)
|
||||||
|
continue
|
||||||
|
|
||||||
|
//Check for knocking people over
|
||||||
|
if(ismob(M) && differential > zas_settings.Get(/datum/ZAS_Setting/airflow_stun_pressure))
|
||||||
|
if(M:status_flags & GODMODE) continue
|
||||||
|
M:airflow_stun()
|
||||||
|
|
||||||
|
if(M.check_airflow_movable(differential))
|
||||||
|
//Check for things that are in range of the midpoint turfs.
|
||||||
|
var/list/close_turfs = list()
|
||||||
|
for(var/turf/U in connecting_turfs)
|
||||||
|
if(get_dist(M,U) < world.view)
|
||||||
|
close_turfs += U
|
||||||
|
if(!close_turfs.len)
|
||||||
|
continue
|
||||||
|
|
||||||
|
M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards.
|
||||||
|
|
||||||
|
if(M)
|
||||||
|
// THERE WAS A SPAWN HERE. STOP DOING THIS SHIT. - N3X
|
||||||
|
if(repelled)
|
||||||
|
M.RepelAirflowDest(differential/5)
|
||||||
|
else
|
||||||
|
M.GotoAirflowDest(differential/10)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/connection_edge/zone/var/zone/B
|
||||||
|
/connection_edge/zone/var/direct = 0
|
||||||
|
|
||||||
|
/connection_edge/zone/New(zone/A, zone/B)
|
||||||
|
|
||||||
|
src.A = A
|
||||||
|
src.B = B
|
||||||
|
A.edges.Add(src)
|
||||||
|
B.edges.Add(src)
|
||||||
|
//id = edge_id(A,B)
|
||||||
|
//world << "New edge between [A] and [B]"
|
||||||
|
|
||||||
|
/connection_edge/zone/add_connection(connection/c)
|
||||||
|
. = ..()
|
||||||
|
connecting_turfs.Add(c.A)
|
||||||
|
if(c.direct()) direct++
|
||||||
|
|
||||||
|
/connection_edge/zone/remove_connection(connection/c)
|
||||||
|
connecting_turfs.Remove(c.A)
|
||||||
|
if(c.direct()) direct--
|
||||||
|
. = ..()
|
||||||
|
|
||||||
|
/connection_edge/zone/contains_zone(zone/Z)
|
||||||
|
return A == Z || B == Z
|
||||||
|
|
||||||
|
/connection_edge/zone/erase()
|
||||||
|
A.edges.Remove(src)
|
||||||
|
B.edges.Remove(src)
|
||||||
|
. = ..()
|
||||||
|
|
||||||
|
/connection_edge/zone/tick()
|
||||||
|
if(A.invalid || B.invalid)
|
||||||
|
erase()
|
||||||
|
return
|
||||||
|
//world << "[id]: Tick [air_master.current_cycle]: \..."
|
||||||
|
if(direct)
|
||||||
|
if(air_master.equivalent_pressure(A, B))
|
||||||
|
//world << "merged."
|
||||||
|
erase()
|
||||||
|
air_master.merge(A, B)
|
||||||
|
//world << "zones merged."
|
||||||
|
return
|
||||||
|
|
||||||
|
//air_master.equalize(A, B)
|
||||||
|
ShareRatio(A.air,B.air,coefficient)
|
||||||
|
air_master.mark_zone_update(A)
|
||||||
|
air_master.mark_zone_update(B)
|
||||||
|
//world << "equalized."
|
||||||
|
|
||||||
|
var/differential = A.air.return_pressure() - B.air.return_pressure()
|
||||||
|
if(abs(differential) < zas_settings.Get(/datum/ZAS_Setting/airflow_lightest_pressure)) return
|
||||||
|
|
||||||
|
var/list/attracted
|
||||||
|
var/list/repelled
|
||||||
|
if(differential > 0)
|
||||||
|
attracted = A.movables()
|
||||||
|
repelled = B.movables()
|
||||||
|
else
|
||||||
|
attracted = B.movables()
|
||||||
|
repelled = A.movables()
|
||||||
|
|
||||||
|
flow(attracted, abs(differential), 0)
|
||||||
|
flow(repelled, abs(differential), 1)
|
||||||
|
|
||||||
|
//Helper proc to get connections for a zone.
|
||||||
|
/connection_edge/zone/proc/get_connected_zone(zone/from)
|
||||||
|
if(A == from) return B
|
||||||
|
else return A
|
||||||
|
|
||||||
|
/connection_edge/unsimulated/var/turf/B
|
||||||
|
/connection_edge/unsimulated/var/datum/gas_mixture/air
|
||||||
|
|
||||||
|
/connection_edge/unsimulated/New(zone/A, turf/B)
|
||||||
|
src.A = A
|
||||||
|
src.B = B
|
||||||
|
A.edges.Add(src)
|
||||||
|
air = B.return_air()
|
||||||
|
//id = 52*A.id
|
||||||
|
//world << "New edge from [A] to [B]."
|
||||||
|
|
||||||
|
/connection_edge/unsimulated/add_connection(connection/c)
|
||||||
|
. = ..()
|
||||||
|
connecting_turfs.Add(c.B)
|
||||||
|
air.group_multiplier = coefficient
|
||||||
|
|
||||||
|
/connection_edge/unsimulated/remove_connection(connection/c)
|
||||||
|
connecting_turfs.Remove(c.B)
|
||||||
|
air.group_multiplier = coefficient
|
||||||
|
. = ..()
|
||||||
|
|
||||||
|
/connection_edge/unsimulated/erase()
|
||||||
|
A.edges.Remove(src)
|
||||||
|
. = ..()
|
||||||
|
|
||||||
|
/connection_edge/unsimulated/contains_zone(zone/Z)
|
||||||
|
return A == Z
|
||||||
|
|
||||||
|
/connection_edge/unsimulated/tick()
|
||||||
|
if(A.invalid)
|
||||||
|
erase()
|
||||||
|
return
|
||||||
|
//world << "[id]: Tick [air_master.current_cycle]: To [B]!"
|
||||||
|
//A.air.mimic(B, coefficient)
|
||||||
|
ShareSpace(A.air,air,dbg_out)
|
||||||
|
air_master.mark_zone_update(A)
|
||||||
|
|
||||||
|
var/differential = A.air.return_pressure() - air.return_pressure()
|
||||||
|
if(abs(differential) < zas_settings.Get(/datum/ZAS_Setting/airflow_lightest_pressure)) return
|
||||||
|
|
||||||
|
var/list/attracted = A.movables()
|
||||||
|
flow(attracted, abs(differential), differential < 0)
|
||||||
|
|
||||||
|
var/list/sharing_lookup_table = list(0.30, 0.40, 0.48, 0.54, 0.60, 0.66)
|
||||||
|
|
||||||
|
proc/ShareRatio(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles)
|
||||||
|
//Shares a specific ratio of gas between mixtures using simple weighted averages.
|
||||||
|
var
|
||||||
|
//WOOT WOOT TOUCH THIS AND YOU ARE A RETARD
|
||||||
|
ratio = sharing_lookup_table[6]
|
||||||
|
//WOOT WOOT TOUCH THIS AND YOU ARE A RETARD
|
||||||
|
|
||||||
|
size = max(1,A.group_multiplier)
|
||||||
|
share_size = max(1,B.group_multiplier)
|
||||||
|
|
||||||
|
full_oxy = A.oxygen * size
|
||||||
|
full_nitro = A.nitrogen * size
|
||||||
|
full_co2 = A.carbon_dioxide * size
|
||||||
|
full_plasma = A.toxins * size
|
||||||
|
|
||||||
|
full_heat_capacity = A.heat_capacity() * size
|
||||||
|
|
||||||
|
s_full_oxy = B.oxygen * share_size
|
||||||
|
s_full_nitro = B.nitrogen * share_size
|
||||||
|
s_full_co2 = B.carbon_dioxide * share_size
|
||||||
|
s_full_plasma = B.toxins * share_size
|
||||||
|
|
||||||
|
s_full_heat_capacity = B.heat_capacity() * share_size
|
||||||
|
|
||||||
|
oxy_avg = (full_oxy + s_full_oxy) / (size + share_size)
|
||||||
|
nit_avg = (full_nitro + s_full_nitro) / (size + share_size)
|
||||||
|
co2_avg = (full_co2 + s_full_co2) / (size + share_size)
|
||||||
|
plasma_avg = (full_plasma + s_full_plasma) / (size + share_size)
|
||||||
|
|
||||||
|
temp_avg = (A.temperature * full_heat_capacity + B.temperature * s_full_heat_capacity) / (full_heat_capacity + s_full_heat_capacity)
|
||||||
|
|
||||||
|
//WOOT WOOT TOUCH THIS AND YOU ARE A RETARD
|
||||||
|
if(sharing_lookup_table.len >= connecting_tiles) //6 or more interconnecting tiles will max at 42% of air moved per tick.
|
||||||
|
ratio = sharing_lookup_table[connecting_tiles]
|
||||||
|
//WOOT WOOT TOUCH THIS AND YOU ARE A RETARD
|
||||||
|
|
||||||
|
A.oxygen = max(0, (A.oxygen - oxy_avg) * (1-ratio) + oxy_avg )
|
||||||
|
A.nitrogen = max(0, (A.nitrogen - nit_avg) * (1-ratio) + nit_avg )
|
||||||
|
A.carbon_dioxide = max(0, (A.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg )
|
||||||
|
A.toxins = max(0, (A.toxins - plasma_avg) * (1-ratio) + plasma_avg )
|
||||||
|
|
||||||
|
A.temperature = max(0, (A.temperature - temp_avg) * (1-ratio) + temp_avg )
|
||||||
|
|
||||||
|
B.oxygen = max(0, (B.oxygen - oxy_avg) * (1-ratio) + oxy_avg )
|
||||||
|
B.nitrogen = max(0, (B.nitrogen - nit_avg) * (1-ratio) + nit_avg )
|
||||||
|
B.carbon_dioxide = max(0, (B.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg )
|
||||||
|
B.toxins = max(0, (B.toxins - plasma_avg) * (1-ratio) + plasma_avg )
|
||||||
|
|
||||||
|
B.temperature = max(0, (B.temperature - temp_avg) * (1-ratio) + temp_avg )
|
||||||
|
|
||||||
|
for(var/datum/gas/G in A.trace_gases)
|
||||||
|
var/datum/gas/H = locate(G.type) in B.trace_gases
|
||||||
|
if(H)
|
||||||
|
var/G_avg = (G.moles*size + H.moles*share_size) / (size+share_size)
|
||||||
|
G.moles = (G.moles - G_avg) * (1-ratio) + G_avg
|
||||||
|
|
||||||
|
H.moles = (H.moles - G_avg) * (1-ratio) + G_avg
|
||||||
|
else
|
||||||
|
H = new G.type
|
||||||
|
B.trace_gases += H
|
||||||
|
var/G_avg = (G.moles*size) / (size+share_size)
|
||||||
|
G.moles = (G.moles - G_avg) * (1-ratio) + G_avg
|
||||||
|
H.moles = (H.moles - G_avg) * (1-ratio) + G_avg
|
||||||
|
|
||||||
|
for(var/datum/gas/G in B.trace_gases)
|
||||||
|
var/datum/gas/H = locate(G.type) in A.trace_gases
|
||||||
|
if(!H)
|
||||||
|
H = new G.type
|
||||||
|
A.trace_gases += H
|
||||||
|
var/G_avg = (G.moles*size) / (size+share_size)
|
||||||
|
G.moles = (G.moles - G_avg) * (1-ratio) + G_avg
|
||||||
|
H.moles = (H.moles - G_avg) * (1-ratio) + G_avg
|
||||||
|
|
||||||
|
A.update_values()
|
||||||
|
B.update_values()
|
||||||
|
|
||||||
|
if(A.compare(B)) return 1
|
||||||
|
else return 0
|
||||||
|
|
||||||
|
proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output)
|
||||||
|
//A modified version of ShareRatio for spacing gas at the same rate as if it were going into a large airless room.
|
||||||
|
if(!unsimulated_tiles)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
var
|
||||||
|
unsim_oxygen = 0
|
||||||
|
unsim_nitrogen = 0
|
||||||
|
unsim_co2 = 0
|
||||||
|
unsim_plasma = 0
|
||||||
|
unsim_heat_capacity = 0
|
||||||
|
unsim_temperature = 0
|
||||||
|
|
||||||
|
size = max(1,A.group_multiplier)
|
||||||
|
|
||||||
|
var/tileslen
|
||||||
|
var/share_size
|
||||||
|
|
||||||
|
if(istype(unsimulated_tiles, /datum/gas_mixture))
|
||||||
|
var/datum/gas_mixture/avg_unsim = unsimulated_tiles
|
||||||
|
unsim_oxygen = avg_unsim.oxygen
|
||||||
|
unsim_co2 = avg_unsim.carbon_dioxide
|
||||||
|
unsim_nitrogen = avg_unsim.nitrogen
|
||||||
|
unsim_plasma = avg_unsim.toxins
|
||||||
|
unsim_temperature = avg_unsim.temperature
|
||||||
|
share_size = max(1, max(size + 3, 1) + avg_unsim.group_multiplier)
|
||||||
|
tileslen = avg_unsim.group_multiplier
|
||||||
|
|
||||||
|
if(dbg_output)
|
||||||
|
world << "O2: [unsim_oxygen] N2: [unsim_nitrogen] Size: [share_size] Tiles: [tileslen]"
|
||||||
|
|
||||||
|
else if(istype(unsimulated_tiles, /list))
|
||||||
|
if(!unsimulated_tiles.len)
|
||||||
|
return 0
|
||||||
|
// We use the same size for the potentially single space tile
|
||||||
|
// as we use for the entire room. Why is this?
|
||||||
|
// Short answer: We do not want larger rooms to depressurize more
|
||||||
|
// slowly than small rooms, preserving our good old "hollywood-style"
|
||||||
|
// oh-shit effect when large rooms get breached, but still having small
|
||||||
|
// rooms remain pressurized for long enough to make escape possible.
|
||||||
|
share_size = max(1, max(size + 3, 1) + unsimulated_tiles.len)
|
||||||
|
var/correction_ratio = share_size / unsimulated_tiles.len
|
||||||
|
|
||||||
|
for(var/turf/T in unsimulated_tiles)
|
||||||
|
unsim_oxygen += T.oxygen
|
||||||
|
unsim_co2 += T.carbon_dioxide
|
||||||
|
unsim_nitrogen += T.nitrogen
|
||||||
|
unsim_plasma += T.toxins
|
||||||
|
unsim_temperature += T.temperature/unsimulated_tiles.len
|
||||||
|
|
||||||
|
//These values require adjustment in order to properly represent a room of the specified size.
|
||||||
|
unsim_oxygen *= correction_ratio
|
||||||
|
unsim_co2 *= correction_ratio
|
||||||
|
unsim_nitrogen *= correction_ratio
|
||||||
|
unsim_plasma *= correction_ratio
|
||||||
|
tileslen = unsimulated_tiles.len
|
||||||
|
|
||||||
|
else //invalid input type
|
||||||
|
return 0
|
||||||
|
|
||||||
|
unsim_heat_capacity = HEAT_CAPACITY_CALCULATION(unsim_oxygen, unsim_co2, unsim_nitrogen, unsim_plasma)
|
||||||
|
|
||||||
|
var
|
||||||
|
ratio = sharing_lookup_table[6]
|
||||||
|
|
||||||
|
old_pressure = A.return_pressure()
|
||||||
|
|
||||||
|
full_oxy = A.oxygen * size
|
||||||
|
full_nitro = A.nitrogen * size
|
||||||
|
full_co2 = A.carbon_dioxide * size
|
||||||
|
full_plasma = A.toxins * size
|
||||||
|
|
||||||
|
full_heat_capacity = A.heat_capacity() * size
|
||||||
|
|
||||||
|
oxy_avg = (full_oxy + unsim_oxygen*share_size) / (size + share_size)
|
||||||
|
nit_avg = (full_nitro + unsim_nitrogen*share_size) / (size + share_size)
|
||||||
|
co2_avg = (full_co2 + unsim_co2*share_size) / (size + share_size)
|
||||||
|
plasma_avg = (full_plasma + unsim_plasma*share_size) / (size + share_size)
|
||||||
|
|
||||||
|
temp_avg = 0
|
||||||
|
|
||||||
|
if((full_heat_capacity + unsim_heat_capacity) > 0)
|
||||||
|
temp_avg = (A.temperature * full_heat_capacity + unsim_temperature * unsim_heat_capacity) / (full_heat_capacity + unsim_heat_capacity)
|
||||||
|
|
||||||
|
if(sharing_lookup_table.len >= tileslen) //6 or more interconnecting tiles will max at 42% of air moved per tick.
|
||||||
|
ratio = sharing_lookup_table[tileslen]
|
||||||
|
|
||||||
|
if(dbg_output)
|
||||||
|
world << "Ratio: [ratio]"
|
||||||
|
world << "Avg O2: [oxy_avg] N2: [nit_avg]"
|
||||||
|
|
||||||
|
A.oxygen = max(0, (A.oxygen - oxy_avg) * (1 - ratio) + oxy_avg )
|
||||||
|
A.nitrogen = max(0, (A.nitrogen - nit_avg) * (1 - ratio) + nit_avg )
|
||||||
|
A.carbon_dioxide = max(0, (A.carbon_dioxide - co2_avg) * (1 - ratio) + co2_avg )
|
||||||
|
A.toxins = max(0, (A.toxins - plasma_avg) * (1 - ratio) + plasma_avg )
|
||||||
|
|
||||||
|
A.temperature = max(TCMB, (A.temperature - temp_avg) * (1 - ratio) + temp_avg )
|
||||||
|
|
||||||
|
for(var/datum/gas/G in A.trace_gases)
|
||||||
|
var/G_avg = (G.moles * size) / (size + share_size)
|
||||||
|
G.moles = (G.moles - G_avg) * (1 - ratio) + G_avg
|
||||||
|
|
||||||
|
A.update_values()
|
||||||
|
|
||||||
|
if(dbg_output) world << "Result: [abs(old_pressure - A.return_pressure())] kPa"
|
||||||
|
|
||||||
|
return abs(old_pressure - A.return_pressure())
|
||||||
|
|
||||||
|
|
||||||
|
proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles)
|
||||||
|
//This implements a simplistic version of the Stefan-Boltzmann law.
|
||||||
|
var/energy_delta = ((A.temperature - B.temperature) ** 4) * 5.6704e-8 * connecting_tiles * 2.5
|
||||||
|
var/maximum_energy_delta = max(0, min(A.temperature * A.heat_capacity() * A.group_multiplier, B.temperature * B.heat_capacity() * B.group_multiplier))
|
||||||
|
if(maximum_energy_delta > abs(energy_delta))
|
||||||
|
if(energy_delta < 0)
|
||||||
|
maximum_energy_delta *= -1
|
||||||
|
energy_delta = maximum_energy_delta
|
||||||
|
|
||||||
|
A.temperature -= energy_delta / (A.heat_capacity() * A.group_multiplier)
|
||||||
|
B.temperature += energy_delta / (B.heat_capacity() * B.group_multiplier)
|
||||||
102
code/ZAS/ConnectionManager.dm
Normal file
102
code/ZAS/ConnectionManager.dm
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Overview:
|
||||||
|
The connection_manager class stores connections in each cardinal direction on a turf.
|
||||||
|
It isn't always present if a turf has no connections, check if(connections) before using.
|
||||||
|
Contains procs for mass manipulation of connection data.
|
||||||
|
|
||||||
|
Class Vars:
|
||||||
|
|
||||||
|
NSEWUD - Connections to this turf in each cardinal direction.
|
||||||
|
|
||||||
|
Class Procs:
|
||||||
|
|
||||||
|
get(d)
|
||||||
|
Returns the connection (if any) in this direction.
|
||||||
|
Preferable to accessing the connection directly because it checks validity.
|
||||||
|
|
||||||
|
place(connection/c, d)
|
||||||
|
Called by air_master.connect(). Sets the connection in the specified direction to c.
|
||||||
|
|
||||||
|
update_all()
|
||||||
|
Called after turf/update_air_properties(). Updates the validity of all connections on this turf.
|
||||||
|
|
||||||
|
erase_all()
|
||||||
|
Called when the turf is changed with ChangeTurf(). Erases all existing connections.
|
||||||
|
|
||||||
|
check(connection/c)
|
||||||
|
Checks for connection validity. It's possible to have a reference to a connection that has been erased.
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/turf/var/tmp/connection_manager/connections
|
||||||
|
|
||||||
|
/connection_manager/var/connection/N
|
||||||
|
/connection_manager/var/connection/S
|
||||||
|
/connection_manager/var/connection/E
|
||||||
|
/connection_manager/var/connection/W
|
||||||
|
|
||||||
|
#ifdef ZLEVELS
|
||||||
|
/connection_manager/var/connection/U
|
||||||
|
/connection_manager/var/connection/D
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/connection_manager/proc/get(d)
|
||||||
|
switch(d)
|
||||||
|
if(NORTH)
|
||||||
|
if(check(N)) return N
|
||||||
|
else return null
|
||||||
|
if(SOUTH)
|
||||||
|
if(check(S)) return S
|
||||||
|
else return null
|
||||||
|
if(EAST)
|
||||||
|
if(check(E)) return E
|
||||||
|
else return null
|
||||||
|
if(WEST)
|
||||||
|
if(check(W)) return W
|
||||||
|
else return null
|
||||||
|
|
||||||
|
#ifdef ZLEVELS
|
||||||
|
if(UP)
|
||||||
|
if(check(U)) return U
|
||||||
|
else return null
|
||||||
|
if(DOWN)
|
||||||
|
if(check(D)) return D
|
||||||
|
else return null
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/connection_manager/proc/place(connection/c, d)
|
||||||
|
switch(d)
|
||||||
|
if(NORTH) N = c
|
||||||
|
if(SOUTH) S = c
|
||||||
|
if(EAST) E = c
|
||||||
|
if(WEST) W = c
|
||||||
|
|
||||||
|
#ifdef ZLEVELS
|
||||||
|
if(UP) U = c
|
||||||
|
if(DOWN) D = c
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/connection_manager/proc/update_all()
|
||||||
|
if(check(N)) N.update()
|
||||||
|
if(check(S)) S.update()
|
||||||
|
if(check(E)) E.update()
|
||||||
|
if(check(W)) W.update()
|
||||||
|
#ifdef ZLEVELS
|
||||||
|
if(check(U)) U.update()
|
||||||
|
if(check(D)) D.update()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/connection_manager/proc/erase_all()
|
||||||
|
if(check(N)) N.erase()
|
||||||
|
if(check(S)) S.erase()
|
||||||
|
if(check(E)) E.erase()
|
||||||
|
if(check(W)) W.erase()
|
||||||
|
#ifdef ZLEVELS
|
||||||
|
if(check(U)) U.erase()
|
||||||
|
if(check(D)) D.erase()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/connection_manager/proc/check(connection/c)
|
||||||
|
return c && c.valid()
|
||||||
321
code/ZAS/Controller.dm
Normal file
321
code/ZAS/Controller.dm
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
var/datum/controller/air_system/air_master
|
||||||
|
|
||||||
|
var/tick_multiplier = 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Overview:
|
||||||
|
The air controller does everything. There are tons of procs in here.
|
||||||
|
|
||||||
|
Class Vars:
|
||||||
|
zones - All zones currently holding one or more turfs.
|
||||||
|
edges - All processing edges.
|
||||||
|
|
||||||
|
tiles_to_update - Tiles scheduled to update next tick.
|
||||||
|
zones_to_update - Zones which have had their air changed and need air archival.
|
||||||
|
active_hotspots - All processing fire objects.
|
||||||
|
|
||||||
|
active_zones - The number of zones which were archived last tick. Used in debug verbs.
|
||||||
|
next_id - The next UID to be applied to a zone. Mostly useful for debugging purposes as zones do not need UIDs to function.
|
||||||
|
|
||||||
|
Class Procs:
|
||||||
|
|
||||||
|
mark_for_update(turf/T)
|
||||||
|
Adds the turf to the update list. When updated, update_air_properties() will be called.
|
||||||
|
When stuff changes that might affect airflow, call this. It's basically the only thing you need.
|
||||||
|
|
||||||
|
add_zone(zone/Z) and remove_zone(zone/Z)
|
||||||
|
Adds zones to the zones list. Does not mark them for update.
|
||||||
|
|
||||||
|
air_blocked(turf/A, turf/B)
|
||||||
|
Returns a bitflag consisting of:
|
||||||
|
AIR_BLOCKED - The connection between turfs is physically blocked. No air can pass.
|
||||||
|
ZONE_BLOCKED - There is a door between the turfs, so zones cannot cross. Air may or may not be permeable.
|
||||||
|
|
||||||
|
has_valid_zone(turf/T)
|
||||||
|
Checks the presence and validity of T's zone.
|
||||||
|
May be called on unsimulated turfs, returning 0.
|
||||||
|
|
||||||
|
merge(zone/A, zone/B)
|
||||||
|
Called when zones have a direct connection and equivalent pressure and temperature.
|
||||||
|
Merges the zones to create a single zone.
|
||||||
|
|
||||||
|
connect(turf/simulated/A, turf/B)
|
||||||
|
Called by turf/update_air_properties(). The first argument must be simulated.
|
||||||
|
Creates a connection between A and B.
|
||||||
|
|
||||||
|
mark_zone_update(zone/Z)
|
||||||
|
Adds zone to the update list. Unlike mark_for_update(), this one is called automatically whenever
|
||||||
|
air is returned from a simulated turf.
|
||||||
|
|
||||||
|
equivalent_pressure(zone/A, zone/B)
|
||||||
|
Currently identical to A.air.compare(B.air). Returns 1 when directly connected zones are ready to be merged.
|
||||||
|
|
||||||
|
get_edge(zone/A, zone/B)
|
||||||
|
get_edge(zone/A, turf/B)
|
||||||
|
Gets a valid connection_edge between A and B, creating a new one if necessary.
|
||||||
|
|
||||||
|
has_same_air(turf/A, turf/B)
|
||||||
|
Used to determine if an unsimulated edge represents a specific turf.
|
||||||
|
Simulated edges use connection_edge/contains_zone() for the same purpose.
|
||||||
|
Returns 1 if A has identical gases and temperature to B.
|
||||||
|
|
||||||
|
remove_edge(connection_edge/edge)
|
||||||
|
Called when an edge is erased. Removes it from processing.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
//Geometry lists
|
||||||
|
/datum/controller/air_system/var/list/zones = list()
|
||||||
|
/datum/controller/air_system/var/list/edges = list()
|
||||||
|
|
||||||
|
//Geometry updates lists
|
||||||
|
/datum/controller/air_system/var/list/tiles_to_update = list()
|
||||||
|
/datum/controller/air_system/var/list/zones_to_update = list()
|
||||||
|
/datum/controller/air_system/var/list/active_hotspots = list()
|
||||||
|
|
||||||
|
/datum/controller/air_system/var/active_zones = 0
|
||||||
|
|
||||||
|
/datum/controller/air_system/var/current_cycle = 0
|
||||||
|
/datum/controller/air_system/var/update_delay = 5 //How long between check should it try to process atmos again.
|
||||||
|
/datum/controller/air_system/var/failed_ticks = 0 //How many ticks have runtimed?
|
||||||
|
|
||||||
|
/datum/controller/air_system/var/tick_progress = 0
|
||||||
|
|
||||||
|
/datum/controller/air_system/var/next_id = 1 //Used to keep track of zone UIDs.
|
||||||
|
|
||||||
|
/datum/controller/air_system/proc/Setup()
|
||||||
|
//Purpose: Call this at the start to setup air groups geometry
|
||||||
|
// (Warning: Very processor intensive but only must be done once per round)
|
||||||
|
//Called by: Gameticker/Master controller
|
||||||
|
//Inputs: None.
|
||||||
|
//Outputs: None.
|
||||||
|
|
||||||
|
#ifndef ZASDBG
|
||||||
|
set background = 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
world << "\red \b Processing Geometry..."
|
||||||
|
sleep(-1)
|
||||||
|
|
||||||
|
var/start_time = world.timeofday
|
||||||
|
|
||||||
|
var/simulated_turf_count = 0
|
||||||
|
|
||||||
|
for(var/turf/simulated/S in world)
|
||||||
|
simulated_turf_count++
|
||||||
|
S.update_air_properties()
|
||||||
|
|
||||||
|
world << {"<font color='red'><b>Geometry initialized in [round(0.1*(world.timeofday-start_time),0.1)] seconds.</b>
|
||||||
|
Total Simulated Turfs: [simulated_turf_count]
|
||||||
|
Total Zones: [zones.len]
|
||||||
|
Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_count]</font>"}
|
||||||
|
|
||||||
|
// spawn Start()
|
||||||
|
|
||||||
|
|
||||||
|
/datum/controller/air_system/proc/Start()
|
||||||
|
//Purpose: This is kicked off by the master controller, and controls the processing of all atmosphere.
|
||||||
|
//Called by: Master controller
|
||||||
|
//Inputs: None.
|
||||||
|
//Outputs: None.
|
||||||
|
|
||||||
|
#ifndef ZASDBG
|
||||||
|
set background = 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
Tick()
|
||||||
|
sleep(max(5,update_delay*tick_multiplier))
|
||||||
|
|
||||||
|
|
||||||
|
/datum/controller/air_system/proc/Tick()
|
||||||
|
. = 1 //Set the default return value, for runtime detection.
|
||||||
|
|
||||||
|
current_cycle++
|
||||||
|
|
||||||
|
//If there are tiles to update, do so.
|
||||||
|
tick_progress = "updating turf properties"
|
||||||
|
|
||||||
|
var/list/updating
|
||||||
|
|
||||||
|
if(tiles_to_update.len)
|
||||||
|
updating = tiles_to_update
|
||||||
|
tiles_to_update = list()
|
||||||
|
|
||||||
|
#ifdef ZASDBG
|
||||||
|
var/updated = 0
|
||||||
|
#endif
|
||||||
|
for(var/turf/T in updating)
|
||||||
|
T.update_air_properties()
|
||||||
|
T.post_update_air_properties()
|
||||||
|
T.needs_air_update = 0
|
||||||
|
#ifdef ZASDBG
|
||||||
|
T.overlays -= mark
|
||||||
|
updated++
|
||||||
|
#endif
|
||||||
|
//sleep(1)
|
||||||
|
|
||||||
|
#ifdef ZASDBG
|
||||||
|
if(updated != updating.len)
|
||||||
|
tick_progress = "[updating.len - updated] tiles left unupdated."
|
||||||
|
world << "\red [tick_progress]"
|
||||||
|
. = 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Where gas exchange happens.
|
||||||
|
if(.)
|
||||||
|
tick_progress = "processing edges"
|
||||||
|
|
||||||
|
for(var/connection_edge/edge in edges)
|
||||||
|
edge.tick()
|
||||||
|
|
||||||
|
//Process fires.
|
||||||
|
if(.)
|
||||||
|
tick_progress = "processing fire"
|
||||||
|
|
||||||
|
for(var/obj/fire/fire in active_hotspots)
|
||||||
|
fire.process()
|
||||||
|
|
||||||
|
//Process zones.
|
||||||
|
if(.)
|
||||||
|
tick_progress = "updating zones"
|
||||||
|
|
||||||
|
active_zones = zones_to_update.len
|
||||||
|
if(zones_to_update.len)
|
||||||
|
updating = zones_to_update
|
||||||
|
zones_to_update = list()
|
||||||
|
for(var/zone/zone in updating)
|
||||||
|
zone.tick()
|
||||||
|
zone.needs_update = 0
|
||||||
|
|
||||||
|
if(.)
|
||||||
|
tick_progress = "success"
|
||||||
|
|
||||||
|
/datum/controller/air_system/proc/add_zone(zone/z)
|
||||||
|
zones.Add(z)
|
||||||
|
z.name = "Zone [next_id++]"
|
||||||
|
mark_zone_update(z)
|
||||||
|
|
||||||
|
/datum/controller/air_system/proc/remove_zone(zone/z)
|
||||||
|
zones.Remove(z)
|
||||||
|
|
||||||
|
/datum/controller/air_system/proc/air_blocked(turf/A, turf/B)
|
||||||
|
#ifdef ZASDBG
|
||||||
|
ASSERT(isturf(A))
|
||||||
|
ASSERT(isturf(B))
|
||||||
|
#endif
|
||||||
|
var/ablock = A.c_airblock(B)
|
||||||
|
if(ablock == BLOCKED) return BLOCKED
|
||||||
|
return ablock | B.c_airblock(A)
|
||||||
|
|
||||||
|
/datum/controller/air_system/proc/has_valid_zone(turf/simulated/T)
|
||||||
|
#ifdef ZASDBG
|
||||||
|
ASSERT(istype(T))
|
||||||
|
#endif
|
||||||
|
return istype(T) && T.zone && !T.zone.invalid
|
||||||
|
|
||||||
|
/datum/controller/air_system/proc/merge(zone/A, zone/B)
|
||||||
|
#ifdef ZASDBG
|
||||||
|
ASSERT(istype(A))
|
||||||
|
ASSERT(istype(B))
|
||||||
|
ASSERT(!A.invalid)
|
||||||
|
ASSERT(!B.invalid)
|
||||||
|
ASSERT(A != B)
|
||||||
|
#endif
|
||||||
|
if(A.contents.len < B.contents.len)
|
||||||
|
A.c_merge(B)
|
||||||
|
mark_zone_update(B)
|
||||||
|
else
|
||||||
|
B.c_merge(A)
|
||||||
|
mark_zone_update(A)
|
||||||
|
|
||||||
|
/datum/controller/air_system/proc/connect(turf/simulated/A, turf/simulated/B)
|
||||||
|
#ifdef ZASDBG
|
||||||
|
ASSERT(istype(A))
|
||||||
|
ASSERT(isturf(B))
|
||||||
|
ASSERT(A.zone)
|
||||||
|
ASSERT(!A.zone.invalid)
|
||||||
|
//ASSERT(B.zone)
|
||||||
|
ASSERT(A != B)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var/block = air_master.air_blocked(A,B)
|
||||||
|
if(block & AIR_BLOCKED) return
|
||||||
|
|
||||||
|
var/direct = !(block & ZONE_BLOCKED)
|
||||||
|
var/space = !istype(B)
|
||||||
|
|
||||||
|
if(direct && !space)
|
||||||
|
if(equivalent_pressure(A.zone,B.zone) || current_cycle == 0)
|
||||||
|
merge(A.zone,B.zone)
|
||||||
|
return
|
||||||
|
|
||||||
|
var
|
||||||
|
a_to_b = get_dir(A,B)
|
||||||
|
b_to_a = get_dir(B,A)
|
||||||
|
|
||||||
|
if(!A.connections) A.connections = new
|
||||||
|
if(!B.connections) B.connections = new
|
||||||
|
|
||||||
|
if(A.connections.get(a_to_b)) return
|
||||||
|
if(B.connections.get(b_to_a)) return
|
||||||
|
if(!space)
|
||||||
|
if(A.zone == B.zone) return
|
||||||
|
|
||||||
|
|
||||||
|
var/connection/c = new /connection(A,B)
|
||||||
|
|
||||||
|
A.connections.place(c, a_to_b)
|
||||||
|
B.connections.place(c, b_to_a)
|
||||||
|
|
||||||
|
if(direct) c.mark_direct()
|
||||||
|
|
||||||
|
/datum/controller/air_system/proc/mark_for_update(turf/T)
|
||||||
|
#ifdef ZASDBG
|
||||||
|
ASSERT(isturf(T))
|
||||||
|
#endif
|
||||||
|
if(T.needs_air_update) return
|
||||||
|
tiles_to_update |= T
|
||||||
|
#ifdef ZASDBG
|
||||||
|
T.overlays += mark
|
||||||
|
#endif
|
||||||
|
T.needs_air_update = 1
|
||||||
|
|
||||||
|
/datum/controller/air_system/proc/mark_zone_update(zone/Z)
|
||||||
|
#ifdef ZASDBG
|
||||||
|
ASSERT(istype(Z))
|
||||||
|
#endif
|
||||||
|
if(Z.needs_update) return
|
||||||
|
zones_to_update.Add(Z)
|
||||||
|
Z.needs_update = 1
|
||||||
|
|
||||||
|
/datum/controller/air_system/proc/equivalent_pressure(zone/A, zone/B)
|
||||||
|
return A.air.compare(B.air)
|
||||||
|
|
||||||
|
/datum/controller/air_system/proc/get_edge(zone/A, zone/B)
|
||||||
|
|
||||||
|
if(istype(B))
|
||||||
|
for(var/connection_edge/zone/edge in A.edges)
|
||||||
|
if(edge.contains_zone(B)) return edge
|
||||||
|
var/connection_edge/edge = new/connection_edge/zone(A,B)
|
||||||
|
edges.Add(edge)
|
||||||
|
return edge
|
||||||
|
else
|
||||||
|
for(var/connection_edge/unsimulated/edge in A.edges)
|
||||||
|
if(has_same_air(edge.B,B)) return edge
|
||||||
|
var/connection_edge/edge = new/connection_edge/unsimulated(A,B)
|
||||||
|
edges.Add(edge)
|
||||||
|
return edge
|
||||||
|
|
||||||
|
/datum/controller/air_system/proc/has_same_air(turf/A, turf/B)
|
||||||
|
if(A.oxygen != B.oxygen) return 0
|
||||||
|
if(A.nitrogen != B.nitrogen) return 0
|
||||||
|
if(A.toxins != B.toxins) return 0
|
||||||
|
if(A.carbon_dioxide != B.carbon_dioxide) return 0
|
||||||
|
if(A.temperature != B.temperature) return 0
|
||||||
|
return 1
|
||||||
|
|
||||||
|
/datum/controller/air_system/proc/remove_edge(connection/c)
|
||||||
|
edges.Remove(c)
|
||||||
@@ -1,124 +1,20 @@
|
|||||||
|
var/image/assigned = image('icons/Testing/Zone.dmi', icon_state = "assigned")
|
||||||
|
var/image/created = image('icons/Testing/Zone.dmi', icon_state = "created")
|
||||||
|
var/image/merged = image('icons/Testing/Zone.dmi', icon_state = "merged")
|
||||||
|
var/image/invalid_zone = image('icons/Testing/Zone.dmi', icon_state = "invalid")
|
||||||
|
var/image/air_blocked = image('icons/Testing/Zone.dmi', icon_state = "block")
|
||||||
|
var/image/zone_blocked = image('icons/Testing/Zone.dmi', icon_state = "zoneblock")
|
||||||
|
var/image/blocked = image('icons/Testing/Zone.dmi', icon_state = "fullblock")
|
||||||
|
var/image/mark = image('icons/Testing/Zone.dmi', icon_state = "mark")
|
||||||
|
|
||||||
client/proc/Zone_Info(turf/T as null|turf)
|
/connection_edge/var/dbg_out = 0
|
||||||
set category = "Debug"
|
|
||||||
if(T)
|
|
||||||
if(T.zone)
|
|
||||||
T.zone.DebugDisplay(src)
|
|
||||||
else
|
|
||||||
mob << "No zone here."
|
|
||||||
else
|
|
||||||
if(zone_debug_images)
|
|
||||||
for(var/zone in zone_debug_images)
|
|
||||||
images -= zone_debug_images[zone]
|
|
||||||
zone_debug_images = null
|
|
||||||
|
|
||||||
client/var/list/zone_debug_images
|
/turf/var/tmp/dbg_img
|
||||||
|
/turf/proc/dbg(image/img, d = 0)
|
||||||
client/proc/Test_ZAS_Connection(var/turf/simulated/T as turf)
|
if(d > 0) img.dir = d
|
||||||
set category = "Debug"
|
overlays -= dbg_img
|
||||||
if(!istype(T))
|
overlays += img
|
||||||
return
|
dbg_img = img
|
||||||
|
|
||||||
var/direction_list = list(\
|
|
||||||
"North" = NORTH,\
|
|
||||||
"South" = SOUTH,\
|
|
||||||
"East" = EAST,\
|
|
||||||
"West" = WEST,\
|
|
||||||
"N/A" = null)
|
|
||||||
var/direction = input("What direction do you wish to test?","Set direction") as null|anything in direction_list
|
|
||||||
if(!direction)
|
|
||||||
return
|
|
||||||
|
|
||||||
if(direction == "N/A")
|
|
||||||
if(T.CanPass(null, T, 0,0))
|
|
||||||
mob << "The turf can pass air! :D"
|
|
||||||
else
|
|
||||||
mob << "No air passage :x"
|
|
||||||
return
|
|
||||||
|
|
||||||
var/turf/simulated/other_turf = get_step(T, direction_list[direction])
|
|
||||||
if(!istype(other_turf))
|
|
||||||
return
|
|
||||||
|
|
||||||
var/pass_directions = T.CanPass(null, other_turf, 0, 0) + 2 * other_turf.CanPass(null, T, 0, 0)
|
|
||||||
|
|
||||||
switch(pass_directions)
|
|
||||||
if(0)
|
|
||||||
mob << "Neither turf can connect. :("
|
|
||||||
|
|
||||||
if(1)
|
|
||||||
mob << "The initial turf only can connect. :\\"
|
|
||||||
|
|
||||||
if(2)
|
|
||||||
mob << "The other turf can connect, but not the initial turf. :/"
|
|
||||||
|
|
||||||
if(3)
|
|
||||||
mob << "Both turfs can connect! :)"
|
|
||||||
|
|
||||||
|
|
||||||
zone/proc/DebugDisplay(client/client)
|
|
||||||
if(!istype(client))
|
|
||||||
return
|
|
||||||
|
|
||||||
if(!dbg_output)
|
|
||||||
dbg_output = 1 //Don't want to be spammed when someone investigates a zone...
|
|
||||||
|
|
||||||
if(!client.zone_debug_images)
|
|
||||||
client.zone_debug_images = list()
|
|
||||||
|
|
||||||
var/list/current_zone_images = list()
|
|
||||||
|
|
||||||
for(var/turf/T in contents)
|
|
||||||
current_zone_images += image('icons/misc/debug_group.dmi', T, null, TURF_LAYER)
|
|
||||||
|
|
||||||
for(var/turf/space/S in unsimulated_tiles)
|
|
||||||
current_zone_images += image('icons/misc/debug_space.dmi', S, null, TURF_LAYER)
|
|
||||||
for(var/turf/simulated/floor/plating/airless/catwalk/C in unsimulated_tiles)
|
|
||||||
current_zone_images += image('icons/misc/debug_space.dmi', C, null, TURF_LAYER)
|
|
||||||
|
|
||||||
client << "<u>Zone Air Contents</u>"
|
|
||||||
client << "Oxygen: [air.oxygen]"
|
|
||||||
client << "Nitrogen: [air.nitrogen]"
|
|
||||||
client << "Plasma: [air.toxins]"
|
|
||||||
client << "Carbon Dioxide: [air.carbon_dioxide]"
|
|
||||||
client << "Temperature: [air.temperature] K"
|
|
||||||
client << "Heat Energy: [air.temperature * air.heat_capacity()] J"
|
|
||||||
client << "Pressure: [air.return_pressure()] KPa"
|
|
||||||
client << ""
|
|
||||||
client << "Space Tiles: [length(unsimulated_tiles)]"
|
|
||||||
client << "Movable Objects: [length(movables())]"
|
|
||||||
client << "<u>Connections: [length(connections)]</u>"
|
|
||||||
|
|
||||||
for(var/connection/C in connections)
|
|
||||||
client << "\ref[C] [C.A] --> [C.B] [(C.indirect?"Open":"Closed")]"
|
|
||||||
current_zone_images += image('icons/misc/debug_connect.dmi', C.A, null, TURF_LAYER)
|
|
||||||
current_zone_images += image('icons/misc/debug_connect.dmi', C.B, null, TURF_LAYER)
|
|
||||||
|
|
||||||
client << "Connected Zones:"
|
|
||||||
for(var/zone/zone in connected_zones)
|
|
||||||
client << "\ref[zone] [zone] - [connected_zones[zone]] (Connected)"
|
|
||||||
|
|
||||||
for(var/zone/zone in closed_connection_zones)
|
|
||||||
client << "\ref[zone] [zone] - [closed_connection_zones[zone]] (Unconnected)"
|
|
||||||
|
|
||||||
for(var/C in connections)
|
|
||||||
if(!istype(C,/connection))
|
|
||||||
client << "[C] (Not Connection!)"
|
|
||||||
|
|
||||||
if(!client.zone_debug_images)
|
|
||||||
client.zone_debug_images = list()
|
|
||||||
client.zone_debug_images[src] = current_zone_images
|
|
||||||
|
|
||||||
client.images += client.zone_debug_images[src]
|
|
||||||
|
|
||||||
else
|
|
||||||
dbg_output = 0
|
|
||||||
|
|
||||||
client.images -= client.zone_debug_images[src]
|
|
||||||
client.zone_debug_images.Remove(src)
|
|
||||||
|
|
||||||
for(var/zone/Z in zones)
|
|
||||||
if(Z.air == air && Z != src)
|
|
||||||
var/turf/zloc = pick(Z.contents)
|
|
||||||
client << "\red Illegal air datum shared by: [zloc.loc.name]"
|
|
||||||
|
|
||||||
|
proc/soft_assert(thing,fail)
|
||||||
|
if(!thing) message_admins(fail)
|
||||||
238
code/ZAS/Diagnostic.dm
Normal file
238
code/ZAS/Diagnostic.dm
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
client/proc/ZoneTick()
|
||||||
|
set category = "Debug"
|
||||||
|
set name = "Process Atmos"
|
||||||
|
|
||||||
|
var/result = air_master.Tick()
|
||||||
|
if(result)
|
||||||
|
src << "Sucessfully Processed."
|
||||||
|
|
||||||
|
else
|
||||||
|
src << "Failed to process! ([air_master.tick_progress])"
|
||||||
|
|
||||||
|
|
||||||
|
client/proc/Zone_Info(turf/T as null|turf)
|
||||||
|
set category = "Debug"
|
||||||
|
if(T)
|
||||||
|
if(istype(T,/turf/simulated) && T:zone)
|
||||||
|
T:zone:dbg_data(src)
|
||||||
|
else
|
||||||
|
mob << "No zone here."
|
||||||
|
var/datum/gas_mixture/mix = T.return_air()
|
||||||
|
mob << "[mix.return_pressure()] kPa [mix.temperature]C"
|
||||||
|
mob << "O2: [mix.oxygen] N2: [mix.nitrogen] CO2: [mix.carbon_dioxide] TX: [mix.toxins]"
|
||||||
|
else
|
||||||
|
if(zone_debug_images)
|
||||||
|
for(var/zone in zone_debug_images)
|
||||||
|
images -= zone_debug_images[zone]
|
||||||
|
zone_debug_images = null
|
||||||
|
|
||||||
|
client/var/list/zone_debug_images
|
||||||
|
|
||||||
|
client/proc/Test_ZAS_Connection(var/turf/simulated/T as turf)
|
||||||
|
set category = "Debug"
|
||||||
|
if(!istype(T))
|
||||||
|
return
|
||||||
|
|
||||||
|
var/direction_list = list(\
|
||||||
|
"North" = NORTH,\
|
||||||
|
"South" = SOUTH,\
|
||||||
|
"East" = EAST,\
|
||||||
|
"West" = WEST,\
|
||||||
|
"N/A" = null)
|
||||||
|
var/direction = input("What direction do you wish to test?","Set direction") as null|anything in direction_list
|
||||||
|
if(!direction)
|
||||||
|
return
|
||||||
|
|
||||||
|
if(direction == "N/A")
|
||||||
|
if(!(T.c_airblock(T) & AIR_BLOCKED))
|
||||||
|
mob << "The turf can pass air! :D"
|
||||||
|
else
|
||||||
|
mob << "No air passage :x"
|
||||||
|
return
|
||||||
|
|
||||||
|
var/turf/simulated/other_turf = get_step(T, direction_list[direction])
|
||||||
|
if(!istype(other_turf))
|
||||||
|
return
|
||||||
|
|
||||||
|
var/t_block = T.c_airblock(other_turf)
|
||||||
|
var/o_block = other_turf.c_airblock(T)
|
||||||
|
|
||||||
|
if(o_block & AIR_BLOCKED)
|
||||||
|
if(t_block & AIR_BLOCKED)
|
||||||
|
mob << "Neither turf can connect. :("
|
||||||
|
|
||||||
|
else
|
||||||
|
mob << "The initial turf only can connect. :\\"
|
||||||
|
else
|
||||||
|
if(t_block & AIR_BLOCKED)
|
||||||
|
mob << "The other turf can connect, but not the initial turf. :/"
|
||||||
|
|
||||||
|
else
|
||||||
|
mob << "Both turfs can connect! :)"
|
||||||
|
|
||||||
|
mob << "Additionally, \..."
|
||||||
|
|
||||||
|
if(o_block & ZONE_BLOCKED)
|
||||||
|
if(t_block & ZONE_BLOCKED)
|
||||||
|
mob << "neither turf can merge."
|
||||||
|
else
|
||||||
|
mob << "the other turf cannot merge."
|
||||||
|
else
|
||||||
|
if(t_block & ZONE_BLOCKED)
|
||||||
|
mob << "the initial turf cannot merge."
|
||||||
|
else
|
||||||
|
mob << "both turfs can merge."
|
||||||
|
|
||||||
|
|
||||||
|
/*zone/proc/DebugDisplay(client/client)
|
||||||
|
if(!istype(client))
|
||||||
|
return
|
||||||
|
|
||||||
|
if(!dbg_output)
|
||||||
|
dbg_output = 1 //Don't want to be spammed when someone investigates a zone...
|
||||||
|
|
||||||
|
if(!client.zone_debug_images)
|
||||||
|
client.zone_debug_images = list()
|
||||||
|
|
||||||
|
var/list/current_zone_images = list()
|
||||||
|
|
||||||
|
for(var/turf/T in contents)
|
||||||
|
current_zone_images += image('icons/misc/debug_group.dmi', T, null, TURF_LAYER)
|
||||||
|
|
||||||
|
for(var/turf/space/S in unsimulated_tiles)
|
||||||
|
current_zone_images += image('icons/misc/debug_space.dmi', S, null, TURF_LAYER)
|
||||||
|
|
||||||
|
client << "<u>Zone Air Contents</u>"
|
||||||
|
client << "Oxygen: [air.oxygen]"
|
||||||
|
client << "Nitrogen: [air.nitrogen]"
|
||||||
|
client << "Plasma: [air.toxins]"
|
||||||
|
client << "Carbon Dioxide: [air.carbon_dioxide]"
|
||||||
|
client << "Temperature: [air.temperature] K"
|
||||||
|
client << "Heat Energy: [air.temperature * air.heat_capacity()] J"
|
||||||
|
client << "Pressure: [air.return_pressure()] KPa"
|
||||||
|
client << ""
|
||||||
|
client << "Space Tiles: [length(unsimulated_tiles)]"
|
||||||
|
client << "Movable Objects: [length(movables())]"
|
||||||
|
client << "<u>Connections: [length(connections)]</u>"
|
||||||
|
|
||||||
|
for(var/connection/C in connections)
|
||||||
|
client << "\ref[C] [C.A] --> [C.B] [(C.indirect?"Open":"Closed")]"
|
||||||
|
current_zone_images += image('icons/misc/debug_connect.dmi', C.A, null, TURF_LAYER)
|
||||||
|
current_zone_images += image('icons/misc/debug_connect.dmi', C.B, null, TURF_LAYER)
|
||||||
|
|
||||||
|
client << "Connected Zones:"
|
||||||
|
for(var/zone/zone in connected_zones)
|
||||||
|
client << "\ref[zone] [zone] - [connected_zones[zone]] (Connected)"
|
||||||
|
|
||||||
|
for(var/zone/zone in closed_connection_zones)
|
||||||
|
client << "\ref[zone] [zone] - [closed_connection_zones[zone]] (Unconnected)"
|
||||||
|
|
||||||
|
for(var/C in connections)
|
||||||
|
if(!istype(C,/connection))
|
||||||
|
client << "[C] (Not Connection!)"
|
||||||
|
|
||||||
|
if(!client.zone_debug_images)
|
||||||
|
client.zone_debug_images = list()
|
||||||
|
client.zone_debug_images[src] = current_zone_images
|
||||||
|
|
||||||
|
client.images += client.zone_debug_images[src]
|
||||||
|
|
||||||
|
else
|
||||||
|
dbg_output = 0
|
||||||
|
|
||||||
|
client.images -= client.zone_debug_images[src]
|
||||||
|
client.zone_debug_images.Remove(src)
|
||||||
|
|
||||||
|
if(air_master)
|
||||||
|
for(var/zone/Z in air_master.zones)
|
||||||
|
if(Z.air == air && Z != src)
|
||||||
|
var/turf/zloc = pick(Z.contents)
|
||||||
|
client << "\red Illegal air datum shared by: [zloc.loc.name]"*/
|
||||||
|
|
||||||
|
|
||||||
|
/*client/proc/TestZASRebuild()
|
||||||
|
set category = "Debug"
|
||||||
|
// var/turf/turf = get_turf(mob)
|
||||||
|
var/zone/current_zone = mob.loc:zone
|
||||||
|
if(!current_zone)
|
||||||
|
src << "There is no zone there!"
|
||||||
|
return
|
||||||
|
|
||||||
|
var/list/current_adjacents = list()
|
||||||
|
var/list/overlays = list()
|
||||||
|
var/adjacent_id
|
||||||
|
var/lowest_id
|
||||||
|
|
||||||
|
var/list/identical_ids = list()
|
||||||
|
var/list/turfs = current_zone.contents.Copy()
|
||||||
|
var/current_identifier = 1
|
||||||
|
|
||||||
|
for(var/turf/simulated/current in turfs)
|
||||||
|
lowest_id = null
|
||||||
|
current_adjacents = list()
|
||||||
|
|
||||||
|
for(var/direction in cardinal)
|
||||||
|
var/turf/simulated/adjacent = get_step(current, direction)
|
||||||
|
if(!current.ZCanPass(adjacent))
|
||||||
|
continue
|
||||||
|
if(turfs.Find(adjacent))
|
||||||
|
current_adjacents += adjacent
|
||||||
|
adjacent_id = turfs[adjacent]
|
||||||
|
|
||||||
|
if(adjacent_id && (!lowest_id || adjacent_id < lowest_id))
|
||||||
|
lowest_id = adjacent_id
|
||||||
|
|
||||||
|
if(!lowest_id)
|
||||||
|
lowest_id = current_identifier++
|
||||||
|
identical_ids += lowest_id
|
||||||
|
overlays += image('icons/misc/debug_rebuild.dmi',, "[lowest_id]")
|
||||||
|
|
||||||
|
for(var/turf/simulated/adjacent in current_adjacents)
|
||||||
|
adjacent_id = turfs[adjacent]
|
||||||
|
if(adjacent_id != lowest_id)
|
||||||
|
if(adjacent_id)
|
||||||
|
adjacent.overlays -= overlays[adjacent_id]
|
||||||
|
identical_ids[adjacent_id] = lowest_id
|
||||||
|
|
||||||
|
turfs[adjacent] = lowest_id
|
||||||
|
adjacent.overlays += overlays[lowest_id]
|
||||||
|
|
||||||
|
sleep(5)
|
||||||
|
|
||||||
|
if(turfs[current])
|
||||||
|
current.overlays -= overlays[turfs[current]]
|
||||||
|
turfs[current] = lowest_id
|
||||||
|
current.overlays += overlays[lowest_id]
|
||||||
|
sleep(5)
|
||||||
|
|
||||||
|
var/list/final_arrangement = list()
|
||||||
|
|
||||||
|
for(var/turf/simulated/current in turfs)
|
||||||
|
current_identifier = identical_ids[turfs[current]]
|
||||||
|
current.overlays -= overlays[turfs[current]]
|
||||||
|
current.overlays += overlays[current_identifier]
|
||||||
|
sleep(5)
|
||||||
|
|
||||||
|
if( current_identifier > final_arrangement.len )
|
||||||
|
final_arrangement.len = current_identifier
|
||||||
|
final_arrangement[current_identifier] = list(current)
|
||||||
|
|
||||||
|
else
|
||||||
|
final_arrangement[current_identifier] += current
|
||||||
|
|
||||||
|
//lazy but fast
|
||||||
|
final_arrangement.Remove(null)
|
||||||
|
|
||||||
|
src << "There are [final_arrangement.len] unique segments."
|
||||||
|
|
||||||
|
for(var/turf/current in turfs)
|
||||||
|
current.overlays -= overlays
|
||||||
|
|
||||||
|
return final_arrangement*/
|
||||||
|
|
||||||
|
/* VG - We rolled our own.
|
||||||
|
client/proc/ZASSettings()
|
||||||
|
set category = "Debug"
|
||||||
|
|
||||||
|
vsc.SetDefault(mob)
|
||||||
|
*/
|
||||||
@@ -38,9 +38,6 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
|
|||||||
|
|
||||||
new /obj/fire(src,1000)
|
new /obj/fire(src,1000)
|
||||||
|
|
||||||
//active_hotspot.just_spawned = (current_cycle < air_master.current_cycle)
|
|
||||||
//remove just_spawned protection if no longer processing this cell
|
|
||||||
|
|
||||||
return igniting
|
return igniting
|
||||||
|
|
||||||
/obj/fire
|
/obj/fire
|
||||||
@@ -78,12 +75,12 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
|
|||||||
|
|
||||||
//since the air is processed in fractions, we need to make sure not to have any minuscle residue or
|
//since the air is processed in fractions, we need to make sure not to have any minuscle residue or
|
||||||
//the amount of moles might get to low for some functions to catch them and thus result in wonky behaviour
|
//the amount of moles might get to low for some functions to catch them and thus result in wonky behaviour
|
||||||
if(air_contents.oxygen < 0.001)
|
if(air_contents.oxygen < 0.1)
|
||||||
air_contents.oxygen = 0
|
air_contents.oxygen = 0
|
||||||
if(air_contents.toxins < 0.001)
|
if(air_contents.toxins < 0.1)
|
||||||
air_contents.toxins = 0
|
air_contents.toxins = 0
|
||||||
if(fuel)
|
if(fuel)
|
||||||
if(fuel.moles < 0.001)
|
if(fuel.moles < 0.1)
|
||||||
air_contents.trace_gases.Remove(fuel)
|
air_contents.trace_gases.Remove(fuel)
|
||||||
|
|
||||||
//check if there is something to combust
|
//check if there is something to combust
|
||||||
@@ -111,7 +108,7 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
|
|||||||
A.fire_act(air_contents, air_contents.temperature, air_contents.return_volume())
|
A.fire_act(air_contents, air_contents.temperature, air_contents.return_volume())
|
||||||
//spread
|
//spread
|
||||||
for(var/direction in cardinal)
|
for(var/direction in cardinal)
|
||||||
if(S.air_check_directions&direction) //Grab all valid bordering tiles
|
if(S.open_directions & direction) //Grab all valid bordering tiles
|
||||||
|
|
||||||
var/turf/simulated/enemy_tile = get_step(S, direction)
|
var/turf/simulated/enemy_tile = get_step(S, direction)
|
||||||
|
|
||||||
@@ -203,7 +200,7 @@ datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, forc
|
|||||||
|
|
||||||
if(liquid)
|
if(liquid)
|
||||||
//Liquid Fuel
|
//Liquid Fuel
|
||||||
if(liquid.amount <= 0)
|
if(liquid.amount <= 0.1)
|
||||||
del liquid
|
del liquid
|
||||||
else
|
else
|
||||||
total_fuel += liquid.amount
|
total_fuel += liquid.amount
|
||||||
@@ -256,34 +253,31 @@ datum/gas_mixture/proc/check_recombustability(obj/effect/decal/cleanable/liquid_
|
|||||||
//this is a copy proc to continue a fire after its been started.
|
//this is a copy proc to continue a fire after its been started.
|
||||||
|
|
||||||
var/datum/gas/volatile_fuel/fuel = locate() in trace_gases
|
var/datum/gas/volatile_fuel/fuel = locate() in trace_gases
|
||||||
var/value = 0
|
|
||||||
|
|
||||||
if(oxygen && (toxins || fuel || liquid))
|
if(oxygen && (toxins || fuel || liquid))
|
||||||
if(liquid)
|
if(liquid)
|
||||||
value = 1
|
return 1
|
||||||
else if (toxins && !value)
|
if(toxins >= 0.1)
|
||||||
value = 1
|
return 1
|
||||||
else if(fuel && !value)
|
if(fuel && fuel.moles >= 0.1)
|
||||||
value = 1
|
return 1
|
||||||
|
|
||||||
return value
|
return 0
|
||||||
|
|
||||||
datum/gas_mixture/proc/check_combustability(obj/effect/decal/cleanable/liquid_fuel/liquid)
|
datum/gas_mixture/proc/check_combustability(obj/effect/decal/cleanable/liquid_fuel/liquid)
|
||||||
//this check comes up very often and is thus centralized here to ease adding stuff
|
//this check comes up very often and is thus centralized here to ease adding stuff
|
||||||
|
|
||||||
var/datum/gas/volatile_fuel/fuel = locate() in trace_gases
|
var/datum/gas/volatile_fuel/fuel = locate() in trace_gases
|
||||||
var/value = 0
|
|
||||||
|
|
||||||
if(oxygen && (toxins || fuel || liquid))
|
if(oxygen && (toxins || fuel || liquid))
|
||||||
if(liquid)
|
if(liquid)
|
||||||
value = 1
|
return 1
|
||||||
else if (toxins >= 0.7 && !value)
|
if (toxins >= 0.1)
|
||||||
value = 1
|
return 1
|
||||||
else if(fuel && !value)
|
if(fuel && fuel.moles >= 0.1)
|
||||||
if(fuel.moles >= 1.4)
|
return 1
|
||||||
value = 1
|
|
||||||
|
|
||||||
return value
|
return 0
|
||||||
|
|
||||||
datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fuel/liquid)
|
datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fuel/liquid)
|
||||||
//Calculates the firelevel based on one equation instead of having to do this multiple times in different areas.
|
//Calculates the firelevel based on one equation instead of having to do this multiple times in different areas.
|
||||||
@@ -316,24 +310,23 @@ datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fue
|
|||||||
return max( 0, firelevel)
|
return max( 0, firelevel)
|
||||||
|
|
||||||
|
|
||||||
/mob/living/carbon/human/proc/FireBurn(var/firelevel, var/last_temperature, var/pressure)
|
/mob/living/proc/FireBurn(var/firelevel, var/last_temperature, var/pressure)
|
||||||
// mostly using the old proc from Sky until I can think of something better
|
var/mx = 5 * firelevel/zas_settings.Get(/datum/ZAS_Setting/fire_firelevel_multiplier) * min(pressure / ONE_ATMOSPHERE, 1)
|
||||||
|
apply_damage(2.5*mx, BURN)
|
||||||
|
|
||||||
|
|
||||||
|
/mob/living/carbon/human/FireBurn(var/firelevel, var/last_temperature, var/pressure)
|
||||||
//Burns mobs due to fire. Respects heat transfer coefficients on various body parts.
|
//Burns mobs due to fire. Respects heat transfer coefficients on various body parts.
|
||||||
//Due to TG reworking how fireprotection works, this is kinda less meaningful.
|
//Due to TG reworking how fireprotection works, this is kinda less meaningful.
|
||||||
|
|
||||||
var
|
var/head_exposure = 1
|
||||||
head_exposure = 1
|
var/chest_exposure = 1
|
||||||
chest_exposure = 1
|
var/groin_exposure = 1
|
||||||
groin_exposure = 1
|
var/legs_exposure = 1
|
||||||
legs_exposure = 1
|
var/arms_exposure = 1
|
||||||
arms_exposure = 1
|
|
||||||
|
|
||||||
//determine the multiplier
|
|
||||||
//minimize this for low-pressure enviroments
|
|
||||||
var/mx = 5 * firelevel/zas_settings.Get(/datum/ZAS_Setting/fire_firelevel_multiplier) * min(pressure / ONE_ATMOSPHERE, 1)
|
|
||||||
|
|
||||||
//Get heat transfer coefficients for clothing.
|
//Get heat transfer coefficients for clothing.
|
||||||
//skytodo: kill anyone who breaks things then orders me to fix them
|
|
||||||
for(var/obj/item/clothing/C in src)
|
for(var/obj/item/clothing/C in src)
|
||||||
if(l_hand == C || r_hand == C)
|
if(l_hand == C || r_hand == C)
|
||||||
continue
|
continue
|
||||||
@@ -349,6 +342,8 @@ datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fue
|
|||||||
legs_exposure = 0
|
legs_exposure = 0
|
||||||
if(C.body_parts_covered & ARMS)
|
if(C.body_parts_covered & ARMS)
|
||||||
arms_exposure = 0
|
arms_exposure = 0
|
||||||
|
//minimize this for low-pressure enviroments
|
||||||
|
var/mx = 5 * firelevel/zas_settings.Get(/datum/ZAS_Setting/fire_firelevel_multiplier) * min(pressure / ONE_ATMOSPHERE, 1)
|
||||||
|
|
||||||
//Always check these damage procs first if fire damage isn't working. They're probably what's wrong.
|
//Always check these damage procs first if fire damage isn't working. They're probably what's wrong.
|
||||||
|
|
||||||
@@ -359,5 +354,3 @@ datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fue
|
|||||||
apply_damage(0.6*mx*legs_exposure, BURN, "r_leg", 0, 0, "Fire")
|
apply_damage(0.6*mx*legs_exposure, BURN, "r_leg", 0, 0, "Fire")
|
||||||
apply_damage(0.4*mx*arms_exposure, BURN, "l_arm", 0, 0, "Fire")
|
apply_damage(0.4*mx*arms_exposure, BURN, "l_arm", 0, 0, "Fire")
|
||||||
apply_damage(0.4*mx*arms_exposure, BURN, "r_arm", 0, 0, "Fire")
|
apply_damage(0.4*mx*arms_exposure, BURN, "r_arm", 0, 0, "Fire")
|
||||||
|
|
||||||
//flash_pain()
|
|
||||||
|
|||||||
241
code/ZAS/Turf.dm
Normal file
241
code/ZAS/Turf.dm
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
/turf/simulated/var/zone/zone
|
||||||
|
/turf/simulated/var/open_directions
|
||||||
|
/turf/simulated/var/gas_graphic
|
||||||
|
|
||||||
|
/turf/var/needs_air_update = 0
|
||||||
|
/turf/var/datum/gas_mixture/air
|
||||||
|
|
||||||
|
/turf/simulated/proc/set_graphic(new_graphic)
|
||||||
|
if(isnum(new_graphic))
|
||||||
|
if(new_graphic == 1) new_graphic = plmaster
|
||||||
|
else if(new_graphic == 2) new_graphic = slmaster
|
||||||
|
if(gas_graphic) overlays -= gas_graphic
|
||||||
|
if(new_graphic) overlays += new_graphic
|
||||||
|
gas_graphic = new_graphic
|
||||||
|
|
||||||
|
/turf/proc/update_air_properties()
|
||||||
|
var/block = c_airblock(src)
|
||||||
|
if(block & AIR_BLOCKED)
|
||||||
|
//dbg(blocked)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
#ifdef ZLEVELS
|
||||||
|
for(var/d = 1, d < 64, d *= 2)
|
||||||
|
#else
|
||||||
|
for(var/d = 1, d < 16, d *= 2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var/turf/unsim = get_step(src, d)
|
||||||
|
block = unsim.c_airblock(src)
|
||||||
|
|
||||||
|
if(block & AIR_BLOCKED)
|
||||||
|
//unsim.dbg(air_blocked, turn(180,d))
|
||||||
|
continue
|
||||||
|
|
||||||
|
var/r_block = c_airblock(unsim)
|
||||||
|
|
||||||
|
if(r_block & AIR_BLOCKED)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if(istype(unsim, /turf/simulated))
|
||||||
|
|
||||||
|
var/turf/simulated/sim = unsim
|
||||||
|
if(air_master.has_valid_zone(sim))
|
||||||
|
|
||||||
|
air_master.connect(sim, src)
|
||||||
|
|
||||||
|
/turf/simulated/update_air_properties()
|
||||||
|
if(zone && zone.invalid)
|
||||||
|
c_copy_air()
|
||||||
|
zone = null //Easier than iterating through the list at the zone.
|
||||||
|
|
||||||
|
var/s_block = c_airblock(src)
|
||||||
|
if(s_block & AIR_BLOCKED)
|
||||||
|
#ifdef ZASDBG
|
||||||
|
if(verbose) world << "Self-blocked."
|
||||||
|
//dbg(blocked)
|
||||||
|
#endif
|
||||||
|
if(zone)
|
||||||
|
var/zone/z = zone
|
||||||
|
if(locate(/obj/machinery/door/airlock) in src) //Hacky, but prevents normal airlocks from rebuilding zones all the time
|
||||||
|
z.remove(src)
|
||||||
|
else
|
||||||
|
z.rebuild()
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
var/previously_open = open_directions
|
||||||
|
open_directions = 0
|
||||||
|
|
||||||
|
var/list/postponed
|
||||||
|
#ifdef ZLEVELS
|
||||||
|
for(var/d = 1, d < 64, d *= 2)
|
||||||
|
#else
|
||||||
|
for(var/d = 1, d < 16, d *= 2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var/turf/unsim = get_step(src, d)
|
||||||
|
var/block = unsim.c_airblock(src)
|
||||||
|
if(block & AIR_BLOCKED)
|
||||||
|
|
||||||
|
#ifdef ZASDBG
|
||||||
|
if(verbose) world << "[d] is blocked."
|
||||||
|
//unsim.dbg(air_blocked, turn(180,d))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
var/r_block = c_airblock(unsim)
|
||||||
|
if(r_block & AIR_BLOCKED)
|
||||||
|
|
||||||
|
#ifdef ZASDBG
|
||||||
|
if(verbose) world << "[d] is blocked."
|
||||||
|
//dbg(air_blocked, d)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Check that our zone hasn't been cut off recently.
|
||||||
|
//This happens when windows move or are constructed. We need to rebuild.
|
||||||
|
if((previously_open & d) && istype(unsim, /turf/simulated))
|
||||||
|
var/turf/simulated/sim = unsim
|
||||||
|
if(sim.zone == zone)
|
||||||
|
zone.rebuild()
|
||||||
|
return
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
open_directions |= d
|
||||||
|
|
||||||
|
if(istype(unsim, /turf/simulated))
|
||||||
|
|
||||||
|
var/turf/simulated/sim = unsim
|
||||||
|
if(air_master.has_valid_zone(sim))
|
||||||
|
|
||||||
|
//Might have assigned a zone, since this happens for each direction.
|
||||||
|
if(!zone)
|
||||||
|
|
||||||
|
//if((block & ZONE_BLOCKED) || (r_block & ZONE_BLOCKED && !(s_block & ZONE_BLOCKED)))
|
||||||
|
if(((block & ZONE_BLOCKED) && !(r_block & ZONE_BLOCKED)) || (r_block & ZONE_BLOCKED && !(s_block & ZONE_BLOCKED)))
|
||||||
|
#ifdef ZASDBG
|
||||||
|
if(verbose) world << "[d] is zone blocked."
|
||||||
|
//dbg(zone_blocked, d)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Postpone this tile rather than exit, since a connection can still be made.
|
||||||
|
if(!postponed) postponed = list()
|
||||||
|
postponed.Add(sim)
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
sim.zone.add(src)
|
||||||
|
|
||||||
|
#ifdef ZASDBG
|
||||||
|
dbg(assigned)
|
||||||
|
if(verbose) world << "Added to [zone]"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
else if(sim.zone != zone)
|
||||||
|
|
||||||
|
#ifdef ZASDBG
|
||||||
|
if(verbose) world << "Connecting to [sim.zone]"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
air_master.connect(src, sim)
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef ZASDBG
|
||||||
|
else if(verbose) world << "[d] has same zone."
|
||||||
|
|
||||||
|
else if(verbose) world << "[d] has invalid zone."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
//Postponing connections to tiles until a zone is assured.
|
||||||
|
if(!postponed) postponed = list()
|
||||||
|
postponed.Add(unsim)
|
||||||
|
|
||||||
|
if(!air_master.has_valid_zone(src)) //Still no zone, make a new one.
|
||||||
|
var/zone/newzone = new/zone()
|
||||||
|
newzone.add(src)
|
||||||
|
|
||||||
|
#ifdef ZASDBG
|
||||||
|
dbg(created)
|
||||||
|
|
||||||
|
ASSERT(zone)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//At this point, a zone should have happened. If it hasn't, don't add more checks, fix the bug.
|
||||||
|
|
||||||
|
for(var/turf/T in postponed)
|
||||||
|
air_master.connect(src, T)
|
||||||
|
|
||||||
|
/turf/proc/post_update_air_properties()
|
||||||
|
if(connections) connections.update_all()
|
||||||
|
|
||||||
|
/turf/assume_air(datum/gas_mixture/giver) //use this for machines to adjust air
|
||||||
|
del(giver)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
/turf/return_air()
|
||||||
|
//Create gas mixture to hold data for passing
|
||||||
|
var/datum/gas_mixture/GM = new
|
||||||
|
|
||||||
|
GM.oxygen = oxygen
|
||||||
|
GM.carbon_dioxide = carbon_dioxide
|
||||||
|
GM.nitrogen = nitrogen
|
||||||
|
GM.toxins = toxins
|
||||||
|
|
||||||
|
GM.temperature = temperature
|
||||||
|
GM.update_values()
|
||||||
|
|
||||||
|
return GM
|
||||||
|
|
||||||
|
/turf/remove_air(amount as num)
|
||||||
|
var/datum/gas_mixture/GM = new
|
||||||
|
|
||||||
|
var/sum = oxygen + carbon_dioxide + nitrogen + toxins
|
||||||
|
if(sum>0)
|
||||||
|
GM.oxygen = (oxygen/sum)*amount
|
||||||
|
GM.carbon_dioxide = (carbon_dioxide/sum)*amount
|
||||||
|
GM.nitrogen = (nitrogen/sum)*amount
|
||||||
|
GM.toxins = (toxins/sum)*amount
|
||||||
|
|
||||||
|
GM.temperature = temperature
|
||||||
|
GM.update_values()
|
||||||
|
|
||||||
|
return GM
|
||||||
|
|
||||||
|
/turf/simulated/assume_air(datum/gas_mixture/giver)
|
||||||
|
var/datum/gas_mixture/my_air = return_air()
|
||||||
|
my_air.merge(giver)
|
||||||
|
|
||||||
|
/turf/simulated/remove_air(amount as num)
|
||||||
|
var/datum/gas_mixture/my_air = return_air()
|
||||||
|
return my_air.remove(amount)
|
||||||
|
|
||||||
|
/turf/simulated/return_air()
|
||||||
|
if(zone)
|
||||||
|
if(!zone.invalid)
|
||||||
|
air_master.mark_zone_update(zone)
|
||||||
|
return zone.air
|
||||||
|
else
|
||||||
|
if(!air)
|
||||||
|
make_air()
|
||||||
|
c_copy_air()
|
||||||
|
return air
|
||||||
|
else
|
||||||
|
if(!air)
|
||||||
|
make_air()
|
||||||
|
return air
|
||||||
|
|
||||||
|
/turf/proc/make_air()
|
||||||
|
air = new/datum/gas_mixture
|
||||||
|
air.temperature = temperature
|
||||||
|
air.adjust(oxygen, carbon_dioxide, nitrogen, toxins)
|
||||||
|
air.group_multiplier = 1
|
||||||
|
air.volume = CELL_VOLUME
|
||||||
|
|
||||||
|
/turf/simulated/proc/c_copy_air()
|
||||||
|
if(!air) air = new/datum/gas_mixture
|
||||||
|
air.copy_from(zone.air)
|
||||||
|
air.group_multiplier = 1
|
||||||
152
code/ZAS/Zone.dm
Normal file
152
code/ZAS/Zone.dm
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Overview:
|
||||||
|
Each zone is a self-contained area where gas values would be the same if tile-based equalization were run indefinitely.
|
||||||
|
If you're unfamiliar with ZAS, FEA's air groups would have similar functionality if they didn't break in a stiff breeze.
|
||||||
|
|
||||||
|
Class Vars:
|
||||||
|
name - A name of the format "Zone [#]", used for debugging.
|
||||||
|
invalid - True if the zone has been erased and is no longer eligible for processing.
|
||||||
|
needs_update - True if the zone has been added to the update list.
|
||||||
|
edges - A list of edges that connect to this zone.
|
||||||
|
air - The gas mixture that any turfs in this zone will return. Values are per-tile with a group multiplier.
|
||||||
|
|
||||||
|
Class Procs:
|
||||||
|
add(turf/simulated/T)
|
||||||
|
Adds a turf to the contents, sets its zone and merges its air.
|
||||||
|
|
||||||
|
remove(turf/simulated/T)
|
||||||
|
Removes a turf, sets its zone to null and erases any gas graphics.
|
||||||
|
Invalidates the zone if it has no more tiles.
|
||||||
|
|
||||||
|
c_merge(zone/into)
|
||||||
|
Invalidates this zone and adds all its former contents to into.
|
||||||
|
|
||||||
|
c_invalidate()
|
||||||
|
Marks this zone as invalid and removes it from processing.
|
||||||
|
|
||||||
|
rebuild()
|
||||||
|
Invalidates the zone and marks all its former tiles for updates.
|
||||||
|
|
||||||
|
add_tile_air(turf/simulated/T)
|
||||||
|
Adds the air contained in T.air to the zone's air supply. Called when adding a turf.
|
||||||
|
|
||||||
|
tick()
|
||||||
|
Called only when the gas content is changed. Archives values and changes gas graphics.
|
||||||
|
|
||||||
|
dbg_data(mob/M)
|
||||||
|
Sends M a printout of important figures for the zone.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/zone
|
||||||
|
var/name
|
||||||
|
var/invalid = 0
|
||||||
|
var/list/contents = list()
|
||||||
|
var/needs_update = 0
|
||||||
|
var/list/edges = list()
|
||||||
|
var/datum/gas_mixture/air = new
|
||||||
|
|
||||||
|
/zone/New()
|
||||||
|
air_master.add_zone(src)
|
||||||
|
air.temperature = TCMB
|
||||||
|
air.group_multiplier = 1
|
||||||
|
air.volume = CELL_VOLUME
|
||||||
|
|
||||||
|
/zone/proc/add(turf/simulated/T)
|
||||||
|
#ifdef ZASDBG
|
||||||
|
ASSERT(!invalid)
|
||||||
|
ASSERT(istype(T))
|
||||||
|
ASSERT(!air_master.has_valid_zone(T))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var/datum/gas_mixture/turf_air = T.return_air()
|
||||||
|
add_tile_air(turf_air)
|
||||||
|
T.zone = src
|
||||||
|
contents.Add(T)
|
||||||
|
T.set_graphic(air.graphics)
|
||||||
|
|
||||||
|
/zone/proc/remove(turf/simulated/T)
|
||||||
|
#ifdef ZASDBG
|
||||||
|
ASSERT(!invalid)
|
||||||
|
ASSERT(istype(T))
|
||||||
|
ASSERT(T.zone == src)
|
||||||
|
soft_assert(T in contents, "Lists are weird broseph")
|
||||||
|
#endif
|
||||||
|
contents.Remove(T)
|
||||||
|
T.zone = null
|
||||||
|
T.set_graphic(0)
|
||||||
|
if(contents.len)
|
||||||
|
air.group_multiplier = contents.len
|
||||||
|
else
|
||||||
|
c_invalidate()
|
||||||
|
|
||||||
|
/zone/proc/c_merge(zone/into)
|
||||||
|
#ifdef ZASDBG
|
||||||
|
ASSERT(!invalid)
|
||||||
|
ASSERT(istype(into))
|
||||||
|
ASSERT(into != src)
|
||||||
|
ASSERT(!into.invalid)
|
||||||
|
#endif
|
||||||
|
c_invalidate()
|
||||||
|
for(var/turf/simulated/T in contents)
|
||||||
|
into.add(T)
|
||||||
|
#ifdef ZASDBG
|
||||||
|
T.dbg(merged)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/zone/proc/c_invalidate()
|
||||||
|
invalid = 1
|
||||||
|
air_master.remove_zone(src)
|
||||||
|
#ifdef ZASDBG
|
||||||
|
for(var/turf/simulated/T in contents)
|
||||||
|
T.dbg(invalid_zone)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/zone/proc/rebuild()
|
||||||
|
if(invalid) return //Short circuit for explosions where rebuild is called many times over.
|
||||||
|
c_invalidate()
|
||||||
|
for(var/turf/simulated/T in contents)
|
||||||
|
//T.dbg(invalid_zone)
|
||||||
|
T.needs_air_update = 0 //Reset the marker so that it will be added to the list.
|
||||||
|
air_master.mark_for_update(T)
|
||||||
|
|
||||||
|
/zone/proc/add_tile_air(datum/gas_mixture/tile_air)
|
||||||
|
//air.volume += CELL_VOLUME
|
||||||
|
air.group_multiplier = 1
|
||||||
|
air.multiply(contents.len)
|
||||||
|
air.merge(tile_air)
|
||||||
|
air.divide(contents.len+1)
|
||||||
|
air.group_multiplier = contents.len+1
|
||||||
|
|
||||||
|
/zone/proc/tick()
|
||||||
|
air.archive()
|
||||||
|
if(air.check_tile_graphic())
|
||||||
|
for(var/turf/simulated/T in contents)
|
||||||
|
T.set_graphic(air.graphics)
|
||||||
|
|
||||||
|
/zone/proc/dbg_data(mob/M)
|
||||||
|
M << name
|
||||||
|
M << "O2: [air.oxygen] N2: [air.nitrogen] CO2: [air.carbon_dioxide] P: [air.toxins]"
|
||||||
|
M << "P: [air.return_pressure()] kPa V: [air.volume]L T: [air.temperature]<5D>K ([air.temperature - T0C]<5D>C)"
|
||||||
|
M << "O2 per N2: [(air.nitrogen ? air.oxygen/air.nitrogen : "N/A")] Moles: [air.total_moles]"
|
||||||
|
M << "Simulated: [contents.len] ([air.group_multiplier])"
|
||||||
|
//M << "Unsimulated: [unsimulated_contents.len]"
|
||||||
|
//M << "Edges: [edges.len]"
|
||||||
|
if(invalid) M << "Invalid!"
|
||||||
|
var/zone_edges = 0
|
||||||
|
var/space_edges = 0
|
||||||
|
var/space_coefficient = 0
|
||||||
|
for(var/connection_edge/E in edges)
|
||||||
|
if(E.type == /connection_edge/zone) zone_edges++
|
||||||
|
else
|
||||||
|
space_edges++
|
||||||
|
space_coefficient += E.coefficient
|
||||||
|
M << "[E:air:return_pressure()]kPa"
|
||||||
|
|
||||||
|
M << "Zone Edges: [zone_edges]"
|
||||||
|
M << "Space Edges: [space_edges] ([space_coefficient] connections)"
|
||||||
|
|
||||||
|
//for(var/turf/T in unsimulated_contents)
|
||||||
|
// M << "[T] at ([T.x],[T.y])"
|
||||||
35
code/ZAS/_docs.dm
Normal file
35
code/ZAS/_docs.dm
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Zone Air System:
|
||||||
|
|
||||||
|
This air system divides the station into impermeable areas called zones.
|
||||||
|
When something happens, i.e. a door opening or a wall being taken down,
|
||||||
|
zones equalize and eventually merge. Making an airtight area closes the connection again.
|
||||||
|
|
||||||
|
Control Flow:
|
||||||
|
Every air tick:
|
||||||
|
Marked turfs are updated with update_air_properties(), followed by post_update_air_properties().
|
||||||
|
Edges, including those generated by connections in the previous step, are processed. This is where gas is exchanged.
|
||||||
|
Fire is processed.
|
||||||
|
Marked zones have their air archived.
|
||||||
|
|
||||||
|
Important Functions:
|
||||||
|
|
||||||
|
air_master.mark_for_update(turf)
|
||||||
|
When stuff happens, call this. It works on everything. You basically don't need to worry about any other
|
||||||
|
functions besides CanPass().
|
||||||
|
|
||||||
|
Notes for people who used ZAS before:
|
||||||
|
There is no connected_zones anymore.
|
||||||
|
To get the zones that are connected to a zone, use this loop:
|
||||||
|
for(var/connection_edge/zone/edge in zone.edges)
|
||||||
|
var/zone/connected_zone = edge.get_connected_zone(zone)
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
//#define ZASDBG
|
||||||
|
//#define ZLEVELS
|
||||||
|
|
||||||
|
#define AIR_BLOCKED 1
|
||||||
|
#define ZONE_BLOCKED 2
|
||||||
|
#define BLOCKED 3
|
||||||
1138
code/ZAS/_gas_mixture.dm
Normal file
1138
code/ZAS/_gas_mixture.dm
Normal file
File diff suppressed because it is too large
Load Diff
@@ -31,10 +31,13 @@ datum/controller/game_controller
|
|||||||
var/total_cost = 0
|
var/total_cost = 0
|
||||||
|
|
||||||
var/last_thing_processed
|
var/last_thing_processed
|
||||||
|
var/mob/list/expensive_mobs = list()
|
||||||
|
var/rebuild_active_areas = 0
|
||||||
|
|
||||||
datum/controller/game_controller/New()
|
datum/controller/game_controller/New()
|
||||||
//There can be only one master_controller. Out with the old and in with the new.
|
//There can be only one master_controller. Out with the old and in with the new.
|
||||||
if(master_controller != src)
|
if(master_controller != src)
|
||||||
|
log_debug("Rebuilding Master Controller")
|
||||||
if(istype(master_controller))
|
if(istype(master_controller))
|
||||||
Recover()
|
Recover()
|
||||||
del(master_controller)
|
del(master_controller)
|
||||||
@@ -53,15 +56,15 @@ datum/controller/game_controller/New()
|
|||||||
datum/controller/game_controller/proc/setup()
|
datum/controller/game_controller/proc/setup()
|
||||||
world.tick_lag = config.Ticklag
|
world.tick_lag = config.Ticklag
|
||||||
|
|
||||||
|
// notify the other process that we started up
|
||||||
socket_talk = new /datum/socket_talk()
|
socket_talk = new /datum/socket_talk()
|
||||||
// notify the other process that we started up
|
|
||||||
socket_talk.send_raw("type=startup")
|
socket_talk.send_raw("type=startup")
|
||||||
|
|
||||||
createRandomZlevel()
|
createRandomZlevel()
|
||||||
|
|
||||||
if(!air_master)
|
if(!air_master)
|
||||||
air_master = new /datum/controller/air_system()
|
air_master = new /datum/controller/air_system()
|
||||||
air_master.setup()
|
air_master.Setup()
|
||||||
|
|
||||||
if(!ticker)
|
if(!ticker)
|
||||||
ticker = new /datum/controller/gameticker()
|
ticker = new /datum/controller/gameticker()
|
||||||
@@ -78,7 +81,8 @@ datum/controller/game_controller/proc/setup()
|
|||||||
for(var/i=0, i<max_secret_rooms, i++)
|
for(var/i=0, i<max_secret_rooms, i++)
|
||||||
make_mining_asteroid_secret()
|
make_mining_asteroid_secret()
|
||||||
|
|
||||||
//if(config.socket_talk) spawn keepalive()
|
//if(config.socket_talk)
|
||||||
|
// keepalive()
|
||||||
|
|
||||||
spawn(0)
|
spawn(0)
|
||||||
if(ticker)
|
if(ticker)
|
||||||
@@ -136,14 +140,8 @@ datum/controller/game_controller/proc/process()
|
|||||||
if(!air_processing_killed)
|
if(!air_processing_killed)
|
||||||
timer = world.timeofday
|
timer = world.timeofday
|
||||||
last_thing_processed = air_master.type
|
last_thing_processed = air_master.type
|
||||||
//air_master.tick()
|
|
||||||
//air_cost = (world.timeofday - timer) / 10 // this might make atmos slower
|
|
||||||
// 1. atmos won't process if the game is generally lagged out(no deadlocks)
|
|
||||||
// 2. if the server frequently crashes during atmos processing we will knowif(!kill_air)
|
|
||||||
//src.set_debug_state("Air Master")
|
|
||||||
|
|
||||||
air_master.current_cycle++
|
if(!air_master.Tick()) //Runtimed.
|
||||||
if(!air_master.tick()) //Runtimed.
|
|
||||||
air_master.failed_ticks++
|
air_master.failed_ticks++
|
||||||
if(air_master.failed_ticks > 5)
|
if(air_master.failed_ticks > 5)
|
||||||
world << "<font color='red'><b>RUNTIMES IN ATMOS TICKER. Killing air simulation!</font></b>"
|
world << "<font color='red'><b>RUNTIMES IN ATMOS TICKER. Killing air simulation!</font></b>"
|
||||||
@@ -152,7 +150,8 @@ datum/controller/game_controller/proc/process()
|
|||||||
log_admin("ZASALERT: unable run zone/process() -- [air_master.tick_progress]")
|
log_admin("ZASALERT: unable run zone/process() -- [air_master.tick_progress]")
|
||||||
air_processing_killed = 1
|
air_processing_killed = 1
|
||||||
air_master.failed_ticks = 0
|
air_master.failed_ticks = 0
|
||||||
air_cost = (world.timeofday - timer) / 10
|
|
||||||
|
air_cost = (world.timeofday - timer) / 10
|
||||||
|
|
||||||
sleep(breather_ticks)
|
sleep(breather_ticks)
|
||||||
|
|
||||||
@@ -241,14 +240,20 @@ datum/controller/game_controller/proc/process()
|
|||||||
else
|
else
|
||||||
sleep(10)
|
sleep(10)
|
||||||
|
|
||||||
/datum/controller/game_controller/proc/processMobs()
|
datum/controller/game_controller/proc/processMobs()
|
||||||
for (var/mob/Mob in mob_list)
|
var/i = 1
|
||||||
if (Mob)
|
expensive_mobs.Cut()
|
||||||
last_thing_processed = Mob.type
|
while(i<=mob_list.len)
|
||||||
Mob.Life()
|
var/mob/M = mob_list[i]
|
||||||
|
if(M)
|
||||||
|
var/clock = world.timeofday
|
||||||
|
last_thing_processed = M.type
|
||||||
|
M.Life()
|
||||||
|
if((world.timeofday - clock) > 1)
|
||||||
|
expensive_mobs += M
|
||||||
|
i++
|
||||||
continue
|
continue
|
||||||
|
mob_list.Cut(i,i+1)
|
||||||
mob_list = mob_list - Mob
|
|
||||||
|
|
||||||
/datum/controller/game_controller/proc/processDiseases()
|
/datum/controller/game_controller/proc/processDiseases()
|
||||||
for (var/datum/disease/Disease in active_diseases)
|
for (var/datum/disease/Disease in active_diseases)
|
||||||
|
|||||||
48
code/game/gamemodes/endgame/endgame.dm
Normal file
48
code/game/gamemodes/endgame/endgame.dm
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/**********************
|
||||||
|
* ENDGAME STUFF
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
// Universal State
|
||||||
|
// Handles stuff like space icon_state, constants, etc.
|
||||||
|
// Essentially a policy manager. Once shit hits the fan, this changes its policies.
|
||||||
|
// Called by master controller.
|
||||||
|
|
||||||
|
var/global/datum/universal_state/universe = new
|
||||||
|
|
||||||
|
// Default shit.
|
||||||
|
/datum/universal_state
|
||||||
|
// Just for reference, for now.
|
||||||
|
// Might eventually add an observatory job.
|
||||||
|
var/name = "Normal"
|
||||||
|
var/desc = "Nothing seems awry."
|
||||||
|
|
||||||
|
// Sets world.turf, replaces all turfs of type /turf/space.
|
||||||
|
var/space_type = /turf/space
|
||||||
|
|
||||||
|
// Replaces all turfs of type /turf/space/transit
|
||||||
|
var/transit_space_type = /turf/space/transit
|
||||||
|
|
||||||
|
// Chance of a floor or wall getting damaged [0-100]
|
||||||
|
// Simulates stuff getting broken due to molecular bonds decaying.
|
||||||
|
var/decay_rate = 0
|
||||||
|
|
||||||
|
var/escape = 0 // NO ESCAPE
|
||||||
|
|
||||||
|
// Actually decay the turf.
|
||||||
|
/datum/universal_state/proc/DecayTurf(var/turf/T)
|
||||||
|
if(istype(T,/turf/simulated/wall))
|
||||||
|
var/turf/simulated/wall/W=T
|
||||||
|
W.melt()
|
||||||
|
return
|
||||||
|
if(istype(T,/turf/simulated/floor))
|
||||||
|
var/turf/simulated/floor/F=T
|
||||||
|
// Burnt?
|
||||||
|
if(!F.burnt)
|
||||||
|
F.burn_tile()
|
||||||
|
else
|
||||||
|
F.ReplaceWithLattice()
|
||||||
|
return
|
||||||
|
|
||||||
|
// Apply changes to a turf
|
||||||
|
/datum/universal_state/proc/FilterTurf(var/turf/T)
|
||||||
|
// Does nothing by default
|
||||||
@@ -14,9 +14,9 @@
|
|||||||
var/minp=16777216;
|
var/minp=16777216;
|
||||||
var/maxp=0;
|
var/maxp=0;
|
||||||
for(var/dir in cardinal)
|
for(var/dir in cardinal)
|
||||||
var/turf/T=get_turf(get_step(loc,dir))
|
var/turf/simulated/T=get_turf(get_step(loc,dir))
|
||||||
var/cp=0
|
var/cp=0
|
||||||
if(T && istype(T,/turf/simulated) && T.zone)
|
if(T && istype(T) && T.zone)
|
||||||
var/datum/gas_mixture/environment = T.return_air()
|
var/datum/gas_mixture/environment = T.return_air()
|
||||||
cp = environment.return_pressure()
|
cp = environment.return_pressure()
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -360,7 +360,7 @@
|
|||||||
O.layer = 5
|
O.layer = 5
|
||||||
O.mouse_opacity = 0
|
O.mouse_opacity = 0
|
||||||
|
|
||||||
/turf/simulated/wall/proc/thermitemelt(mob/user as mob)
|
/turf/simulated/wall/proc/thermitemelt(var/mob/user)
|
||||||
if(mineral == "diamond")
|
if(mineral == "diamond")
|
||||||
return
|
return
|
||||||
var/obj/effect/overlay/O = new/obj/effect/overlay( src )
|
var/obj/effect/overlay/O = new/obj/effect/overlay( src )
|
||||||
@@ -394,6 +394,21 @@
|
|||||||
// F.sd_LumReset() //TODO: ~Carn
|
// F.sd_LumReset() //TODO: ~Carn
|
||||||
return
|
return
|
||||||
|
|
||||||
|
// Generic wall melting proc.
|
||||||
|
/turf/simulated/wall/proc/melt(var/mob/user)
|
||||||
|
if(mineral == "diamond")
|
||||||
|
return
|
||||||
|
|
||||||
|
src.ChangeTurf(/turf/simulated/floor/plating)
|
||||||
|
|
||||||
|
var/turf/simulated/floor/F = src
|
||||||
|
if(!F)
|
||||||
|
return
|
||||||
|
F.burn_tile()
|
||||||
|
F.icon_state = "wall_thermite"
|
||||||
|
// F.sd_LumReset() //TODO: ~Carn
|
||||||
|
return
|
||||||
|
|
||||||
/turf/simulated/wall/meteorhit(obj/M as obj)
|
/turf/simulated/wall/meteorhit(obj/M as obj)
|
||||||
if (prob(15) && !rotting)
|
if (prob(15) && !rotting)
|
||||||
dismantle_wall()
|
dismantle_wall()
|
||||||
|
|||||||
@@ -241,51 +241,75 @@
|
|||||||
if (!N)
|
if (!N)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
#ifdef ENABLE_TRI_LEVEL
|
||||||
|
// Fuck this, for now - N3X
|
||||||
|
///// Z-Level Stuff ///// This makes sure that turfs are not changed to space when one side is part of a zone
|
||||||
|
if(N == /turf/space)
|
||||||
|
var/turf/controller = locate(1, 1, src.z)
|
||||||
|
for(var/obj/effect/landmark/zcontroller/c in controller)
|
||||||
|
if(c.down)
|
||||||
|
var/turf/below = locate(src.x, src.y, c.down_target)
|
||||||
|
if((air_master.has_valid_zone(below) || air_master.has_valid_zone(src)) && !istype(below, /turf/space)) // dont make open space into space, its pointless and makes people drop out of the station
|
||||||
|
var/turf/W = src.ChangeTurf(/turf/simulated/floor/open)
|
||||||
|
var/list/temp = list()
|
||||||
|
temp += W
|
||||||
|
c.add(temp,3,1) // report the new open space to the zcontroller
|
||||||
|
return W
|
||||||
|
///// Z-Level Stuff
|
||||||
|
#endif
|
||||||
|
|
||||||
var/old_lumcount = lighting_lumcount - initial(lighting_lumcount)
|
var/old_lumcount = lighting_lumcount - initial(lighting_lumcount)
|
||||||
|
|
||||||
|
//world << "Replacing [src.type] with [N]"
|
||||||
|
|
||||||
|
if(connections) connections.erase_all()
|
||||||
|
|
||||||
|
if(istype(src,/turf/simulated))
|
||||||
|
//Yeah, we're just going to rebuild the whole thing.
|
||||||
|
//Despite this being called a bunch during explosions,
|
||||||
|
//the zone will only really do heavy lifting once.
|
||||||
|
var/turf/simulated/S = src
|
||||||
|
if(S.zone) S.zone.rebuild()
|
||||||
|
|
||||||
if(ispath(N, /turf/simulated/floor))
|
if(ispath(N, /turf/simulated/floor))
|
||||||
|
//if the old turf had a zone, connect the new turf to it as well - Cael
|
||||||
|
//Adjusted by SkyMarshal 5/10/13 - The air master will handle the addition of the new turf.
|
||||||
|
//if(zone)
|
||||||
|
// zone.RemoveTurf(src)
|
||||||
|
// if(!zone.CheckStatus())
|
||||||
|
// zone.SetStatus(ZONE_ACTIVE)
|
||||||
|
|
||||||
var/turf/simulated/W = new N( locate(src.x, src.y, src.z) )
|
var/turf/simulated/W = new N( locate(src.x, src.y, src.z) )
|
||||||
W.copy_air_from(src)
|
|
||||||
//W.Assimilate_Air()
|
//W.Assimilate_Air()
|
||||||
|
|
||||||
W.lighting_lumcount += old_lumcount
|
W.lighting_lumcount += old_lumcount
|
||||||
if(old_lumcount != W.lighting_lumcount || !accepts_lighting)
|
if(old_lumcount != W.lighting_lumcount)
|
||||||
W.lighting_changed = 1
|
W.lighting_changed = 1
|
||||||
lighting_controller.changed_turfs += W
|
lighting_controller.changed_turfs += W
|
||||||
|
|
||||||
if (istype(W,/turf/simulated/floor))
|
if (istype(W,/turf/simulated/floor))
|
||||||
W.RemoveLattice()
|
W.RemoveLattice()
|
||||||
|
|
||||||
//if the old turf had a zone, connect the new turf to it as well - Cael
|
if(air_master)
|
||||||
if(src.zone)
|
air_master.mark_for_update(src)
|
||||||
src.zone.RemoveTurf(src)
|
|
||||||
W.zone = src.zone
|
|
||||||
W.zone.AddTurf(W)
|
|
||||||
|
|
||||||
for(var/turf/simulated/T in orange(src,1))
|
|
||||||
air_master.tiles_to_update.Add(T)
|
|
||||||
|
|
||||||
W.levelupdate()
|
W.levelupdate()
|
||||||
return W
|
return W
|
||||||
|
|
||||||
else
|
else
|
||||||
/*if(istype(src, /turf/simulated) && src.zone)
|
//if(zone)
|
||||||
src.zone.rebuild = 1*/
|
// zone.RemoveTurf(src)
|
||||||
|
// if(!zone.CheckStatus())
|
||||||
|
// zone.SetStatus(ZONE_ACTIVE)
|
||||||
|
|
||||||
var/turf/W = new N( locate(src.x, src.y, src.z) )
|
var/turf/W = new N( locate(src.x, src.y, src.z) )
|
||||||
W.lighting_lumcount += old_lumcount
|
W.lighting_lumcount += old_lumcount
|
||||||
if(old_lumcount != W.lighting_lumcount || !accepts_lighting)
|
if(old_lumcount != W.lighting_lumcount)
|
||||||
W.lighting_changed = 1
|
W.lighting_changed = 1
|
||||||
lighting_controller.changed_turfs += W
|
lighting_controller.changed_turfs += W
|
||||||
|
|
||||||
if(src.zone)
|
|
||||||
src.zone.RemoveTurf(src)
|
|
||||||
W.zone = src.zone
|
|
||||||
W.zone.AddTurf(W)
|
|
||||||
|
|
||||||
if(air_master)
|
if(air_master)
|
||||||
for(var/turf/simulated/T in orange(src,1))
|
air_master.mark_for_update(src)
|
||||||
air_master.tiles_to_update.Add(T)
|
|
||||||
|
|
||||||
W.levelupdate()
|
W.levelupdate()
|
||||||
return W
|
return W
|
||||||
|
|||||||
@@ -601,11 +601,11 @@ var/list/admin_verbs_mod = list(
|
|||||||
set category = "Debug"
|
set category = "Debug"
|
||||||
set name = "Kill Air"
|
set name = "Kill Air"
|
||||||
set desc = "Toggle Air Processing"
|
set desc = "Toggle Air Processing"
|
||||||
if(kill_air)
|
if(air_processing_killed)
|
||||||
kill_air = 0
|
air_processing_killed = 0
|
||||||
usr << "<b>Enabled air processing.</b>"
|
usr << "<b>Enabled air processing.</b>"
|
||||||
else
|
else
|
||||||
kill_air = 1
|
air_processing_killed = 1
|
||||||
usr << "<b>Disabled air processing.</b>"
|
usr << "<b>Disabled air processing.</b>"
|
||||||
feedback_add_details("admin_verb","KA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
feedback_add_details("admin_verb","KA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||||
log_admin("[key_name(usr)] used 'kill air'.")
|
log_admin("[key_name(usr)] used 'kill air'.")
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 121 KiB |
Reference in New Issue
Block a user