diff --git a/code/ZAS/Atom.dm b/code/ZAS/Atom.dm
index ce69ad7162..4961355940 100644
--- a/code/ZAS/Atom.dm
+++ b/code/ZAS/Atom.dm
@@ -57,11 +57,11 @@ turf/c_airblock(turf/other)
#ifdef ZASDBG
ASSERT(isturf(other))
#endif
- if(blocks_air || other.blocks_air)
+ if(((blocks_air & AIR_BLOCKED) || (other.blocks_air & AIR_BLOCKED)))
return BLOCKED
//Z-level handling code. Always block if there isn't an open space.
- #ifdef ZLEVELS
+ #ifdef MULTIZAS
if(other.z != src.z)
if(other.z < src.z)
if(!istype(src, /turf/simulated/open)) return BLOCKED
@@ -69,6 +69,12 @@ turf/c_airblock(turf/other)
if(!istype(other, /turf/simulated/open)) return BLOCKED
#endif
+ if(((blocks_air & ZONE_BLOCKED) || (other.blocks_air & ZONE_BLOCKED)))
+ if(z == other.z)
+ return ZONE_BLOCKED
+ else
+ return AIR_BLOCKED
+
var/result = 0
for(var/atom/movable/M in contents)
result |= M.c_airblock(other)
diff --git a/code/ZAS/ConnectionManager.dm b/code/ZAS/ConnectionManager.dm
index 1c101f4b45..28ef365830 100644
--- a/code/ZAS/ConnectionManager.dm
+++ b/code/ZAS/ConnectionManager.dm
@@ -37,7 +37,7 @@ Class Procs:
/connection_manager/var/connection/E
/connection_manager/var/connection/W
-#ifdef ZLEVELS
+#ifdef MULTIZAS
/connection_manager/var/connection/U
/connection_manager/var/connection/D
#endif
@@ -57,7 +57,7 @@ Class Procs:
if(check(W)) return W
else return null
- #ifdef ZLEVELS
+ #ifdef MULTIZAS
if(UP)
if(check(U)) return U
else return null
@@ -73,7 +73,7 @@ Class Procs:
if(EAST) E = c
if(WEST) W = c
- #ifdef ZLEVELS
+ #ifdef MULTIZAS
if(UP) U = c
if(DOWN) D = c
#endif
@@ -83,7 +83,7 @@ Class Procs:
if(check(S)) S.update()
if(check(E)) E.update()
if(check(W)) W.update()
- #ifdef ZLEVELS
+ #ifdef MULTIZAS
if(check(U)) U.update()
if(check(D)) D.update()
#endif
@@ -93,7 +93,7 @@ Class Procs:
if(check(S)) S.erase()
if(check(E)) E.erase()
if(check(W)) W.erase()
- #ifdef ZLEVELS
+ #ifdef MULTIZAS
if(check(U)) U.erase()
if(check(D)) D.erase()
#endif
diff --git a/code/ZAS/Controller.dm b/code/ZAS/Controller.dm
index cfd6cff414..2469f7a36f 100644
--- a/code/ZAS/Controller.dm
+++ b/code/ZAS/Controller.dm
@@ -158,6 +158,9 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
//defer updating of self-zone-blocked turfs until after all other turfs have been updated.
//this hopefully ensures that non-self-zone-blocked turfs adjacent to self-zone-blocked ones
//have valid zones when the self-zone-blocked turfs update.
+
+ //This ensures that doorways don't form their own single-turf zones, since doorways are self-zone-blocked and
+ //can merge with an adjacent zone, whereas zones that are formed on adjacent turfs cannot merge with the doorway.
var/list/deferred = list()
for(var/turf/T in updating)
diff --git a/code/ZAS/Diagnostic.dm b/code/ZAS/Diagnostic.dm
index ed94b7d582..10ec2e731b 100644
--- a/code/ZAS/Diagnostic.dm
+++ b/code/ZAS/Diagnostic.dm
@@ -39,6 +39,10 @@ client/proc/Test_ZAS_Connection(var/turf/simulated/T as turf)
"South" = SOUTH,\
"East" = EAST,\
"West" = WEST,\
+ #ifdef MULTIZAS
+ "Up" = UP,\
+ "Down" = DOWN,\
+ #endif
"N/A" = null)
var/direction = input("What direction do you wish to test?","Set direction") as null|anything in direction_list
if(!direction)
diff --git a/code/ZAS/Turf.dm b/code/ZAS/Turf.dm
index 62cad5e469..bb5eb5050e 100644
--- a/code/ZAS/Turf.dm
+++ b/code/ZAS/Turf.dm
@@ -16,7 +16,7 @@
//dbg(blocked)
return 1
- #ifdef ZLEVELS
+ #ifdef MULTIZAS
for(var/d = 1, d < 64, d *= 2)
#else
for(var/d = 1, d < 16, d *= 2)
@@ -52,34 +52,40 @@
*/
/turf/simulated/proc/can_safely_remove_from_zone()
- #ifdef ZLEVELS
- return 0 //TODO generalize this to multiz.
- #else
-
+
+
if(!zone) return 1
-
+
var/check_dirs = get_zone_neighbours(src)
var/unconnected_dirs = check_dirs
-
- for(var/dir in list(NORTHWEST, NORTHEAST, SOUTHEAST, SOUTHWEST))
-
+
+ #ifdef MULTIZAS
+ var/to_check = cornerdirsz
+ #else
+ var/to_check = cornerdirs
+ #endif
+
+ for(var/dir in to_check)
//for each pair of "adjacent" cardinals (e.g. NORTH and WEST, but not NORTH and SOUTH)
if((dir & check_dirs) == dir)
//check that they are connected by the corner turf
var/connected_dirs = get_zone_neighbours(get_step(src, dir))
- if(connected_dirs && (dir & turn(connected_dirs, 180)) == dir)
+ if(connected_dirs && (dir & reverse_dir[connected_dirs]) == dir)
unconnected_dirs &= ~dir //they are, so unflag the cardinals in question
-
+
//it is safe to remove src from the zone if all cardinals are connected by corner turfs
return !unconnected_dirs
-
- #endif
//helper for can_safely_remove_from_zone()
/turf/simulated/proc/get_zone_neighbours(turf/simulated/T)
. = 0
if(istype(T) && T.zone)
- for(var/dir in cardinal)
+ #ifdef MULTIZAS
+ var/to_check = cardinalz
+ #else
+ var/to_check = cardinal
+ #endif
+ for(var/dir in to_check)
var/turf/simulated/other = get_step(T, dir)
if(istype(other) && other.zone == T.zone && !(other.c_airblock(T) & AIR_BLOCKED) && get_dist(src, other) <= 1)
. |= dir
@@ -98,7 +104,7 @@
#endif
if(zone)
var/zone/z = zone
-
+
if(can_safely_remove_from_zone()) //Helps normal airlocks avoid rebuilding zones all the time
z.remove(src)
else
@@ -110,7 +116,7 @@
open_directions = 0
var/list/postponed
- #ifdef ZLEVELS
+ #ifdef MULTIZAS
for(var/d = 1, d < 64, d *= 2)
#else
for(var/d = 1, d < 16, d *= 2)
@@ -161,7 +167,7 @@
//Might have assigned a zone, since this happens for each direction.
if(!zone)
- //We do not merge if
+ //We do not merge if
// they are blocking us and we are not blocking them, or if
// we are blocking them and not blocking ourselves - this prevents tiny zones from forming on doorways.
if(((block & ZONE_BLOCKED) && !(r_block & ZONE_BLOCKED)) || ((r_block & ZONE_BLOCKED) && !(s_block & ZONE_BLOCKED)))
diff --git a/code/ZAS/_docs.dm b/code/ZAS/_docs.dm
index 1f652ffaab..4433478e32 100644
--- a/code/ZAS/_docs.dm
+++ b/code/ZAS/_docs.dm
@@ -28,8 +28,7 @@ Notes for people who used ZAS before:
*/
//#define ZASDBG
-//#define ZLEVELS
-
+//#define MULTIZAS
#define AIR_BLOCKED 1
#define ZONE_BLOCKED 2
#define BLOCKED 3
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 57f2247255..5021453462 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -166,6 +166,7 @@ var/list/gamemode_cache = list()
var/simultaneous_pm_warning_timeout = 100
var/use_recursive_explosions //Defines whether the server uses recursive or circular explosions.
+ var/multi_z_explosion_scalar = 0.5 //Multiplier for how much weaker explosions are on neighboring z levels.
var/assistant_maint = 0 //Do assistants get maint access?
var/gateway_delay = 18000 //How long the gateway takes before it activates. Default is half an hour.
@@ -283,6 +284,9 @@ var/list/gamemode_cache = list()
if ("use_recursive_explosions")
use_recursive_explosions = 1
+ if ("multi_z_explosion_scalar")
+ multi_z_explosion_scalar = text2num(value)
+
if ("log_ooc")
config.log_ooc = 1
diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm
index b081530e10..dd18925da2 100644
--- a/code/game/objects/explosion.dm
+++ b/code/game/objects/explosion.dm
@@ -1,23 +1,26 @@
//TODO: Flash range does nothing currently
-proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = 1, z_transfer = UP|DOWN)
+proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = 1, z_transfer = UP|DOWN, shaped)
+ var/multi_z_scalar = config.multi_z_explosion_scalar
src = null //so we don't abort once src is deleted
spawn(0)
- if(config.use_recursive_explosions)
- var/power = devastation_range * 2 + heavy_impact_range + light_impact_range //The ranges add up, ie light 14 includes both heavy 7 and devestation 3. So this calculation means devestation counts for 4, heavy for 2 and light for 1 power, giving us a cap of 27 power.
- explosion_rec(epicenter, power)
- return
-
var/start = world.timeofday
epicenter = get_turf(epicenter)
if(!epicenter) return
// Handles recursive propagation of explosions.
- if(devastation_range > 2 || heavy_impact_range > 2)
- if(HasAbove(epicenter.z) && z_transfer & UP)
- explosion(GetAbove(epicenter), max(0, devastation_range - 2), max(0, heavy_impact_range - 2), max(0, light_impact_range - 2), max(0, flash_range - 2), 0, UP)
- if(HasBelow(epicenter.z) && z_transfer & DOWN)
- explosion(GetAbove(epicenter), max(0, devastation_range - 2), max(0, heavy_impact_range - 2), max(0, light_impact_range - 2), max(0, flash_range - 2), 0, DOWN)
+ if(z_transfer && multi_z_scalar)
+ var/adj_dev = max(0, (multi_z_scalar * devastation_range) - (shaped ? 2 : 0) )
+ var/adj_heavy = max(0, (multi_z_scalar * heavy_impact_range) - (shaped ? 2 : 0) )
+ var/adj_light = max(0, (multi_z_scalar * light_impact_range) - (shaped ? 2 : 0) )
+ var/adj_flash = max(0, (multi_z_scalar * flash_range) - (shaped ? 2 : 0) )
+
+
+ if(adj_dev > 0 || adj_heavy > 0)
+ if(HasAbove(epicenter.z) && z_transfer & UP)
+ explosion(GetAbove(epicenter), round(adj_dev), round(adj_heavy), round(adj_light), round(adj_flash), 0, UP, shaped)
+ if(HasBelow(epicenter.z) && z_transfer & DOWN)
+ explosion(GetBelow(epicenter), round(adj_dev), round(adj_heavy), round(adj_light), round(adj_flash), 0, DOWN, shaped)
var/max_range = max(devastation_range, heavy_impact_range, light_impact_range, flash_range)
@@ -30,31 +33,20 @@ proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impa
far_dist += devastation_range * 20
var/frequency = get_rand_frequency()
for(var/mob/M in player_list)
- // Double check for client
- if(M && M.client)
+ if(M.z == epicenter.z)
var/turf/M_turf = get_turf(M)
- if(M_turf && M_turf.z == epicenter.z)
- var/dist = get_dist(M_turf, epicenter)
- // If inside the blast radius + world.view - 2
- if(dist <= round(max_range + world.view - 2, 1))
- M.playsound_local(epicenter, get_sfx("explosion"), 100, 1, frequency, falloff = 5) // get_sfx() is so that everyone gets the same sound
+ var/dist = get_dist(M_turf, epicenter)
+ // If inside the blast radius + world.view - 2
+ if(dist <= round(max_range + world.view - 2, 1))
+ M.playsound_local(epicenter, get_sfx("explosion"), 100, 1, frequency, falloff = 5) // get_sfx() is so that everyone gets the same sound
+ else if(dist <= far_dist)
+ var/far_volume = Clamp(far_dist, 30, 50) // Volume is based on explosion size and dist
+ far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
+ M.playsound_local(epicenter, 'sound/effects/explosionfar.ogg', far_volume, 1, frequency, falloff = 5)
- //You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station.
-
- else if(dist <= far_dist)
- var/far_volume = Clamp(far_dist, 30, 50) // Volume is based on explosion size and dist
- far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
- M.playsound_local(epicenter, 'sound/effects/explosionfar.ogg', far_volume, 1, frequency, falloff = 5)
-
- var/close = range(world.view+round(devastation_range,1), epicenter)
- // to all distanced mobs play a different sound
- for(var/mob/M in world) if(M.z == epicenter.z) if(!(M in close))
- // check if the mob can hear
- if(M.ear_deaf <= 0 || !M.ear_deaf) if(!istype(M.loc,/turf/space))
- M << 'sound/effects/explosionfar.ogg'
if(adminlog)
- message_admins("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range]) in area [epicenter.loc.name] ([epicenter.x],[epicenter.y],[epicenter.z]) (JMP)")
- log_game("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range]) in area [epicenter.loc.name] ")
+ message_admins("Explosion with [shaped ? "shaped" : "non-shaped"] size ([devastation_range], [heavy_impact_range], [light_impact_range]) in area [epicenter.loc.name] ([epicenter.x],[epicenter.y],[epicenter.z]) (JMP)")
+ log_game("Explosion with [shaped ? "shaped" : "non-shaped"] size ([devastation_range], [heavy_impact_range], [light_impact_range]) in area [epicenter.loc.name] ")
var/approximate_intensity = (devastation_range * 3) + (heavy_impact_range * 2) + light_impact_range
var/powernet_rebuild_was_deferred_already = defer_powernet_rebuild
@@ -70,41 +62,42 @@ proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impa
var/x0 = epicenter.x
var/y0 = epicenter.y
var/z0 = epicenter.z
+ if(config.use_recursive_explosions)
+ var/power = devastation_range * 2 + heavy_impact_range + light_impact_range //The ranges add up, ie light 14 includes both heavy 7 and devestation 3. So this calculation means devestation counts for 4, heavy for 2 and light for 1 power, giving us a cap of 27 power.
+ explosion_rec(epicenter, power, shaped)
+ else
+ for(var/turf/T in trange(max_range, epicenter))
+ var/dist = sqrt((T.x - x0)**2 + (T.y - y0)**2)
- for(var/turf/T in trange(max_range, epicenter))
- var/dist = sqrt((T.x - x0)**2 + (T.y - y0)**2)
+ if(dist < devastation_range) dist = 1
+ else if(dist < heavy_impact_range) dist = 2
+ else if(dist < light_impact_range) dist = 3
+ else continue
- if(dist < devastation_range) dist = 1
- else if(dist < heavy_impact_range) dist = 2
- else if(dist < light_impact_range) dist = 3
- else continue
-
- T.ex_act(dist)
- if(T)
+ if(!T)
+ T = locate(x0,y0,z0)
for(var/atom_movable in T.contents) //bypass type checking since only atom/movable can be contained by turfs anyway
var/atom/movable/AM = atom_movable
if(AM && AM.simulated) AM.ex_act(dist)
+ T.ex_act(dist)
+
var/took = (world.timeofday-start)/10
//You need to press the DebugGame verb to see these now....they were getting annoying and we've collected a fair bit of data. Just -test- changes to explosion code using this please so we can compare
- if(Debug2) world.log << "## DEBUG: Explosion([x0],[y0],[z0])(d[devastation_range],h[heavy_impact_range],l[light_impact_range]): Took [took] seconds."
+ if(Debug2) world.log << "## DEBUG: Explosion([x0],[y0],[z0])(d[devastation_range],h[heavy_impact_range],l[light_impact_range]): Took [took] seconds."
//Machines which report explosions.
for(var/i,i<=doppler_arrays.len,i++)
var/obj/machinery/doppler_array/Array = doppler_arrays[i]
if(Array)
Array.sense_explosion(x0,y0,z0,devastation_range,heavy_impact_range,light_impact_range,took)
-
sleep(8)
if(!powernet_rebuild_was_deferred_already && defer_powernet_rebuild)
makepowernets()
defer_powernet_rebuild = 0
-
return 1
-
-
proc/secondaryexplosion(turf/epicenter, range)
for(var/turf/tile in range(range, epicenter))
tile.ex_act(2)
diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm
index 47620d030a..098782ebdf 100644
--- a/code/game/turfs/simulated/wall_attacks.dm
+++ b/code/game/turfs/simulated/wall_attacks.dm
@@ -1,3 +1,6 @@
+#define ZONE_BLOCKED 2
+#define AIR_BLOCKED 1
+
//Interactions
/turf/simulated/wall/proc/toggle_open(var/mob/user)
@@ -8,7 +11,9 @@
can_open = WALL_OPENING
//flick("[material.icon_base]fwall_opening", src)
density = 0
+ blocks_air = ZONE_BLOCKED
update_icon()
+ update_air()
set_light(0)
src.blocks_air = 0
set_opacity(0)
@@ -18,7 +23,9 @@
can_open = WALL_OPENING
//flick("[material.icon_base]fwall_closing", src)
density = 1
+ blocks_air = AIR_BLOCKED
update_icon()
+ update_air()
set_light(1)
src.blocks_air = 1
set_opacity(1)
@@ -28,6 +35,25 @@
can_open = WALL_CAN_OPEN
update_icon()
+#undef ZONE_BLOCKED
+#undef AIR_BLOCKED
+
+/turf/simulated/wall/proc/update_air()
+ if(!air_master)
+ return
+
+ for(var/turf/simulated/turf in loc)
+ update_thermal(turf)
+ air_master.mark_for_update(turf)
+
+
+/turf/simulated/wall/proc/update_thermal(var/turf/simulated/source)
+ if(istype(source))
+ if(density && opacity)
+ source.thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
+ else
+ source.thermal_conductivity = initial(source.thermal_conductivity)
+
/turf/simulated/wall/proc/fail_smash(var/mob/user)
user << "You smash against the wall!"
take_damage(rand(25,75))
diff --git a/code/global.dm b/code/global.dm
index 6970e68dff..ea27e3f823 100644
--- a/code/global.dm
+++ b/code/global.dm
@@ -89,7 +89,9 @@ var/list/blobstart = list()
var/list/ninjastart = list()
var/list/cardinal = list(NORTH, SOUTH, EAST, WEST)
+var/list/cardinalz = list(NORTH, SOUTH, EAST, WEST, UP, DOWN)
var/list/cornerdirs = list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST)
+var/list/cornerdirsz = list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST, NORTH|UP, EAST|UP, WEST|UP, SOUTH|UP, NORTH|DOWN, EAST|DOWN, WEST|DOWN, SOUTH|DOWN)
var/list/alldirs = list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST)
var/list/reverse_dir = list( // reverse_dir[dir] = reverse of dir
2, 1, 3, 8, 10, 9, 11, 4, 6, 5, 7, 12, 14, 13, 15, 32, 34, 33, 35, 40, 42,
diff --git a/config/example/config.txt b/config/example/config.txt
index 8437829fd3..232d3c66ad 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -33,6 +33,9 @@ JOBS_HAVE_MINIMAL_ACCESS
## Unhash this to use recursive explosions, keep it hashed to use circle explosions. Recursive explosions react to walls, airlocks and blast doors, making them look a lot cooler than the boring old circular explosions. They require more CPU and are (as of january 2013) experimental
#USE_RECURSIVE_EXPLOSIONS
+Configure how fast explosion strength diminishes when travelling up/down z levels. All explosion distances are multiplied by this each time they go up/down z-levels.
+#MULTI_Z_EXPLOSION_SCALAR 0.5
+
## log OOC channel
LOG_OOC
diff --git a/html/changelogs/Anewbe - MultiZAS.yml b/html/changelogs/Anewbe - MultiZAS.yml
new file mode 100644
index 0000000000..c04097eb3d
--- /dev/null
+++ b/html/changelogs/Anewbe - MultiZAS.yml
@@ -0,0 +1,36 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# wip (For works in progress)
+# tweak
+# soundadd
+# sounddel
+# rscadd (general adding of nice things)
+# rscdel (general deleting of nice things)
+# imageadd
+# imagedel
+# maptweak
+# spellcheck (typo fixes)
+# experiment
+#################################
+
+# Your name.
+author: Anewbe
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
+# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - rscadd: "Ports but does not enable Bay's MultiZAS."
\ No newline at end of file
diff --git a/html/changelogs/Leshana - MultiZAS.yml b/html/changelogs/Leshana - MultiZAS.yml
new file mode 100644
index 0000000000..891bf846c2
--- /dev/null
+++ b/html/changelogs/Leshana - MultiZAS.yml
@@ -0,0 +1,5 @@
+author: Leshana
+delete-after: True
+changes:
+ - tweak: "Optimized (but still not enabled) multi-z ZAS"
+ - rscadd: "Multi-Z explosion transfer coefficient is now configurable"
\ No newline at end of file