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..16122a2eac 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,36 @@ */ /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)) - + var/to_check = list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST) + #ifdef MULTIZAS + to_check += list(NORTHUP, EASTUP, WESTUP, SOUTHUP, NORTHDOWN, EASTDOWN, WESTDOWN, SOUTHDOWN) + #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) + var/to_check = cardinal.Copy() + #ifdef MULTIZAS + to_check += list(UP, DOWN) + #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 +100,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 +112,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 +163,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/__defines/misc.dm b/code/__defines/misc.dm index f85ac5e7d4..cb32f8faa9 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -196,3 +196,13 @@ #define TSC_MORPH "Morpheus" #define TSC_XION "Xion" // Not really needed but consistancy I guess. #define TSC_GIL "Gilthari" + +//MultiZ directions for ZAS checks. +#define NORTHUP (NORTH|UP) +#define EASTUP (EAST|UP) +#define SOUTHUP (SOUTH|UP) +#define WESTUP (WEST|UP) +#define NORTHDOWN (NORTH|DOWN) +#define EASTDOWN (EAST|DOWN) +#define SOUTHDOWN (SOUTH|DOWN) +#define WESTDOWN (WEST|DOWN) diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm index b081530e10..0004a39b1c 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 = 0.35 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) + 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,34 +33,22 @@ 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] ") var/approximate_intensity = (devastation_range * 3) + (heavy_impact_range * 2) + light_impact_range - var/powernet_rebuild_was_deferred_already = defer_powernet_rebuild // Large enough explosion. For performance reasons, powernets will be rebuilt manually if(!defer_powernet_rebuild && (approximate_intensity > 25)) defer_powernet_rebuild = 1 @@ -70,41 +61,41 @@ 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) + T.ex_act(dist) + 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) 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) + tile.ex_act(2) \ No newline at end of file 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/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