Merge pull request #3651 from SkyMarshal/airfixes

ZAS update, needs testing.
This commit is contained in:
Zuhayr
2013-09-07 05:46:04 -07:00
18 changed files with 522 additions and 362 deletions

View File

@@ -13,68 +13,62 @@ Indirect connections will not merge the two zones after they reach equilibrium.
var/zone/zone_A
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()
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()
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]
if(A in air_master.turfs_with_connections)
var/list/connections = air_master.turfs_with_connections[A]
connections.Add(src)
else
air_master.turfs_with_connections[ref_A] = list(src)
air_master.turfs_with_connections[A] = list(src)
if(ref_B in air_master.turfs_with_connections)
var/list/connections = air_master.turfs_with_connections[ref_B]
if(B in air_master.turfs_with_connections)
var/list/connections = air_master.turfs_with_connections[B]
connections.Add(src)
else
air_master.turfs_with_connections[ref_B] = list(src)
air_master.turfs_with_connections[B] = list(src)
if(A.CanPass(null, B, 0, 0))
ConnectZones(A.zone, B.zone, 1)
if(A.HasDoor(B) || B.HasDoor(A))
if(!A.CanPass(null, B, 1.5, 1))
indirect = CONNECTION_INDIRECT
ConnectZones(A.zone, B.zone, indirect)
else
ConnectZones(A.zone, B.zone)
indirect = CONNECTION_CLOSED
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])"
del(src)
SoftDelete()
/connection/Del()
//remove connections from master lists.
if(ref_B in air_master.turfs_with_connections)
var/list/connections = air_master.turfs_with_connections[ref_B]
if(B in air_master.turfs_with_connections)
var/list/connections = air_master.turfs_with_connections[B]
connections.Remove(src)
if(ref_A in air_master.turfs_with_connections)
var/list/connections = air_master.turfs_with_connections[ref_A]
if(A in air_master.turfs_with_connections)
var/list/connections = air_master.turfs_with_connections[A]
connections.Remove(src)
//Remove connection from zones.
@@ -110,6 +104,46 @@ Indirect connections will not merge the two zones after they reach equilibrium.
. = ..()
/connection/proc/SoftDelete()
//remove connections from master lists.
if(B in air_master.turfs_with_connections)
var/list/connections = air_master.turfs_with_connections[B]
connections.Remove(src)
if(A in air_master.turfs_with_connections)
var/list/connections = air_master.turfs_with_connections[A]
connections.Remove(src)
//Remove connection from zones.
if(A)
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))
if(zone_A.connections)
zone_A.connections.Remove(src)
if(!zone_A.connections.len)
zone_A.connections = null
if(B)
if(B.zone && B.zone.connections)
B.zone.connections.Remove(src)
if(!B.zone.connections.len)
B.zone.connections = null
if(istype(zone_B) && (!B || B.zone != zone_B))
if(zone_B.connections)
zone_B.connections.Remove(src)
if(!zone_B.connections.len)
zone_B.connections = null
//Disconnect zones while handling unusual conditions.
// e.g. loss of a zone on a turf
DisconnectZones(zone_A, zone_B)
/connection/proc/ConnectZones(var/zone/zone_1, var/zone/zone_2, open = 0)
//Sanity checking
@@ -139,6 +173,18 @@ Indirect connections will not merge the two zones after they reach equilibrium.
zone_2.connected_zones += zone_1
zone_2.connected_zones[zone_1] = 1
if(open == CONNECTION_DIRECT)
if(!zone_1.direct_connections)
zone_1.direct_connections = list(src)
else
zone_1.direct_connections += src
if(!zone_2.direct_connections)
zone_2.direct_connections = list(src)
else
zone_2.direct_connections += src
//Handle closed connections.
else
@@ -192,6 +238,15 @@ Indirect connections will not merge the two zones after they reach equilibrium.
if(!zone_2.connected_zones.len)
zone_2.connected_zones = null
if(indirect == CONNECTION_DIRECT)
zone_1.direct_connections -= src
if(!zone_1.direct_connections.len)
zone_1.direct_connections = null
zone_2.direct_connections -= src
if(!zone_2.direct_connections.len)
zone_2.direct_connections = null
else
//Handle disconnection of closed zones.
if( (zone_1 in zone_2.closed_connection_zones) || (zone_2 in zone_1.closed_connection_zones) )
@@ -221,35 +276,23 @@ Indirect connections will not merge the two zones after they reach equilibrium.
//Check sanity: existance of turfs
if(!A || !B)
del src
SoftDelete()
return
//Check sanity: loss of zone
if(!A.zone || !B.zone)
SoftDelete()
return
//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
SoftDelete()
return
//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...
@@ -262,7 +305,7 @@ Indirect connections will not merge the two zones after they reach equilibrium.
//Make and remove connections to let air pass.
if(indirect == CONNECTION_CLOSED)
DisconnectZones(A.zone, B.zone)
ConnectZones(A.zone, B.zone, 1)
ConnectZones(A.zone, B.zone, door_pass + 1)
if(door_pass)
indirect = CONNECTION_DIRECT
@@ -277,7 +320,8 @@ Indirect connections will not merge the two zones after they reach equilibrium.
//If I can no longer pass air, better delete
else
del src
SoftDelete()
return
/connection/proc/Sanitize()
//If the zones change on connected turfs, update it.
@@ -293,9 +337,6 @@ Indirect connections will not merge the two zones after they reach equilibrium.
A = temp
zone_B = B.zone
zone_A = A.zone
var/temp_ref = ref_A
ref_A = ref_B
ref_B = temp_ref
return
//Handle removal of connections from archived zones.

View File

@@ -1,3 +1,14 @@
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"
@@ -120,3 +131,82 @@ zone/proc/DebugDisplay(client/client)
var/turf/zloc = pick(Z.contents)
client << "\red Illegal air datum shared by: [zloc.loc.name]"
client/proc/TestZASRebuild()
// 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.ZAirPass(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

View File

@@ -8,7 +8,7 @@ What are the archived variables for?
#define SPECIFIC_HEAT_AIR 20
#define SPECIFIC_HEAT_CDO 30
#define HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins) \
(carbon_dioxide*SPECIFIC_HEAT_CDO + (oxygen+nitrogen)*SPECIFIC_HEAT_AIR + toxins*SPECIFIC_HEAT_TOXIN)
max(0, carbon_dioxide * SPECIFIC_HEAT_CDO + (oxygen + nitrogen) * SPECIFIC_HEAT_AIR + toxins * SPECIFIC_HEAT_TOXIN)
#define MINIMUM_HEAT_CAPACITY 0.0003
#define QUANTIZE(variable) (round(variable,0.0001))

View File

@@ -53,7 +53,6 @@ Important Procedures
*/
var/kill_air = 0
var/tick_multiplier = 2
atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0)
@@ -87,17 +86,24 @@ atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0)
var/datum/controller/air_system/air_master
/datum/controller/air_system/
//Geoemetry lists
/datum/controller/air_system
//Geometry lists
var/list/turfs_with_connections = list()
var/list/active_hotspots = list()
//Special functions lists
var/reconsidering_zones = FALSE
var/list/tiles_to_reconsider_zones = list()
var/list/tiles_to_reconsider_alternate
//Geometry updates lists
var/updating_tiles = FALSE
var/list/tiles_to_update = list()
var/list/tiles_to_update_alternate
var/checking_connections = FALSE
var/list/connections_to_check = list()
var/list/connections_to_check_alternate
var/current_cycle = 0
var/update_delay = 5 //How long between check should it try to process atmos again.
@@ -106,20 +112,7 @@ var/datum/controller/air_system/air_master
var/tick_progress = 0
/* process()
//Call this to process air movements for a cycle
process_rebuild_select_groups()
//Used by process()
//Warning: Do not call this
rebuild_group(datum/air_group)
//Used by process_rebuild_select_groups()
//Warning: Do not call this, add the group to air_master.groups_to_rebuild instead
*/
/datum/controller/air_system/proc/setup()
/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
@@ -147,10 +140,11 @@ var/datum/controller/air_system/air_master
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()
// 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.
@@ -160,45 +154,60 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
set background = 1
while(1)
if(!kill_air)
current_cycle++
var/success = tick() //Changed so that a runtime does not crash the ticker.
if(!air_processing_killed)
var/success = Tick() //Changed so that a runtime does not crash the ticker.
if(!success) //Runtimed.
failed_ticks++
if(failed_ticks > 20)
world << "<font color='red'><b>ERROR IN ATMOS TICKER. Killing air simulation!</font></b>"
kill_air = 1
air_processing_killed = 1
sleep(max(5,update_delay*tick_multiplier))
*/
/datum/controller/air_system/proc/tick()
/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 = "update_air_properties"
if(tiles_to_update.len) //If there are tiles to update, do so.
if(tiles_to_update.len)
updating_tiles = TRUE
for(var/turf/simulated/T in tiles_to_update)
if(. && T && !T.update_air_properties())
. = 0 //If a runtime occured, make sure we can sense it.
//message_admins("ZASALERT: Unable run turf/simualted/update_air_properties()")
//If a runtime occured, make sure we can sense it.
. = 0
updating_tiles = FALSE
if(.)
tiles_to_update = list()
if(tiles_to_update_alternate)
tiles_to_update = tiles_to_update_alternate
tiles_to_update_alternate = null
else
tiles_to_update = list()
else if(tiles_to_update_alternate)
tiles_to_update |= tiles_to_update_alternate
tiles_to_update_alternate = null
//Check sanity on connection objects.
if(.)
tick_progress = "connections_to_check"
if(connections_to_check.len)
for(var/connection/C in connections_to_check)
C.CheckPassSanity()
connections_to_check = list()
checking_connections = TRUE
//Ensure tiles still have zones.
if(.)
tick_progress = "tiles_to_reconsider_zones"
if(tiles_to_reconsider_zones.len)
for(var/turf/simulated/T in tiles_to_reconsider_zones)
if(!T.zone)
new /zone(T)
tiles_to_reconsider_zones = list()
for(var/connection/C in connections_to_check)
C.Cleanup()
checking_connections = FALSE
if(connections_to_check_alternate)
connections_to_check = connections_to_check_alternate
connections_to_check_alternate = null
else
connections_to_check = list()
//Process zones.
if(.)
@@ -210,6 +219,25 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
Z.last_update = current_cycle
if(. && Z && !output)
. = 0
//Ensure tiles still have zones.
if(.)
tick_progress = "tiles_to_reconsider_zones"
if(tiles_to_reconsider_zones.len)
reconsidering_zones = TRUE
for(var/turf/simulated/T in tiles_to_reconsider_zones)
if(!T.zone)
new /zone(T)
reconsidering_zones = FALSE
if(tiles_to_reconsider_alternate)
tiles_to_reconsider_zones = tiles_to_reconsider_alternate
tiles_to_reconsider_alternate = null
else
tiles_to_reconsider_zones = list()
//Process fires.
if(.)
tick_progress = "active_hotspots (fire)"
@@ -218,4 +246,54 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
. = 0
if(.)
tick_progress = "success"
tick_progress = "success"
/datum/controller/air_system/proc/AddTurfToUpdate(turf/simulated/outdated_turf)
var/list/tiles_to_check = list()
if(istype(outdated_turf))
tiles_to_check |= outdated_turf
if(istype(outdated_turf, /turf))
for(var/direction in cardinal)
var/turf/simulated/adjacent_turf = get_step(outdated_turf, direction)
if(istype(adjacent_turf))
tiles_to_check |= adjacent_turf
if(updating_tiles)
if(!tiles_to_update_alternate)
tiles_to_update_alternate = tiles_to_check
else
tiles_to_update_alternate |= tiles_to_check
else
tiles_to_update |= tiles_to_check
/datum/controller/air_system/proc/AddConnectionToCheck(connection/connection)
if(checking_connections)
if(istype(connection, /list))
if(!connections_to_check_alternate)
connections_to_check_alternate = connection
else if(!connections_to_check_alternate)
connections_to_check_alternate = list()
connections_to_check_alternate |= connection
else
connections_to_check |= connection
/datum/controller/air_system/proc/ReconsiderTileZone(var/turf/simulated/zoneless_turf)
if(zoneless_turf.zone)
return
if(reconsidering_zones)
if(!tiles_to_reconsider_alternate)
tiles_to_reconsider_alternate = list()
tiles_to_reconsider_alternate |= zoneless_turf
else
tiles_to_reconsider_zones |= zoneless_turf

View File

@@ -157,14 +157,13 @@ proc/ZConnect(turf/simulated/A,turf/simulated/B)
if(!A.zone || !B.zone) return
if(A.zone == B.zone) return
if(A.CanPass(null,B,0,1))
if(A.CanPass(null, B, 1.5, 1) && A.zone.air.compare(B.zone.air))
return ZMerge(A.zone,B.zone)
//Ensure the connection isn't already made.
if("\ref[A]" in air_master.turfs_with_connections)
for(var/connection/C in air_master.turfs_with_connections["\ref[A]"])
C.Cleanup()
if(C && (C.B == B || C.A == B))
if(A in air_master.turfs_with_connections)
for(var/connection/C in air_master.turfs_with_connections[A])
if(C.B == B || C.A == B)
return
//Make the connection.

View File

@@ -136,8 +136,8 @@
if(!zone && !blocks_air) //No zone, but not a wall.
for(var/direction in DoorDirections) //Check door directions first.
if(air_check_directions&direction)
var/turf/simulated/T = get_step(src,direction)
if(air_check_directions & direction)
var/turf/simulated/T = get_step(src, direction)
if(!istype(T))
continue
if(T.zone)
@@ -145,7 +145,7 @@
break
if(!zone) //Still no zone
for(var/direction in CounterDoorDirections) //Check the others second.
if(air_check_directions&direction)
if(air_check_directions & direction)
var/turf/simulated/T = get_step(src,direction)
if(!istype(T))
continue
@@ -158,77 +158,23 @@
new/zone(list(src))
//Check pass sanity of the connections.
if("\ref[src]" in air_master.turfs_with_connections)
for(var/connection/C in air_master.turfs_with_connections["\ref[src]"])
air_master.connections_to_check |= C
if(src in air_master.turfs_with_connections)
air_master.AddConnectionToCheck(air_master.turfs_with_connections[src])
if(zone && CanPass(null, src, 0, 0))
if(zone && !zone.rebuild)
for(var/direction in cardinal)
var/turf/T = get_step(src,direction)
if(!istype(T))
continue
//I can connect to air in this direction
if(air_check_directions&direction)
if(air_check_directions & direction && !(air_directions_archived & direction))
//If either block air, we must look to see if the adjacent turfs need rebuilt.
if(!CanPass(null, T, 0, 0))
//Target blocks air
if(!T.CanPass(null, T, 0, 0))
var/turf/NT = get_step(T, direction)
//If that turf is in my zone still, rebuild.
if(istype(NT,/turf/simulated) && NT in zone.contents)
zone.rebuild = 1
//If that is an unsimulated tile in my zone, see if we need to rebuild or just remove.
else if(istype(NT) && NT in zone.unsimulated_tiles)
var/consider_rebuild = 0
for(var/d in cardinal)
var/turf/UT = get_step(NT,d)
if(istype(UT, /turf/simulated) && UT.zone == zone && UT.CanPass(null, NT, 0, 0)) //If we find a neighboring tile that is in the same zone, check if we need to rebuild
consider_rebuild = 1
break
if(consider_rebuild)
zone.rebuild = 1 //Gotta check if we need to rebuild, dammit
else
zone.RemoveTurf(NT) //Not adjacent to anything, and unsimulated. Goodbye~
//To make a closed connection through closed door.
ZConnect(T, src)
//If I block air.
else if(T.zone && !T.zone.rebuild)
var/turf/NT = get_step(src, reverse_direction(direction))
//If I am splitting a zone, rebuild.
if(istype(NT,/turf/simulated) && (NT in T.zone.contents || (NT.zone && T in NT.zone.contents)))
T.zone.rebuild = 1
//If NT is unsimulated, parse if I should remove it or rebuild.
else if(istype(NT) && NT in T.zone.unsimulated_tiles)
var/consider_rebuild = 0
for(var/d in cardinal)
var/turf/UT = get_step(NT,d)
if(istype(UT, /turf/simulated) && UT.zone == T.zone && UT.CanPass(null, NT, 0, 0)) //If we find a neighboring tile that is in the same zone, check if we need to rebuild
consider_rebuild = 1
break
//Needs rebuilt.
if(consider_rebuild)
T.zone.rebuild = 1
//Not adjacent to anything, and unsimulated. Goodbye~
else
T.zone.RemoveTurf(NT)
else
//Produce connection through open door.
ZConnect(src,T)
ZConnect(src,T)
//Something like a wall was built, changing the geometry.
else if(air_directions_archived&direction)
else if(!(air_check_directions & direction) && air_directions_archived & direction)
var/turf/NT = get_step(T, direction)
//If the tile is in our own zone, and we cannot connect to it, better rebuild.
@@ -290,13 +236,13 @@
return 0
for(var/obj/obstacle in src)
if(istype(obstacle, /obj/machinery/door) && !obstacle:air_properties_vary_with_direction)
if(istype(obstacle, /obj/machinery/door) && !(obstacle:air_properties_vary_with_direction))
continue
if(!obstacle.CanPass(null, T, 1.5, 1))
return 0
for(var/obj/obstacle in T)
if(istype(obstacle, /obj/machinery/door) && !obstacle:air_properties_vary_with_direction)
if(istype(obstacle, /obj/machinery/door) && !(obstacle:air_properties_vary_with_direction))
continue
if(!obstacle.CanPass(null, src, 1.5, 1))
return 0
@@ -312,13 +258,13 @@
return 0
for(var/obj/obstacle in src)
if(istype(obstacle, /obj/machinery/door) && !obstacle:air_properties_vary_with_direction)
if(istype(obstacle, /obj/machinery/door) && !(obstacle:air_properties_vary_with_direction))
continue
if(!obstacle.CanPass(null, T, 0, 0))
return 0
for(var/obj/obstacle in T)
if(istype(obstacle, /obj/machinery/door) && !obstacle:air_properties_vary_with_direction)
if(istype(obstacle, /obj/machinery/door) && !(obstacle:air_properties_vary_with_direction))
continue
if(!obstacle.CanPass(null, src, 0, 0))
return 0

View File

@@ -7,11 +7,15 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs
var/rebuild = 0 //If 1, zone will be rebuilt on next process. Not sure if used.
var/datum/gas_mixture/air //The air contents of the zone.
var/list/contents //All the tiles that are contained in this zone.
var/list/connections // /connection objects which refer to connections with other zones, e.g. through a door.
var/list/connected_zones //Parallels connections, but lists zones to which this one is connected and the number
//of points they're connected at.
var/list/closed_connection_zones //Same as connected_zones, but for zones where the door or whatever is closed.
var/list/unsimulated_tiles // Any space tiles in this list will cause air to flow out.
var/list/connections //connection objects which refer to connections with other zones, e.g. through a door.
var/list/direct_connections //connections which directly connect two zones.
var/list/connected_zones //Parallels connections, but lists zones to which this one is connected and the number
//of points they're connected at.
var/list/closed_connection_zones //Same as connected_zones, but for zones where the door or whatever is closed.
var/last_update = 0
var/progress = "nothing"
@@ -49,23 +53,22 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs
zones.Add(src)
//LEGACY, DO NOT USE. Use the SoftDelete proc.
//DO NOT USE. Use the SoftDelete proc.
/zone/Del()
//Ensuring the zone list doesn't get clogged with null values.
for(var/turf/simulated/T in contents)
RemoveTurf(T)
air_master.tiles_to_reconsider_zones += T
air_master.ReconsiderTileZone(T)
for(var/zone/Z in connected_zones)
if(src in Z.connected_zones)
Z.connected_zones.Remove(src)
for(var/connection/C in connections)
air_master.connections_to_check += C
air_master.AddConnectionToCheck(connections)
zones.Remove(src)
air = null
. = ..()
//Handles deletion via garbage collection.
//Handles deletion via garbage collection.
/zone/proc/SoftDelete()
zones.Remove(src)
air = null
@@ -73,7 +76,7 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs
//Ensuring the zone list doesn't get clogged with null values.
for(var/turf/simulated/T in contents)
RemoveTurf(T)
air_master.tiles_to_reconsider_zones += T
air_master.ReconsiderTileZone(T)
//Removing zone connections and scheduling connection cleanup
for(var/zone/Z in connected_zones)
@@ -81,8 +84,7 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs
Z.connected_zones.Remove(src)
connected_zones = null
for(var/connection/C in connections)
air_master.connections_to_check += C
air_master.AddConnectionToCheck(connections)
connections = null
return 1
@@ -99,7 +101,9 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs
contents += T
if(air)
air.group_multiplier++
T.zone = src
else
if(!unsimulated_tiles)
unsimulated_tiles = list()
@@ -116,8 +120,13 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs
contents -= T
if(air)
air.group_multiplier--
if(T.zone == src)
T.zone = null
if(!contents.len)
SoftDelete()
else if(unsimulated_tiles)
unsimulated_tiles -= T
if(!unsimulated_tiles.len)
@@ -226,17 +235,13 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs
progress = "problem with: ZMerge(), a couple of misc procs"
for(var/connection/C in connections)
//Check if the connection is valid first.
if(!C.Cleanup())
continue
if(length(direct_connections))
for(var/connection/C in direct_connections)
//Do merging if conditions are met. Specifically, if there's a non-door connection
//to somewhere with space, the zones are merged regardless of equilibrium, to speed
//up spacing in areas with double-plated windows.
if(C && C.A.zone && C.B.zone)
//indirect = 2 is a direct connection.
if( C.indirect == 2 )
//Do merging if conditions are met. Specifically, if there's a non-door connection
//to somewhere with space, the zones are merged regardless of equilibrium, to speed
//up spacing in areas with double-plated windows.
if(C.A.zone && C.B.zone)
if(C.A.zone.air.compare(C.B.zone.air) || unsimulated_tiles)
ZMerge(C.A.zone,C.B.zone)
@@ -266,6 +271,7 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs
//If that zone has already processed, skip it.
if(Z.last_update > last_update)
continue
if(air && Z.air)
if( abs(air.temperature - Z.air.temperature) > vsc.connection_temperature_delta )
ShareHeat(air, Z.air, closed_connection_zones[Z])
@@ -383,7 +389,7 @@ proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output)
unsim_co2 *= correction_ratio
unsim_nitrogen *= correction_ratio
unsim_plasma *= correction_ratio
unsim_heat_capacity = HEAT_CAPACITY_CALCULATION(unsim_oxygen,unsim_co2,unsim_nitrogen,unsim_plasma)
unsim_heat_capacity = HEAT_CAPACITY_CALCULATION(unsim_oxygen, unsim_co2, unsim_nitrogen, unsim_plasma)
var
ratio = sharing_lookup_table[6]
@@ -402,6 +408,9 @@ proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output)
co2_avg = (full_co2 + unsim_co2) / (size + share_size)
plasma_avg = (full_plasma + unsim_plasma) / (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 >= unsimulated_tiles.len) //6 or more interconnecting tiles will max at 42% of air moved per tick.
@@ -451,72 +460,146 @@ proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles)
///////////////////
//Zone Rebuilding//
///////////////////
//Used for updating zone geometry when a zone is cut into two parts.
zone/proc/Rebuild()
var/list/new_zone_contents = IsolateContents()
if(new_zone_contents.len == 1)
return
var/list/current_contents
var/list/new_zones = list()
contents = new_zone_contents[1]
air.group_multiplier = contents.len
for(var/identifier in 2 to new_zone_contents.len)
current_contents = new_zone_contents[identifier]
var/zone/new_zone = new (current_contents)
new_zone.air.copy_from(air)
new_zones += new_zone
for(var/connection/connection in connections)
connection.Cleanup()
var/turf/simulated/adjacent
for(var/turf/unsimulated in unsimulated_tiles)
for(var/direction in cardinal)
adjacent = get_step(unsimulated, direction)
if(istype(adjacent) && adjacent.CanPass(null, unsimulated, 0, 0))
for(var/zone/zone in new_zones)
if(adjacent in zone)
zone.AddTurf(unsimulated)
//Implements a two-pass connected component labeling algorithm to determine if the zone is, in fact, split.
/zone/proc/IsolateContents()
var/list/current_adjacents = list()
var/adjacent_id
var/lowest_id
var/list/identical_ids = list()
var/list/turfs = contents.Copy()
var/current_identifier = 1
for(var/turf/simulated/current in turfs)
lowest_id = null
current_adjacents = list()
for(var/direction in cardinal)
if( !(current.air_check_directions & direction))
continue
var/turf/simulated/adjacent = get_step(current, direction)
if(adjacent in turfs)
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
for(var/turf/simulated/adjacent in current_adjacents)
adjacent_id = turfs[adjacent]
if(adjacent_id != lowest_id)
if(adjacent_id)
identical_ids[adjacent_id] = lowest_id
turfs[adjacent] = lowest_id
turfs[current] = lowest_id
var/list/final_arrangement = list()
for(var/turf/simulated/current in turfs)
current_identifier = identical_ids[turfs[current]]
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)
return final_arrangement
/*
if(!RequiresRebuild())
return
//Choose a random turf and regenerate the zone from it.
var
turf/simulated/sample = locate() in contents
list/new_contents
problem = 0
var/list/new_contents
var/list/new_unsimulated
//
var/list/turfs_to_consider = contents.Copy()
var/list/turfs_needing_zones = list()
while(!sample || !sample.CanPass(null, sample, 1.5, 1))
if(sample)
turfs_to_consider.Remove(sample)
sample = locate() in turfs_to_consider
if(!sample)
break
var/list/zones_to_check_connections = list(src)
if(!istype(sample) || !sample.CanPass(null, sample, 1.5, 1)) //Not a single valid turf.
for(var/turf/simulated/T in contents)
air_master.tiles_to_update |= T
if(!locate(/turf/simulated/floor) in contents)
for(var/turf/simulated/turf in contents)
air_master.ReconsiderTileZone(turf)
return SoftDelete()
new_contents = FloodFill(sample)
var/turfs_to_ignore = list()
if(direct_connections)
for(var/connection/connection in direct_connections)
if(connection.A.zone != src)
turfs_to_ignore += A
else if(connection.B.zone != src)
turfs_to_ignore += B
var/list/new_unsimulated = ( unsimulated_tiles ? unsimulated_tiles : list() )
new_unsimulated = ( unsimulated_tiles ? unsimulated_tiles : list() )
//Now, we have allocated the new turfs into proper lists, and we can start actually rebuilding.
//If something isn't carried over, it will need a new zone.
for(var/turf/T in contents)
if(!(T in new_contents))
RemoveTurf(T)
turfs_needing_zones += T
//Handle addition of new turfs
for(var/turf/S in new_contents)
if(!istype(S, /turf/simulated))
new_unsimulated |= S
new_contents.Remove(S)
if(contents.len != new_contents.len)
problem = 1
//If something new is added, we need to deal with it seperately.
else if(!(S in contents) && istype(S, /turf/simulated))
if(!(S.zone in zones_to_check_connections))
zones_to_check_connections += S.zone
//If something isn't carried over, there was a complication.
for(var/turf/T in contents)
if(!(T in new_contents))
T.zone = null
problem = 1
S.zone.RemoveTurf(S)
AddTurf(S)
if(problem)
//Build some new zones for stuff that wasn't included.
var/list/turf/simulated/rebuild_turfs = contents - new_contents
var/list/turf/simulated/reconsider_turfs = list()
contents = new_contents
for(var/turf/simulated/T in rebuild_turfs)
if(!T.zone && T.CanPass(null, T, 1.5, 1))
var/zone/Z = new /zone(T)
Z.air.copy_from(air)
else
reconsider_turfs |= T
for(var/turf/simulated/T in reconsider_turfs)
if(!T.zone && T.CanPass(null, T, 1.5, 1))
var/zone/Z = new /zone(T)
Z.air.copy_from(air)
else if(!T in air_master.tiles_to_update)
air_master.tiles_to_update.Add(T)
for(var/turf/simulated/T in contents)
if(T.zone && T.zone != src)
T.zone.RemoveTurf(T)
T.zone = src
else if(!T.zone)
T.zone = src
air.group_multiplier = contents.len
//Handle the addition of new unsimulated tiles.
unsimulated_tiles = null
if(new_unsimulated.len)
@@ -528,20 +611,13 @@ zone/proc/Rebuild()
if(istype(T) && T.zone && S.CanPass(null, T, 0, 0))
T.zone.AddTurf(S)
//UNUSED
/*
zone/proc/connected_zones()
//A legacy proc for getting connected zones.
. = list()
for(var/connection/C in connections)
var/zone/Z
if(C.A.zone == src)
Z = C.B.zone
else
Z = C.A.zone
//Finally, handle the orphaned turfs
for(var/turf/simulated/T in turfs_needing_zones)
if(!T.zone)
zones_to_check_connections += new /zone(T)
for(var/zone/zone in zones_to_check_connections)
for(var/connection/C in zone.connections)
C.Cleanup()*/
if(Z in .)
.[Z]++
else
. += Z
.[Z] = 1*/