From 6f6b606fbfafb93f39bdbcd5146511537d62684e Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Fri, 27 Oct 2023 21:04:53 -0500 Subject: [PATCH 001/906] Simplify sanitize_frequency --- code/_helpers/unsorted.dm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index 8fd9c4e5253..85d9ce8208d 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -275,10 +275,7 @@ Turf and target are seperate in case you want to teleport some distance from a t //Ensure the frequency is within bounds of what it should be sending/recieving at /proc/sanitize_frequency(var/f, var/low = PUBLIC_LOW_FREQ, var/high = PUBLIC_HIGH_FREQ) - f = round(f) - f = max(low, f) - f = min(high, f) - return f + return clamp(round(f), low, high) //Turns 1479 into 147.9 /proc/format_frequency(var/f) From e0bb29055bf4ce7627fe47998e903ca81f3060ad Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Sun, 29 Oct 2023 15:20:53 -0500 Subject: [PATCH 002/906] Add stack amount string helper --- code/game/objects/items/stacks/stack.dm | 12 ++++++++++-- .../objects/structures/_structure_construction.dm | 2 +- code/modules/materials/material_sheets.dm | 7 +++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 2987ca68b1b..b35cf3a4c7b 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -17,6 +17,8 @@ var/list/matter_per_piece var/singular_name var/plural_name + /// If unset, picks a/an based off of if the first letter is a vowel or not. + var/indefinite_article var/base_state var/plural_icon_state var/max_icon_state @@ -42,7 +44,7 @@ if(!singular_name) singular_name = "sheet" if(!plural_name) - plural_name = "[singular_name]s" + plural_name = text_make_plural(singular_name) /obj/item/stack/Destroy() if (src && usr && usr.machine == src) @@ -413,4 +415,10 @@ /**Whether a stack type has the capability to be merged. */ /obj/item/stack/proc/can_merge_stacks(var/obj/item/stack/other) - return !(uses_charge && !force) \ No newline at end of file + return !(uses_charge && !force) + +/// Returns the string describing an amount of the stack, i.e. "an ingot" vs "a flag" +/obj/item/stack/proc/get_string_for_amount(amount) + if(amount == 1) + return indefinite_article ? "[indefinite_article] [singular_name]" : ADD_ARTICLE(singular_name) + return "[amount] [plural_name]" \ No newline at end of file diff --git a/code/game/objects/structures/_structure_construction.dm b/code/game/objects/structures/_structure_construction.dm index 2f9817726c0..e0d45e85e70 100644 --- a/code/game/objects/structures/_structure_construction.dm +++ b/code/game/objects/structures/_structure_construction.dm @@ -107,7 +107,7 @@ var/amount_needed = CEILING((maxhealth - health)/DOOR_REPAIR_AMOUNT) var/used = min(amount_needed,stack.amount) if(used) - to_chat(user, SPAN_NOTICE("You fit [used] [stack.singular_name]\s to damaged areas of \the [src].")) + to_chat(user, SPAN_NOTICE("You fit [stack.get_string_for_amount(used)] to damaged areas of \the [src].")) stack.use(used) last_damage_message = null health = clamp(health, health + used*DOOR_REPAIR_AMOUNT, maxhealth) diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm index f09230614d5..1a119eef214 100644 --- a/code/modules/materials/material_sheets.dm +++ b/code/modules/materials/material_sheets.dm @@ -147,6 +147,13 @@ else icon_state = base_state +/obj/item/stack/material/get_string_for_amount(amount) + . = "[reinf_material ? "reinforced " : null][material.use_name]" + if(amount == 1) + . += " [singular_name]" + return indefinite_article ? "[indefinite_article] [.]" : ADD_ARTICLE(.) + return "[amount] [.] [plural_name]" + /obj/item/stack/material/ingot name = "ingots" singular_name = "ingot" From b9da3292708a606ebe6a4a1e7e7489df66bf298c Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Thu, 2 Nov 2023 12:17:22 -0500 Subject: [PATCH 003/906] Allow cable coil subtypes to disallow recoloring --- code/_global_vars/lists/flavor.dm | 3 ++- code/modules/power/cable.dm | 12 +++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/code/_global_vars/lists/flavor.dm b/code/_global_vars/lists/flavor.dm index 28bf458706f..ccf00b40b7e 100644 --- a/code/_global_vars/lists/flavor.dm +++ b/code/_global_vars/lists/flavor.dm @@ -130,7 +130,8 @@ GLOBAL_GETTER(cable_colors, /list, SetupCableColors()) var/name = special_name_mappings[coil_type] || capitalize(copytext_after_last("[coil_type]", "/")) var/obj/item/stack/cable_coil/C = coil_type + if(!initial(C.can_have_color)) + continue var/color = initial(C.color) - .[name] = color . = sortTim(., /proc/cmp_text_asc) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 99bc9c130bc..ac3cfc25a1e 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -33,6 +33,8 @@ By design, d1 is the smallest direction and d2 is the highest obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED level = LEVEL_BELOW_PLATING + /// Whether this cable type can be (re)colored. + var/can_have_color = TRUE var/d1 var/d2 var/datum/powernet/powernet @@ -241,6 +243,8 @@ By design, d1 is the smallest direction and d2 is the highest . = ..() /obj/structure/cable/proc/cableColor(var/colorC) + if(!can_have_color) + return var/color_n = "#dd0000" if(colorC) color_n = colorC @@ -495,6 +499,8 @@ By design, d1 is the smallest direction and d2 is the highest attack_verb = list("whipped", "lashed", "disciplined", "flogged") stack_merge_type = /obj/item/stack/cable_coil matter_multiplier = 0.15 + /// Whether or not this cable coil can even have a color in the first place. + var/can_have_color = TRUE /obj/item/stack/cable_coil/single amount = 1 @@ -515,7 +521,7 @@ By design, d1 is the smallest direction and d2 is the highest TOOL_CABLECOIL = TOOL_QUALITY_DEFAULT, TOOL_SUTURES = TOOL_QUALITY_MEDIOCRE )) - if (param_color) // It should be red by default, so only recolor it if parameter was specified. + if (can_have_color && param_color) // It should be red by default, so only recolor it if parameter was specified. color = param_color update_icon() update_wclass() @@ -547,7 +553,7 @@ By design, d1 is the smallest direction and d2 is the highest /obj/item/stack/cable_coil/on_update_icon() . = ..() - if (!color) + if (!color && can_have_color) var/list/possible_cable_colours = get_global_cable_colors() color = possible_cable_colours[pick(possible_cable_colours)] if(amount == 1) @@ -564,7 +570,7 @@ By design, d1 is the smallest direction and d2 is the highest SetName(initial(name)) /obj/item/stack/cable_coil/proc/set_cable_color(var/selected_color, var/user) - if(!selected_color) + if(!selected_color || !can_have_color) return var/list/possible_cable_colours = get_global_cable_colors() From 7895d83baccb07f500f4f7e1f5d721b2153c3359 Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Sun, 29 Oct 2023 18:45:44 -0500 Subject: [PATCH 004/906] Readd Ian bedsheet --- code/game/objects/structures/bedsheet_bin.dm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index b5e55077eb7..046bd6e2119 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -78,6 +78,9 @@ LINEN BINS /obj/item/bedsheet/brown icon = 'icons/obj/bedsheets/bedsheet_brown.dmi' +/obj/item/bedsheet/ian + icon = 'icons/obj/bedsheets/bedsheet_ian.dmi' + ////////////////////////////////////////// // Bedsheet bin ////////////////////////////////////////// From 8418b282b6eb9c819a91f68613f7962e74f64296 Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Mon, 23 Oct 2023 23:41:38 -0500 Subject: [PATCH 005/906] Connect cablenets across level boundaries --- code/modules/power/cable.dm | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index ac3cfc25a1e..86bb4d1d262 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -259,7 +259,7 @@ By design, d1 is the smallest direction and d2 is the highest /obj/structure/cable/proc/mergeDiagonalsNetworks(var/direction) //search for and merge diagonally matching cables from the first direction component (north/south) - var/turf/T = get_step(src, direction&3)//go north/south + var/turf/T = get_step_resolving_mimic(src, direction & (NORTH|SOUTH)) for(var/obj/structure/cable/C in T) @@ -269,7 +269,7 @@ By design, d1 is the smallest direction and d2 is the highest if(src == C) continue - if(C.d1 == (direction^3) || C.d2 == (direction^3)) //we've got a diagonally matching cable + if(C.d1 == (direction ^ (NORTH|SOUTH)) || C.d2 == (direction ^ (NORTH|SOUTH))) //we've got a diagonally matching cable if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables) var/datum/powernet/newPN = new() newPN.add_cable(C) @@ -280,7 +280,7 @@ By design, d1 is the smallest direction and d2 is the highest C.powernet.add_cable(src) //else, we simply connect to the matching cable powernet //the same from the second direction component (east/west) - T = get_step(src, direction&12)//go east/west + T = get_step_resolving_mimic(src, direction & (EAST|WEST)) for(var/obj/structure/cable/C in T) @@ -289,7 +289,7 @@ By design, d1 is the smallest direction and d2 is the highest if(src == C) continue - if(C.d1 == (direction^12) || C.d2 == (direction^12)) //we've got a diagonally matching cable + if(C.d1 == (direction ^ (EAST|WEST)) || C.d2 == (direction ^ (EAST|WEST))) //we've got a diagonally matching cable if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables) var/datum/powernet/newPN = new() newPN.add_cable(C) @@ -307,7 +307,7 @@ By design, d1 is the smallest direction and d2 is the highest if(!(d1 == direction || d2 == direction)) //if the cable is not pointed in this direction, do nothing return - var/turf/TB = get_zstep(src, direction) + var/turf/TB = get_zstep_resolving_mimic(src, direction) for(var/obj/structure/cable/C in TB) @@ -384,14 +384,14 @@ By design, d1 is the smallest direction and d2 is the highest if(cable_dir == 0) continue var/reverse = global.reverse_dir[cable_dir] - T = get_zstep(src, cable_dir) + T = get_zstep_resolving_mimic(src, cable_dir) if(T) for(var/obj/structure/cable/C in T) if(C.d1 == reverse || C.d2 == reverse) . += C if(cable_dir & (cable_dir - 1)) // Diagonal, check for /\/\/\ style cables along cardinal directions for(var/pair in list(NORTH|SOUTH, EAST|WEST)) - T = get_step(src, cable_dir & pair) + T = get_step_resolving_mimic(src, cable_dir & pair) if(T) var/req_dir = cable_dir ^ pair for(var/obj/structure/cable/C in T) @@ -435,7 +435,7 @@ By design, d1 is the smallest direction and d2 is the highest var/list/P_list if(!T1) return if(d1) - T1 = get_step(T1, d1) + T1 = get_zstep_resolving_mimic(T1, d1) P_list = power_list(T1, src, turn(d1,180),0,cable_only = 1) // what adjacently joins on to cut cable... P_list += power_list(loc, src, d1, 0, cable_only = 1)//... and on turf From 9b491fa2267e80a53cccb04665e4b71abd5a3410 Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Fri, 27 Oct 2023 06:19:19 -0500 Subject: [PATCH 006/906] Add missing rust floor decals --- code/game/turfs/flooring/flooring_decals.dm | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/code/game/turfs/flooring/flooring_decals.dm b/code/game/turfs/flooring/flooring_decals.dm index a0b5e210674..3ea49fd069f 100644 --- a/code/game/turfs/flooring/flooring_decals.dm +++ b/code/game/turfs/flooring/flooring_decals.dm @@ -1426,6 +1426,20 @@ var/global/list/floor_decals = list() /obj/effect/floor_decal/rust/part_rusted1 icon_state = "part_rusted1" +/obj/effect/floor_decal/rust/part_rusted2 + icon_state = "part_rusted2" + +/obj/effect/floor_decal/rust/part_rusted3 + icon_state = "part_rusted3" + +/obj/effect/floor_decal/rust/mono_rusted1 + icon_state = "mono_rusted1" + +/obj/effect/floor_decal/rust/mono_rusted2 + icon_state = "mono_rusted2" + +/obj/effect/floor_decal/rust/mono_rusted3 + icon_state = "mono_rusted3" /obj/effect/floor_decal/rust/steel_decals_rusted1 icon_state = "steel_decals_rusted1" From d9cb12c539a2fc9a3efd6132dc12037df58f1427 Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Mon, 30 Oct 2023 23:01:05 -0500 Subject: [PATCH 007/906] Optimize random maps by approximately 70% --- .../planet_themes/ruined_city.dm | 11 +-- .../random_exoplanet/planet_types/volcanic.dm | 18 +---- .../random_exoplanet/random_map.dm | 5 +- code/modules/random_map/_random_map_setup.dm | 8 ++ code/modules/random_map/building/building.dm | 9 ++- code/modules/random_map/drop/droppod.dm | 4 +- code/modules/random_map/dungeon/room.dm | 30 +++++--- .../random_map/dungeon/winding_dungeon.dm | 37 +++++----- code/modules/random_map/mazes/maze.dm | 21 ++++-- code/modules/random_map/noise/magma.dm | 19 ++--- code/modules/random_map/noise/noise.dm | 74 ++++++++++++------- code/modules/random_map/noise/ore.dm | 26 +++---- code/modules/random_map/random_map.dm | 22 +++--- 13 files changed, 162 insertions(+), 122 deletions(-) diff --git a/code/modules/maps/template_types/random_exoplanet/planet_themes/ruined_city.dm b/code/modules/maps/template_types/random_exoplanet/planet_themes/ruined_city.dm index 2ec87d62a47..0decc6d51af 100644 --- a/code/modules/maps/template_types/random_exoplanet/planet_themes/ruined_city.dm +++ b/code/modules/maps/template_types/random_exoplanet/planet_themes/ruined_city.dm @@ -171,26 +171,27 @@ ..() for(var/x in 1 to limit_x - 1) for(var/y in 1 to limit_y - 1) - var/value = map[get_map_cell(x,y)] + var/value = map[TRANSLATE_COORD(x,y)] if(value != FLOOR_VALUE) continue var/list/neighbors = list() for(var/offset in list(list(0,1), list(0,-1), list(1,0), list(-1,0))) - var/char = map[get_map_cell(x + offset[1], y + offset[2])] + var/tmp_cell = TRANSLATE_COORD(x + offset[1], y+offset[2]) + var/char = LAZYACCESS(map, tmp_cell) if(char == FLOOR_VALUE || char == DOOR_VALUE) - neighbors.Add(get_map_cell(x + offset[1], y + offset[2])) + neighbors.Add(tmp_cell) if(length(neighbors) > 1) continue map[neighbors[1]] = DOOR_VALUE if(artifacts_to_spawn) - map[get_map_cell(x,y)] = ARTIFACT_VALUE + map[TRANSLATE_COORD(x,y)] = ARTIFACT_VALUE artifacts_to_spawn-- var/entrance_x = pick(rand(2,limit_x-1), 1, limit_x) var/entrance_y = pick(1, limit_y) if(entrance_x == 1 || entrance_x == limit_x) entrance_y = rand(2,limit_y-1) - map[get_map_cell(entrance_x,entrance_y)] = DOOR_VALUE + map[TRANSLATE_COORD(entrance_x,entrance_y)] = DOOR_VALUE /datum/random_map/maze/lab/get_appropriate_path(var/value) if(value == ARTIFACT_VALUE) diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/volcanic.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/volcanic.dm index 352ea65fd3f..1fce3f9757d 100644 --- a/code/modules/maps/template_types/random_exoplanet/planet_types/volcanic.dm +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/volcanic.dm @@ -119,23 +119,7 @@ flora_prob = 3 grass_prob = 0 large_flora_prob = 0 - -//Squashing most of 1 tile lava puddles -/datum/random_map/noise/exoplanet/volcanic/cleanup() - for(var/x = 1, x <= limit_x, x++) - for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) - if(noise2value(map[current_cell]) < water_level) - continue - var/frendos - for(var/dx in list(-1,0,1)) - for(var/dy in list(-1,0,1)) - var/tmp_cell = get_map_cell(x+dx,y+dy) - if(tmp_cell && tmp_cell != current_cell && noise2value(map[tmp_cell]) >= water_level) - frendos = 1 - break - if(!frendos) - map[current_cell] = 1 + smooth_single_tiles = TRUE //////////////////////////////////////////////////////////////////////////// // Areas diff --git a/code/modules/maps/template_types/random_exoplanet/random_map.dm b/code/modules/maps/template_types/random_exoplanet/random_map.dm index 2123227b8df..c3b8a9e729d 100644 --- a/code/modules/maps/template_types/random_exoplanet/random_map.dm +++ b/code/modules/maps/template_types/random_exoplanet/random_map.dm @@ -1,4 +1,5 @@ #define COAST_VALUE (cell_range + 1) +#define TRANSLATE_COORD(X,Y) ((((Y) - 1) * limit_x) + (X)) ///Place down flora/fauna spawners, grass, water, and apply selected land type. /datum/random_map/noise/exoplanet @@ -137,7 +138,7 @@ return for(var/x in 1 to limit_x - 1) for(var/y in 1 to limit_y - 1) - var/mapcell = get_map_cell(x,y) + var/mapcell = TRANSLATE_COORD(x,y) if(noise2value(map[mapcell]) < water_level) var/neighbors = get_neighbors(x, y, TRUE) for(var/cell in neighbors) @@ -168,3 +169,5 @@ target_turf_type = /turf/exterior/rock/volcanic //Only let it apply to non-lava turfs floor_type = null wall_type = /turf/exterior/wall + +#undef TRANSLATE_COORD \ No newline at end of file diff --git a/code/modules/random_map/_random_map_setup.dm b/code/modules/random_map/_random_map_setup.dm index e89f0cd035d..0d3347d89e6 100644 --- a/code/modules/random_map/_random_map_setup.dm +++ b/code/modules/random_map/_random_map_setup.dm @@ -27,6 +27,14 @@ #define TRANSLATE_AND_VERIFY_COORD_MLEN(X,Y,LEN) \ tmp_cell = TRANSLATE_COORD(X,Y);\ + if (tmp_cell < 1 || tmp_cell > LEN) {\ + tmp_cell = null;\ + } + +#define TRANSLATE_COORD_OTHER_MAP(X,Y,MAP) ((((Y) - 1) * MAP.limit_x) + (X)) +#define TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(X,Y,MAP) TRANSLATE_AND_VERIFY_COORD_OTHER_MAP_MLEN(X, Y, MAP, MAP.map.len) +#define TRANSLATE_AND_VERIFY_COORD_OTHER_MAP_MLEN(X,Y,MAP,LEN) \ + tmp_cell = TRANSLATE_COORD_OTHER_MAP(X,Y,MAP);\ if (tmp_cell < 1 || tmp_cell > LEN) {\ tmp_cell = null;\ } \ No newline at end of file diff --git a/code/modules/random_map/building/building.dm b/code/modules/random_map/building/building.dm index 98a157c4599..5a24fa36708 100644 --- a/code/modules/random_map/building/building.dm +++ b/code/modules/random_map/building/building.dm @@ -6,7 +6,7 @@ /datum/random_map/building/generate_map() for(var/x = 1, x <= limit_x, x++) for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) + var/current_cell = TRANSLATE_COORD(x,y) if(!current_cell) continue if(x == 1 || y == 1 || x == limit_x || y == limit_y) @@ -18,7 +18,7 @@ var/list/possible_doors for(var/x = 1, x <= limit_x, x++) for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) + var/current_cell = TRANSLATE_COORD(x,y) if(!current_cell) continue if(!(x == 1 || y == 1 || x == limit_x || y == limit_y)) @@ -39,7 +39,10 @@ if(place_door) - possible_doors |= target_map.get_map_cell(tx+x,ty+y) + var/tmp_cell + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(tx+x, ty+y, target_map) + if(tmp_cell) + possible_doors |= tmp_cell if(possible_doors.len) // Place at least one door. diff --git a/code/modules/random_map/drop/droppod.dm b/code/modules/random_map/drop/droppod.dm index 60cadc79e2c..e154e501ded 100644 --- a/code/modules/random_map/drop/droppod.dm +++ b/code/modules/random_map/drop/droppod.dm @@ -47,7 +47,7 @@ // Draw walls/floors/doors. for(var/x = 1, x <= limit_x, x++) for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) + var/current_cell = TRANSLATE_COORD(x,y) if(!current_cell) continue @@ -73,7 +73,7 @@ map[current_cell] = SD_FLOOR_TILE // Draw the drop contents. - var/current_cell = get_map_cell(x_midpoint,y_midpoint) + var/current_cell = TRANSLATE_COORD(x_midpoint,y_midpoint) if(current_cell) map[current_cell] = SD_SUPPLY_TILE return 1 diff --git a/code/modules/random_map/dungeon/room.dm b/code/modules/random_map/dungeon/room.dm index 8c60a977c27..c95dff95a9f 100644 --- a/code/modules/random_map/dungeon/room.dm +++ b/code/modules/random_map/dungeon/room.dm @@ -41,35 +41,45 @@ If its complexity is lower than our theme's then for(var/j = 0, j < height, j++) var/truex = xorigin + x + i - 1 var/truey = yorigin + y + j - 1 - var/cell = map.get_map_cell(x+i,y+j) + var/tmp_cell + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i, y+j, map) + var/cell = tmp_cell room_theme.apply_room_theme(truex,truey,map.map[cell]) if(generate_doors && room_theme.door_type && !(map.map[cell] == WALL_CHAR || map.map[cell] == ARTIFACT_TURF_CHAR) && (i == 0 || i == width-1 || j == 0 || j == height-1)) var/isGood = 1 if(j == 0 || j == height-1) //check horizontally - var/curCell = map.map[map.get_map_cell(x+i-1,y+j)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i-1,y+j, map) + var/curCell = map.map[tmp_cell] if(curCell != WALL_CHAR && curCell != ARTIFACT_TURF_CHAR) isGood = 0 - curCell = map.map[map.get_map_cell(x+i+1,y+j)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i+1,y+j, map) + curCell = map.map[tmp_cell] if(curCell != WALL_CHAR && curCell != ARTIFACT_TURF_CHAR) isGood = 0 - curCell = map.map[map.get_map_cell(x+i,y+j-1)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i,y+j-1, map) + curCell = map.map[tmp_cell] if(curCell == WALL_CHAR || curCell == ARTIFACT_TURF_CHAR) isGood = 0 - curCell = map.map[map.get_map_cell(x+i,y+j+1)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i,y+j+1, map) + curCell = map.map[tmp_cell] if(curCell == WALL_CHAR || curCell == ARTIFACT_TURF_CHAR) isGood = 0 - if(i == 0 || i == width-1) //verticle + if(i == 0 || i == width-1) //vertical isGood = 1 //if it failed above, it might not fail here. - var/curCell = map.map[map.get_map_cell(x+i,y+j-1)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i,y+j-1, map) + var/curCell = map.map[tmp_cell] if(curCell != WALL_CHAR && curCell != ARTIFACT_TURF_CHAR) isGood = 0 - curCell = map.map[map.get_map_cell(x+i,y+j+1)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i,y+j+1, map) + curCell = map.map[tmp_cell] if(curCell != WALL_CHAR && curCell != ARTIFACT_TURF_CHAR) isGood = 0 - curCell = map.map[map.get_map_cell(x+i-1,y+j)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i-1,y+j, map) + curCell = map.map[tmp_cell] if(curCell == WALL_CHAR || curCell == ARTIFACT_TURF_CHAR) isGood = 0 - curCell = map.map[map.get_map_cell(x+i+1,y+j)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i+1,y+j, map) + curCell = map.map[tmp_cell] if(curCell == WALL_CHAR || curCell == ARTIFACT_TURF_CHAR) isGood = 0 if(isGood) diff --git a/code/modules/random_map/dungeon/winding_dungeon.dm b/code/modules/random_map/dungeon/winding_dungeon.dm index dc66d864e75..e301ec2c887 100644 --- a/code/modules/random_map/dungeon/winding_dungeon.dm +++ b/code/modules/random_map/dungeon/winding_dungeon.dm @@ -154,11 +154,11 @@ logging("Winding Dungeon Generation Start") //first generate the border for(var/xx = 1, xx <= limit_x, xx++) - map[get_map_cell(xx,1)] = BORDER_CHAR - map[get_map_cell(xx,limit_y)] = BORDER_CHAR + map[TRANSLATE_COORD(xx,1)] = BORDER_CHAR + map[TRANSLATE_COORD(xx,limit_y)] = BORDER_CHAR for(var/yy = 1, yy < limit_y, yy++) - map[get_map_cell(1,yy)] = BORDER_CHAR - map[get_map_cell(limit_x,yy)] = BORDER_CHAR + map[TRANSLATE_COORD(1,yy)] = BORDER_CHAR + map[TRANSLATE_COORD(limit_x,yy)] = BORDER_CHAR var/num_of_features = limit_x * limit_y * features_multiplier logging("Number of features: [num_of_features]") @@ -197,7 +197,7 @@ logging("open_positions empty. Using randomly chosen coords ([newx],[newy])") //We want to make sure we aren't RIGHT next to another corridor or something. - if(map[get_map_cell(newx,newy+1)] == ARTIFACT_CHAR || map[get_map_cell(newx-1,newy)] == ARTIFACT_CHAR || map[get_map_cell(newx,newy-1)] == ARTIFACT_CHAR || map[get_map_cell(newx+1,newy)] == ARTIFACT_CHAR) + if(LAZYACCESS(map, TRANSLATE_COORD(newx,newy+1)) == ARTIFACT_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx-1,newy)) == ARTIFACT_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx,newy-1)) == ARTIFACT_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx+1,newy)) == ARTIFACT_CHAR) logging("Coords ([newx],[newy]) are too close to an ARTIFACT_CHAR position.") continue @@ -207,9 +207,9 @@ height = rand(room_size_min,room_size_max) isRoom = rand(100) <= chance_of_room - if(map[get_map_cell(newx, newy)] == ARTIFACT_TURF_CHAR || map[get_map_cell(newx, newy)] == CORRIDOR_TURF_CHAR) + if(LAZYACCESS(map, TRANSLATE_COORD(newx, newy)) == ARTIFACT_TURF_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx, newy)) == CORRIDOR_TURF_CHAR) //we are basically checking to see where we're going. Up, right, down or left and finding the bottom left corner. - if(map[get_map_cell(newx,newy+1)] == FLOOR_CHAR || map[get_map_cell(newx,newy+1)] == CORRIDOR_TURF_CHAR) //0 - down + if(LAZYACCESS(map, TRANSLATE_COORD(newx,newy+1)) == FLOOR_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx,newy+1)) == CORRIDOR_TURF_CHAR) //0 - down logging("This feature is DOWN") if(isRoom) //gotta do some math for this one, since the origin is centered. xmod = -width/2 @@ -219,7 +219,7 @@ ymod = -height //a lot of this will seem nonsense but I swear its not doorx = 0 doory = -1 - else if(map[get_map_cell(newx-1,newy)] == FLOOR_CHAR || map[get_map_cell(newx-1,newy)] == CORRIDOR_TURF_CHAR) //1 - right + else if(LAZYACCESS(map, TRANSLATE_COORD(newx-1,newy)) == FLOOR_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx-1,newy)) == CORRIDOR_TURF_CHAR) //1 - right logging("This feature is RIGHT") if(isRoom) ymod = -height/2 @@ -229,7 +229,7 @@ xmod = 1 doorx = 1 doory = 0 - else if(map[get_map_cell(newx,newy-1)] == FLOOR_CHAR || map[get_map_cell(newx,newy-1)] == CORRIDOR_TURF_CHAR) //2 - up + else if(LAZYACCESS(map, TRANSLATE_COORD(newx,newy-1)) == FLOOR_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx,newy-1)) == CORRIDOR_TURF_CHAR) //2 - up logging("This feature is UP") if(isRoom) xmod = -width/2 @@ -239,7 +239,7 @@ ymod = 1 doorx = 0 doory = 1 - else if(map[get_map_cell(newx+1,newy)] == FLOOR_CHAR || map[get_map_cell(newx+1,newy)] == CORRIDOR_TURF_CHAR) // 3 - left + else if(LAZYACCESS(map, TRANSLATE_COORD(newx+1,newy)) == FLOOR_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx+1,newy)) == CORRIDOR_TURF_CHAR) // 3 - left logging("This feature is LEFT") if(isRoom) ymod = -height/2 @@ -263,16 +263,17 @@ currentFeatures++ if(isRoom) logging("Room created at: [newx+xmod], [newy+ymod].") - map[get_map_cell(newx,newy)] = FLOOR_CHAR - map[get_map_cell(newx+doorx,newy+doory)] = ARTIFACT_CHAR + map[TRANSLATE_COORD(newx,newy)] = FLOOR_CHAR + map[TRANSLATE_COORD(newx+doorx,newy+doory)] = ARTIFACT_CHAR if(rand(0,100) >= chance_of_room_empty) var/room_result = create_room_features(round(newx+xmod),round(newy+ymod),width,height) logging("Attempted room feature creation: [room_result ? "Success" : "Failure"]") else logging("Creating corridor.") - var/door = get_map_cell(newx,newy) - if(map[door] == ARTIFACT_TURF_CHAR) - map[door] = ARTIFACT_CHAR + var/tmp_cell + TRANSLATE_AND_VERIFY_COORD(newx,newy) + if(map[tmp_cell] == ARTIFACT_TURF_CHAR) + map[tmp_cell] = ARTIFACT_CHAR logging("Map completed. Loops: [sanity], [currentFeatures] out of [num_of_features] created.") open_positions.Cut() @@ -287,17 +288,17 @@ if(xtemp < 0 || xtemp > limit_x) logging("We are beyond our x limits") return 0 - if(map[get_map_cell(xtemp,ytemp)] != WALL_CHAR) + if(map[TRANSLATE_COORD(xtemp,ytemp)] != WALL_CHAR) logging("[xtemp],[ytemp] is not equal to WALL_CHAR") return 0 else if(wall_char && (ytemp == truey || ytemp == truey + height - 1 || xtemp == truex || xtemp == truex + width - 1)) - map[get_map_cell(xtemp,ytemp)] = wall_char + map[TRANSLATE_COORD(xtemp,ytemp)] = wall_char if(!("[xtemp]:[ytemp]" in open_positions)) open_positions += "[xtemp]:[ytemp]" logging("Adding \"[xtemp]:[ytemp]\" to open_positions (length: [open_positions.len])") else - map[get_map_cell(xtemp,ytemp)] = char + map[TRANSLATE_COORD(xtemp,ytemp)] = char return 1 /datum/random_map/winding_dungeon/proc/create_room_features(var/rox,var/roy,var/width,var/height) diff --git a/code/modules/random_map/mazes/maze.dm b/code/modules/random_map/mazes/maze.dm index 557adbd6e8e..b9e5cc24b3e 100644 --- a/code/modules/random_map/mazes/maze.dm +++ b/code/modules/random_map/mazes/maze.dm @@ -31,19 +31,28 @@ // Preliminary marking-off... closedlist[next.name] = next - map[get_map_cell(next.x,next.y)] = FLOOR_CHAR + map[TRANSLATE_COORD(next.x,next.y)] = FLOOR_CHAR // Apply the values required and fill gap between this cell and origin point. + var/tmp_cell if(next.ox && next.oy) if(next.ox < next.x) - map[get_map_cell(next.x-1,next.y)] = FLOOR_CHAR + TRANSLATE_AND_VERIFY_COORD(next.x-1, next.y) + if(tmp_cell) + map[tmp_cell] = FLOOR_CHAR else if(next.ox == next.x) if(next.oy < next.y) - map[get_map_cell(next.x,next.y-1)] = FLOOR_CHAR + TRANSLATE_AND_VERIFY_COORD(next.x, next.y-1) + if(tmp_cell) + map[tmp_cell] = FLOOR_CHAR else - map[get_map_cell(next.x,next.y+1)] = FLOOR_CHAR + TRANSLATE_AND_VERIFY_COORD(next.x, next.y+1) + if(tmp_cell) + map[tmp_cell] = FLOOR_CHAR else - map[get_map_cell(next.x+1,next.y)] = FLOOR_CHAR + TRANSLATE_AND_VERIFY_COORD(next.x+1, next.y) + if(tmp_cell) + map[tmp_cell] = FLOOR_CHAR // Grab valid neighbors for use in the open list! add_to_openlist(next.x,next.y+2,next.x,next.y) @@ -60,6 +69,6 @@ if(tx < 1 || ty < 1 || tx > limit_x || ty > limit_y || !isnull(checked_coord_cache["[tx]-[ty]"])) return 0 checked_coord_cache["[tx]-[ty]"] = 1 - map[get_map_cell(tx,ty)] = DOOR_CHAR + map[TRANSLATE_COORD(tx,ty)] = DOOR_CHAR var/datum/maze_cell/new_cell = new(tx,ty,nx,ny) openlist |= new_cell diff --git a/code/modules/random_map/noise/magma.dm b/code/modules/random_map/noise/magma.dm index 0e3ac3c7945..d078ef6cdf1 100644 --- a/code/modules/random_map/noise/magma.dm +++ b/code/modules/random_map/noise/magma.dm @@ -9,25 +9,26 @@ /datum/random_map/noise/volcanism/cleanup() for(var/x = 1, x <= limit_x, x++) for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) + var/current_cell = TRANSLATE_COORD(x,y) if(map[current_cell] < 178) continue var/count - var/tmp_cell = get_map_cell(x+1,y+1) + var/tmp_cell + TRANSLATE_AND_VERIFY_COORD(x+1, y+1) if(tmp_cell && map[tmp_cell] >= 178) count++ - tmp_cell = get_map_cell(x-1,y-1) + TRANSLATE_AND_VERIFY_COORD(x-1,y-1) if(tmp_cell && map[tmp_cell] >= 178) count++ - tmp_cell = get_map_cell(x+1,y-1) + TRANSLATE_AND_VERIFY_COORD(x+1,y-1) if(tmp_cell && map[tmp_cell] >= 178) count++ - tmp_cell = get_map_cell(x-1,y+1) + TRANSLATE_AND_VERIFY_COORD(x-1,y+1) if(tmp_cell && map[tmp_cell] >= 178) count++ - tmp_cell = get_map_cell(x-1,y) + TRANSLATE_AND_VERIFY_COORD(x-1,y) if(tmp_cell && map[tmp_cell] >= 178) count++ - tmp_cell = get_map_cell(x,y-1) + TRANSLATE_AND_VERIFY_COORD(x,y-1) if(tmp_cell && map[tmp_cell] >= 178) count++ - tmp_cell = get_map_cell(x+1,y) + TRANSLATE_AND_VERIFY_COORD(x+1,y) if(tmp_cell && map[tmp_cell] >= 178) count++ - tmp_cell = get_map_cell(x,y+1) + TRANSLATE_AND_VERIFY_COORD(x,y+1) if(tmp_cell && map[tmp_cell] >= 178) count++ if(!count) map[current_cell] = 177 diff --git a/code/modules/random_map/noise/noise.dm b/code/modules/random_map/noise/noise.dm index 33cf03f5c7f..6b40f758086 100644 --- a/code/modules/random_map/noise/noise.dm +++ b/code/modules/random_map/noise/noise.dm @@ -83,7 +83,7 @@ map[TRANSLATE_COORD(x+isize,y)] \ )/2) - map[get_map_cell(x,y+hsize)] = round(( \ + map[TRANSLATE_COORD(x,y+hsize)] = round(( \ map[TRANSLATE_COORD(x,y+isize)] + \ map[TRANSLATE_COORD(x,y)] \ )/2) @@ -154,31 +154,55 @@ map = next_map if(smooth_single_tiles) - var/lonely for(var/x in 1 to limit_x - 1) for(var/y in 1 to limit_y - 1) - var/mapcell = get_map_cell(x,y) - var/list/neighbors = get_neighbors(x, y, TRUE) - lonely = TRUE - for(var/cell in neighbors) - if(get_appropriate_path(map[cell]) == get_appropriate_path(map[mapcell])) - lonely = FALSE - break - if(lonely) - map[mapcell] = map[pick(neighbors)] - + var/mapcell = TRANSLATE_COORD(x,y) + if(has_neighbor_with_path(x, y, get_appropriate_path(map[mapcell]), TRUE)) + continue + map[mapcell] = map[pick(get_neighbors(x, y, TRUE))] + +#define CHECK_NEIGHBOR_FOR_PATH(X, Y) \ + TRANSLATE_AND_VERIFY_COORD(X,Y);\ + if(tmp_cell && (get_appropriate_path(map[tmp_cell]) == path)) {\ + return TRUE;\ + } + +/// Checks if the cell at x,y has a neighbor with the given path. +/// Faster than looping over get_neighbors for the same purpose because it doesn't use list ops. +/datum/random_map/noise/proc/has_neighbor_with_path(x, y, path, include_diagonals) + var/tmp_cell + CHECK_NEIGHBOR_FOR_PATH(x-1,y) + CHECK_NEIGHBOR_FOR_PATH(x+1,y) + CHECK_NEIGHBOR_FOR_PATH(x,y+1) + CHECK_NEIGHBOR_FOR_PATH(x,y-1) + if(include_diagonals) + CHECK_NEIGHBOR_FOR_PATH(x+1,y+1) + CHECK_NEIGHBOR_FOR_PATH(x+1,y-1) + CHECK_NEIGHBOR_FOR_PATH(x-1,y-1) + CHECK_NEIGHBOR_FOR_PATH(x-1,y+1) + return FALSE + +#undef CHECK_NEIGHBOR_FOR_PATH + +#define VERIFY_AND_ADD_CELL(X, Y) \ + TRANSLATE_AND_VERIFY_COORD(X,Y);\ + if(tmp_cell) {\ + . += tmp_cell;\ + } + +/// Gets the neighbors of the cell at x, y, optionally including diagonals. +/// (x,y) and its neighbors can safely be invalid/not validated before calling. /datum/random_map/noise/proc/get_neighbors(x, y, include_diagonals) . = list() - if(!include_diagonals) - var/static/list/ortho_offsets = list(list(-1, 0), list(1, 0), list(0, 1), list(0,-1)) - for(var/list/offset in ortho_offsets) - var/tmp_cell = get_map_cell(x+offset[1],y+offset[2]) - if(tmp_cell) - . += tmp_cell - else - for(var/dx in -1 to 1) - for(var/dy in -1 to 1) - var/tmp_cell = get_map_cell(x+dx,y+dy) - if(tmp_cell) - . += tmp_cell - . -= get_map_cell(x,y) \ No newline at end of file + var/tmp_cell + VERIFY_AND_ADD_CELL(x-1,y) + VERIFY_AND_ADD_CELL(x+1,y) + VERIFY_AND_ADD_CELL(x,y+1) + VERIFY_AND_ADD_CELL(x,y-1) + if(include_diagonals) + VERIFY_AND_ADD_CELL(x+1,y+1) + VERIFY_AND_ADD_CELL(x+1,y-1) + VERIFY_AND_ADD_CELL(x-1,y-1) + VERIFY_AND_ADD_CELL(x-1,y+1) + +#undef VERIFY_AND_ADD_CELL \ No newline at end of file diff --git a/code/modules/random_map/noise/ore.dm b/code/modules/random_map/noise/ore.dm index 20e971700e5..d1f2f719b50 100644 --- a/code/modules/random_map/noise/ore.dm +++ b/code/modules/random_map/noise/ore.dm @@ -94,19 +94,19 @@ var/tmp_cell TRANSLATE_AND_VERIFY_COORD(x, y) - - var/spawning - if(tmp_cell < rare_val) - spawning = surface_metals - else if(tmp_cell < deep_val) - spawning = rare_metals - else - spawning = deep_metals - - for(var/val in spawning) - var/list/ranges = spawning[val] - resources[val] = rand(ranges[1], ranges[2]) - set_extension(T, /datum/extension/buried_resources, resources) + if(tmp_cell) + var/spawning + if(tmp_cell < rare_val) + spawning = surface_metals + else if(tmp_cell < deep_val) + spawning = rare_metals + else + spawning = deep_metals + + for(var/val in spawning) + var/list/ranges = spawning[val] + resources[val] = rand(ranges[1], ranges[2]) + set_extension(T, /datum/extension/buried_resources, resources) /datum/random_map/noise/ore/get_map_char(var/value) if(value < rare_val) diff --git a/code/modules/random_map/random_map.dm b/code/modules/random_map/random_map.dm index c0b3ce9fa9a..1919398f116 100644 --- a/code/modules/random_map/random_map.dm +++ b/code/modules/random_map/random_map.dm @@ -72,13 +72,6 @@ var/global/list/map_count = list() else admin_notice(SPAN_DANGER("[capitalize(name)] failed to generate ([round(0.1*(world.timeofday-start_time),0.1)] seconds): could not produce sane map."), R_DEBUG) -/datum/random_map/proc/get_map_cell(var/x,var/y) - if(!map) - set_map_size() - . = ((y-1)*limit_x)+x - if((. < 1) || (. > map.len)) - return null - /datum/random_map/proc/get_map_char(var/value) switch(value) if(WALL_CHAR) @@ -106,7 +99,7 @@ var/global/list/map_count = list() var/dat = "+------+
" for(var/x = 1, x <= limit_x, x++) for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) + var/current_cell = TRANSLATE_COORD(x,y) if(current_cell) dat += get_map_char(map[current_cell]) dat += "
" @@ -119,7 +112,7 @@ var/global/list/map_count = list() /datum/random_map/proc/seed_map() for(var/x = 1, x <= limit_x, x++) for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) + var/current_cell = TRANSLATE_COORD(x,y) if(prob(initial_wall_cell)) map[current_cell] = WALL_CHAR else @@ -128,7 +121,7 @@ var/global/list/map_count = list() /datum/random_map/proc/clear_map() for(var/x = 1, x <= limit_x, x++) for(var/y = 1, y <= limit_y, y++) - map[get_map_cell(x,y)] = 0 + map[TRANSLATE_COORD(x,y)] = 0 /datum/random_map/proc/generate() seed_map() @@ -165,7 +158,7 @@ var/global/list/map_count = list() apply_to_turf(x,y) /datum/random_map/proc/apply_to_turf(var/x,var/y) - var/current_cell = get_map_cell(x,y) + var/current_cell = TRANSLATE_COORD(x,y) if(!current_cell) return 0 var/turf/T = locate((origin_x-1)+x,(origin_y-1)+y,origin_z) @@ -201,14 +194,17 @@ var/global/list/map_count = list() ty-- // doesn't push it off-kilter by one. for(var/x = 1, x <= limit_x, x++) for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) + var/current_cell = TRANSLATE_COORD(x,y) if(!current_cell) continue if(tx+x > target_map.limit_x) continue if(ty+y > target_map.limit_y) continue - target_map.map[target_map.get_map_cell(tx+x,ty+y)] = map[current_cell] + var/tmp_cell + TRANSLATE_AND_VERIFY_COORD_MLEN(tx+x, ty+y, target_map.map.len) + if(tmp_cell) + target_map.map[tmp_cell] = map[current_cell] handle_post_overlay_on(target_map,tx,ty) From 4b121e6b7cff2041f95a797db701f7b793c9584d Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Tue, 31 Oct 2023 11:34:24 -0500 Subject: [PATCH 008/906] Add tag-based area atmos controller. Add circuitboard for tag scrubber control computer --- .../atmoalter/area_atmos_computer.dm | 28 +++++++++++++++++-- .../circuitboards/computer/computer.dm | 5 ++++ .../imprinter/designs_misc_circuits.dm | 5 +++- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/code/game/machinery/atmoalter/area_atmos_computer.dm b/code/game/machinery/atmoalter/area_atmos_computer.dm index 234285eb067..1f7b2dd927e 100644 --- a/code/game/machinery/atmoalter/area_atmos_computer.dm +++ b/code/game/machinery/atmoalter/area_atmos_computer.dm @@ -1,5 +1,5 @@ /obj/machinery/computer/area_atmos - name = "Area Air Control" + name = "area air control" desc = "A computer used to control the stationary scrubbers and pumps in the area." icon_keyboard = "atmos_key" icon_screen = "area_atmos" @@ -20,7 +20,7 @@ /obj/machinery/computer/area_atmos/interface_interact(user) interact(user) return TRUE - + /obj/machinery/computer/area_atmos/interact(mob/user) var/dat = {" @@ -173,3 +173,27 @@ status = "ERROR: No scrubber found!" src.updateUsrDialog() + +/obj/machinery/computer/area_atmos/tag + name = "heavy scrubber control" + zone = "This computer is operating industrial scrubbers nearby." + var/last_scan + +/obj/machinery/computer/area_atmos/tag/scanscrubbers() + if(last_scan && ((world.time - last_scan) < 20 SECONDS)) + return FALSE + else + last_scan = world.time + + connectedscrubbers.Cut() + + for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in SSmachines.machinery) + if(scrubber.id_tag == id_tag) + connectedscrubbers += scrubber + + updateUsrDialog() + +/obj/machinery/computer/area_atmos/tag/validscrubber(obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber) + if(scrubber.id_tag == id_tag) + return TRUE + return FALSE \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/computer/computer.dm b/code/game/objects/items/weapons/circuitboards/computer/computer.dm index c7dcc5ad3ca..62000c93bd6 100644 --- a/code/game/objects/items/weapons/circuitboards/computer/computer.dm +++ b/code/game/objects/items/weapons/circuitboards/computer/computer.dm @@ -97,6 +97,11 @@ build_path = /obj/machinery/computer/area_atmos origin_tech = "{'programming':2}" +/obj/item/stock_parts/circuitboard/tag_scrubber_control + name = "circuitboard (wireless scrubber control console)" + build_path = /obj/machinery/computer/area_atmos/tag + origin_tech = "{'programming':2}" + /obj/item/stock_parts/circuitboard/account_database name = "circuitboard (accounts uplink terminal)" build_path = /obj/machinery/computer/account_database diff --git a/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm b/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm index f26e6361ca5..11c03040a34 100644 --- a/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm +++ b/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm @@ -483,4 +483,7 @@ path = /obj/item/stock_parts/circuitboard/holomap /datum/fabricator_recipe/imprinter/circuit/geothermal_generator - path = /obj/item/stock_parts/circuitboard/geothermal \ No newline at end of file + path = /obj/item/stock_parts/circuitboard/geothermal + +/datum/fabricator_recipe/imprinter/circuit/tag_scrubber_control + path = /obj/item/stock_parts/circuitboard/tag_scrubber_control \ No newline at end of file From b192cbf39e386514f2c13b583c53daaa22b98531 Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Mon, 30 Oct 2023 23:05:31 -0500 Subject: [PATCH 009/906] Make integrated circuit printer use atom info repo --- code/modules/integrated_electronics/core/printer.dm | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/code/modules/integrated_electronics/core/printer.dm b/code/modules/integrated_electronics/core/printer.dm index 5ac88803f88..225ba85d98b 100644 --- a/code/modules/integrated_electronics/core/printer.dm +++ b/code/modules/integrated_electronics/core/printer.dm @@ -218,14 +218,8 @@ if(!build_type || !ispath(build_type)) return TRUE - var/list/cost - if(ispath(build_type, /obj/item/electronic_assembly)) - var/obj/item/electronic_assembly/E = SScircuit.cached_assemblies[build_type] - cost = E.matter - else if(ispath(build_type, /obj/item/integrated_circuit)) - var/obj/item/integrated_circuit/IC = SScircuit.cached_components[build_type] - cost = IC.matter - else if(!(build_type in SScircuit.circuit_fabricator_recipe_list["Tools"])) + var/list/cost = atom_info_repository.get_matter_for(build_type) + if(!ispath(build_type, /obj/item/electronic_assembly) && !ispath(build_type, /obj/item/integrated_circuit) && !(build_type in SScircuit.circuit_fabricator_recipe_list["Tools"])) return if(!debug && !subtract_material_costs(cost, usr)) From 91781986fb4cd9c23f5855a80cfa6edfda387849 Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Mon, 30 Oct 2023 23:07:09 -0500 Subject: [PATCH 010/906] Make get_breath use mob is_flooded --- code/modules/mob/living/living_breath.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/living_breath.dm b/code/modules/mob/living/living_breath.dm index 06a3150811d..b354bc045cf 100644 --- a/code/modules/mob/living/living_breath.dm +++ b/code/modules/mob/living/living_breath.dm @@ -57,8 +57,8 @@ // First handle being in a submerged environment. var/datum/gas_mixture/breath - var/turf/my_turf = get_turf(src) - if(istype(my_turf) && my_turf.is_flooded(lying)) + if(is_flooded(lying)) + var/turf/my_turf = get_turf(src) //Can we get air from the turf above us? var/can_breathe_air_above = FALSE From 4d704f17ab08965b4a6e80be384d4261d392f0a4 Mon Sep 17 00:00:00 2001 From: NebulaSS13Bot Date: Mon, 6 Nov 2023 00:37:23 +0000 Subject: [PATCH 011/906] Automatic changelog generation [ci skip] --- html/changelog.html | 6 ------ 1 file changed, 6 deletions(-) diff --git a/html/changelog.html b/html/changelog.html index c6c50cf62f4..2e457929dfd 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -98,12 +98,6 @@

NataKilar updated:

  • Fixed water tanks being unable to be refilled
- -

04 September 2023

-

LenSkozzy updated:

-
    -
  • fixed folding@home
  • -
From d095fcb52e2c66f5f4fe7b21c3a527cf6149176c Mon Sep 17 00:00:00 2001 From: Lohikar Date: Fri, 22 Sep 2023 15:23:53 -0500 Subject: [PATCH 012/906] Z-Mimic: Synchronize with upstream --- code/__defines/zmimic.dm | 29 +- code/controllers/subsystems/zcopy.dm | 325 +++++++++++++++----- code/game/atoms_movable.dm | 9 + code/game/turfs/turf_enter.dm | 6 +- code/modules/multiz/zmimic/mimic_movable.dm | 28 +- 5 files changed, 299 insertions(+), 98 deletions(-) diff --git a/code/__defines/zmimic.dm b/code/__defines/zmimic.dm index 5f679f43597..c509012f8ab 100644 --- a/code/__defines/zmimic.dm +++ b/code/__defines/zmimic.dm @@ -1,7 +1,28 @@ +#define ZM_DESTRUCTION_TIMER(TARGET) addtimer(CALLBACK(TARGET, /datum/.proc/qdel_self), 10 SECONDS, TIMER_STOPPABLE) #define TURF_IS_MIMICKING(T) (isturf(T) && (T:z_flags & ZM_MIMIC_BELOW)) -#define CHECK_OO_EXISTENCE(OO) if (OO && !TURF_IS_MIMICKING(OO.loc)) { qdel(OO); } +#define CHECK_OO_EXISTENCE(OO) if (OO && !MOVABLE_IS_ON_ZTURF(OO) && !OO.destruction_timer) { OO.destruction_timer = ZM_DESTRUCTION_TIMER(OO); } #define UPDATE_OO_IF_PRESENT CHECK_OO_EXISTENCE(bound_overlay); if (bound_overlay) { update_above(); } +// I do not apologize. + +// These aren't intended to be used anywhere else, they just can't be undef'd because DM is dum. +#define ZM_INTERNAL_SCAN_LOOKAHEAD(M,VTR,F) ((get_step(M, M:dir)?:VTR & F) || (get_step(M, turn(M:dir, 180))?:VTR & F)) +#define ZM_INTERNAL_SCAN_LOOKBESIDE(M,VTR,F) ((get_step(M, turn(M:dir, 90))?:VTR & F) || (get_step(M, turn(M:dir, -90))?:VTR & F)) + +/// Is this movable visible from a turf that is mimicking below? Note: this does not necessarily mean *directly* below. +#define MOVABLE_IS_BELOW_ZTURF(M) (\ + isturf(M:loc) && (TURF_IS_MIMICKING(M:loc:above) \ + || ((M:z_flags & ZMM_LOOKAHEAD) && ZM_INTERNAL_SCAN_LOOKAHEAD(M, above?:z_flags, ZM_MIMIC_BELOW)) \ + || ((M:z_flags & ZMM_LOOKBESIDE) && ZM_INTERNAL_SCAN_LOOKBESIDE(M, above?:z_flags, ZM_MIMIC_BELOW))) \ +) +/// Is this movable located on a turf that is mimicking below? Note: this does not necessarily mean *directly* on. +#define MOVABLE_IS_ON_ZTURF(M) (\ + isturf(M:loc) && (TURF_IS_MIMICKING(M:loc:above) \ + || ((M:z_flags & ZMM_LOOKAHEAD) && ZM_INTERNAL_SCAN_LOOKAHEAD(M, z_flags, ZM_MIMIC_BELOW)) \ + || ((M:z_flags & ZMM_LOOKBESIDE) && ZM_INTERNAL_SCAN_LOOKBESIDE(M, z_flags, ZM_MIMIC_BELOW))) \ +) +#define MOVABLE_SHALL_MIMIC(AM) (!(AM.z_flags & ZMM_IGNORE) && MOVABLE_IS_BELOW_ZTURF(AM)) + // Turf MZ flags. #define ZM_MIMIC_BELOW 1 //! If this turf should mimic the turf on the Z below. #define ZM_MIMIC_OVERWRITE 2 //! If this turf is Z-mimicking, overwrite the turf's appearance instead of using a movable. This is faster, but means the turf cannot have its own appearance (say, edges or a translucent sprite). @@ -26,5 +47,7 @@ var/global/list/mimic_defines = list( ) // Movable flags. -#define ZMM_IGNORE 1 //! Do not copy this movable. -#define ZMM_MANGLE_PLANES 2 //! Check this movable's overlays/underlays for explicit plane use and mangle for compatibility with Z-Mimic. If you're using emissive overlays, you probably should be using this flag. Expensive, only use if necessary. +#define ZMM_IGNORE 1 //! Do not copy this movable. +#define ZMM_MANGLE_PLANES 2 //! Check this movable's overlays/underlays for explicit plane use and mangle for compatibility with Z-Mimic. If you're using emissive overlays, you probably should be using this flag. Expensive, only use if necessary. +#define ZMM_LOOKAHEAD 3 //! Look one turf ahead and one turf back when considering z-turfs that might be seeing this atom. Cheap, but not free. +#define ZMM_LOOKBESIDE 4 //! Look one turf beside (left/right) when considering z-turfs that might be seeing this atom. Cheap, but not free. diff --git a/code/controllers/subsystems/zcopy.dm b/code/controllers/subsystems/zcopy.dm index fdadc76814b..0bf66080ab7 100644 --- a/code/controllers/subsystems/zcopy.dm +++ b/code/controllers/subsystems/zcopy.dm @@ -9,6 +9,18 @@ #define SHADOWER_DARKENING_FACTOR 0.6 // The multiplication factor for openturf shadower darkness. Lighting will be multiplied by this. #define SHADOWER_DARKENING_COLOR "#999999" // The above, but as an RGB string for lighting-less turfs. +//#define ZM_RECORD_STATS // This doesn't work on O7/Neb right now. + +#ifdef ZM_RECORD_STATS +#define ZM_RECORD_START STAT_START_STOPWATCH +#define ZM_RECORD_STOP STAT_STOP_STOPWATCH +#define ZM_RECORD_WRITE(X...) STAT_LOG_ENTRY(##X) +#else +#define ZM_RECORD_START +#define ZM_RECORD_STOP +#define ZM_RECORD_WRITE(X...) +#endif + SUBSYSTEM_DEF(zcopy) name = "Z-Copy" wait = 1 @@ -25,8 +37,19 @@ SUBSYSTEM_DEF(zcopy) var/openspace_turfs = 0 var/multiqueue_skips_turf = 0 + var/multiqueue_skips_discovery = 0 var/multiqueue_skips_object = 0 + var/total_updates_turf = 0 + var/total_updates_discovery = 0 + var/total_updates_object = 0 + +#ifdef ZM_RECORD_STATS + var/list/turf_stats = list() + var/list/discovery_stats = list() + var/list/mimic_stats = list() +#endif + // Highest Z level in a given Z-group for absolute layering. // zstm[zlev] = group_max var/list/zlev_maximums = list() @@ -108,14 +131,38 @@ SUBSYSTEM_DEF(zcopy) /datum/controller/subsystem/zcopy/stat_entry() var/list/entries = list( - "Mx:[json_encode(zlev_maximums)]", + "", // newline + "ZSt: [build_zstack_display()]", // This is a human-readable list of the z-stacks known to ZM. + "ZMx: [zlev_maximums.Join(", ")]", // And this is the raw internal state. + // This one gets broken out from the below because it's more important. "Q: { T: [queued_turfs.len - (qt_idex - 1)] O: [queued_overlays.len - (qo_idex - 1)] }", - "T: { T: [openspace_turfs] O: [openspace_overlays] }", - "Sk: { T: [multiqueue_skips_turf] O: [multiqueue_skips_object] }", + // In order: Total, Queued, Skipped + "T(O): { T: [openspace_turfs] O: [openspace_overlays] }", + "T(U): { T: [total_updates_turf] D: [total_updates_discovery] O: [total_updates_object] }", + "Sk: { T: [multiqueue_skips_turf] D: [multiqueue_skips_discovery] O: [multiqueue_skips_object] }", "F: { H: [fixup_hit] M: [fixup_miss] N: [fixup_noop] FC: [fixup_cache.len] FKG: [fixup_known_good.len] }" ) ..(entries.Join("\n\t")) +// 1, 2, 3..=7, 8 +/datum/controller/subsystem/zcopy/proc/build_zstack_display() + if (!zlev_maximums.len) + return "" + var/list/zmx = list() + var/idx = 1 + var/span_ctr = 0 + do + if (zlev_maximums[idx] != idx) + span_ctr += 1 + else if (span_ctr) + zmx += "[idx - span_ctr]..=[idx]" + span_ctr = 0 + else + zmx += "[idx]" + idx += 1 + while (idx <= zlev_maximums.len) + return jointext(zmx, ", ") + /datum/controller/subsystem/zcopy/Initialize(timeofday) calculate_zstack_limits() // Flush the queue. @@ -169,8 +216,16 @@ SUBSYSTEM_DEF(zcopy) if (!no_mc_tick) MC_SPLIT_TICK + tick_turfs(no_mc_tick) + + if (!no_mc_tick) + MC_SPLIT_TICK + + tick_mimic(no_mc_tick) + +// - Turf mimic - +/datum/controller/subsystem/zcopy/proc/tick_turfs(no_mc_tick) var/list/curr_turfs = queued_turfs - var/list/curr_ov = queued_overlays while (qt_idex <= curr_turfs.len) var/turf/T = curr_turfs[qt_idex] @@ -188,6 +243,7 @@ SUBSYSTEM_DEF(zcopy) if (T.z_queued > 1) T.z_queued -= 1 multiqueue_skips_turf += 1 + if (no_mc_tick) CHECK_TICK else if (MC_TICK_CHECK) @@ -197,12 +253,23 @@ SUBSYSTEM_DEF(zcopy) // Z-Turf on the bottom-most level, just fake-copy space (or baseturf). // It's impossible for anything to be on the synthetic turf, so ignore the rest of the ZM machinery. if (!T.below) + ZM_RECORD_START flush_z_state(T) if (T.z_flags & ZM_MIMIC_BASETURF) simple_appearance_copy(T, get_base_turf_by_area(T), OPENTURF_MAX_PLANE) else simple_appearance_copy(T, SSskybox.dust_cache["[((T.x + T.y) ^ ~(T.x * T.y) + T.z) % 25]"]) + T.z_generation += 1 + T.z_queued -= 1 + total_updates_turf += 1 + + if (T.above) + T.above.update_mimic() + + ZM_RECORD_STOP + ZM_RECORD_WRITE(turf_stats, "Fake: [T.type] on [T.z]") + if (no_mc_tick) CHECK_TICK else if (MC_TICK_CHECK) @@ -215,9 +282,12 @@ SUBSYSTEM_DEF(zcopy) T.z_generation += 1 + ZM_RECORD_START + // Get the bottom-most turf, the one we want to mimic. + // Baseturf mimics act as false bottoms of the stack. var/turf/Td = T - while (Td.below) + while (Td.below && !(Td.z_flags & ZM_MIMIC_BASETURF)) Td = Td.below // Depth must be the depth of the *visible* turf, not self. @@ -231,6 +301,15 @@ SUBSYSTEM_DEF(zcopy) flush_z_state(T) simple_appearance_copy(T, get_base_turf_by_area(T), t_target) + if (T.above) + T.above.update_mimic() + + total_updates_turf += 1 + T.z_queued -= 1 + + ZM_RECORD_STOP + ZM_RECORD_WRITE(turf_stats, "Simple: [T.type] on [T.z]") + if (no_mc_tick) CHECK_TICK else if (MC_TICK_CHECK) @@ -286,11 +365,16 @@ SUBSYSTEM_DEF(zcopy) // Handle below atoms. - // Add everything below us to the update queue. + // Add everything below us to the discovery queue. for (var/thing in T.below) var/atom/movable/object = thing if (QDELETED(object) || (object.z_flags & ZMM_IGNORE) || object.loc != T.below || object.invisibility == INVISIBILITY_ABSTRACT) - // Don't queue deleted stuff, stuff that's not visible, blacklisted stuff, or stuff that's centered on another tile but intersects ours. + /* Don't queue: + - (q)deleted objects + - Explicitly ignored objects + - Objects not rooted on this turf (multitiles) + - Always-invisible atoms + */ continue // Special case: these are merged into the shadower to reduce memory usage. @@ -298,63 +382,20 @@ SUBSYSTEM_DEF(zcopy) T.shadower.copy_lighting(object) continue - if (!object.bound_overlay) // Generate a new overlay if the atom doesn't already have one. - object.bound_overlay = new(T) - object.bound_overlay.associated_atom = object - - var/override_depth - var/original_type = object.type - var/original_z = object.z - var/have_performed_fixup = FALSE - - switch (object.type) - // Layering for recursive mimic needs to be inherited. - if (/atom/movable/openspace/mimic) - var/atom/movable/openspace/mimic/OOO = object - original_type = OOO.mimiced_type - override_depth = OOO.override_depth - original_z = OOO.original_z - have_performed_fixup = OOO.have_performed_fixup - - // If this is a turf proxy (the mimic for a non-OVERWRITE turf), it needs to respect space parallax if relevant. - if (/atom/movable/openspace/turf_proxy) - if (T.z_eventually_space) - // Yes, this is an awful hack; I don't want to add yet another override_* var. - override_depth = OPENTURF_MAX_PLANE - SPACE_PLANE - - if (/atom/movable/openspace/turf_mimic) - original_z += 1 - - var/atom/movable/openspace/mimic/OO = object.bound_overlay - - // If the OO was queued for destruction but was claimed by another OT, stop the destruction timer. - if (OO.destruction_timer) - deltimer(OO.destruction_timer) - OO.destruction_timer = null - - OO.depth = override_depth || min(zlev_maximums[T.z] - original_z, OPENTURF_MAX_DEPTH) - - // These types need to be pushed a layer down for bigturfs to function correctly. - switch (original_type) - if (/atom/movable/openspace/multiplier, /atom/movable/openspace/turf_proxy) - if (OO.depth < OPENTURF_MAX_DEPTH) - OO.depth += 1 - - OO.mimiced_type = original_type - OO.override_depth = override_depth - OO.original_z = original_z - OO.have_performed_fixup ||= have_performed_fixup - - // Multi-queue to maintain ordering of updates to these - // queueing it multiple times will result in only the most recent - // actually processing. - OO.queued += 1 - queued_overlays += OO + // If an atom already has an overlay, we probably don't need to discover it again. + // ...but we need to force it if the object was salvaged from another zturf. + if (!object.bound_overlay || object.bound_overlay.destruction_timer) + discover_movable(object, T) T.z_queued -= 1 if (T.above) T.above.update_mimic() + total_updates_turf += 1 + + ZM_RECORD_STOP + ZM_RECORD_WRITE(turf_stats, "Complex: [T.type] on [T.z]") + if (no_mc_tick) CHECK_TICK else if (MC_TICK_CHECK) @@ -364,9 +405,9 @@ SUBSYSTEM_DEF(zcopy) curr_turfs.Cut(1, qt_idex) qt_idex = 1 - if (!no_mc_tick) - MC_SPLIT_TICK - +// - Phase: Mimic update -- actually update the mimics' appearance, order sensitive - +/datum/controller/subsystem/zcopy/proc/tick_mimic(no_mc_tick) + var/list/curr_ov = queued_overlays while (qo_idex <= curr_ov.len) var/atom/movable/openspace/mimic/OO = curr_ov[qo_idex] curr_ov[qo_idex] = null @@ -379,8 +420,9 @@ SUBSYSTEM_DEF(zcopy) break continue - if (QDELETED(OO.associated_atom)) // This shouldn't happen, but just in-case. + if (QDELETED(OO.associated_atom)) // This shouldn't happen. qdel(OO) + log_debug("Z-Mimic: Received mimic with QDELETED parent ([OO.associated_atom || ""])") if (no_mc_tick) CHECK_TICK @@ -392,21 +434,24 @@ SUBSYSTEM_DEF(zcopy) if (OO.queued > 1) OO.queued -= 1 multiqueue_skips_object += 1 + if (no_mc_tick) CHECK_TICK else if (MC_TICK_CHECK) break continue + ZM_RECORD_START + // Actually update the overlay. if (OO.dir != OO.associated_atom.dir) - OO.set_dir(OO.associated_atom.dir) + OO.dir = OO.associated_atom.dir // updates are propagated up another way, don't use set_dir + OO.appearance = OO.associated_atom + OO.z_flags = OO.associated_atom.z_flags if (OO.particles != OO.associated_atom.particles) OO.particles = OO.associated_atom.particles - OO.appearance = OO.associated_atom - OO.z_flags = OO.associated_atom.z_flags OO.plane = OPENTURF_MAX_PLANE - OO.depth OO.opacity = FALSE @@ -422,6 +467,11 @@ SUBSYSTEM_DEF(zcopy) if (OO.bound_overlay) // If we have a bound overlay, queue it too. OO.update_above() + total_updates_object += 1 + + ZM_RECORD_STOP + ZM_RECORD_WRITE(mimic_stats, OO.mimiced_type) + if (no_mc_tick) CHECK_TICK else if (MC_TICK_CHECK) @@ -431,14 +481,85 @@ SUBSYSTEM_DEF(zcopy) curr_ov.Cut(1, qo_idex) qo_idex = 1 +// return: is-invalid +/datum/controller/subsystem/zcopy/proc/discover_movable(atom/movable/object) + ASSERT(!QDELETED(object)) + + var/turf/Tloc = object.loc + if (!isturf(Tloc) || !Tloc.above) + return TRUE + + var/turf/T = Tloc.above + + ZM_RECORD_START + + if (!object.bound_overlay) + var/atom/movable/openspace/mimic/M = new(T) + object.bound_overlay = M + M.associated_atom = object + if (TURF_IS_MIMICKING(M.loc)) + .(M) + + var/override_depth + var/original_type = object.type + var/original_z = object.z + + switch (object.type) + // Layering for recursive mimic needs to be inherited. + if (/atom/movable/openspace/mimic) + var/atom/movable/openspace/mimic/OOO = object + original_type = OOO.mimiced_type + override_depth = OOO.override_depth + original_z = OOO.original_z + + // If this is a turf proxy (the mimic for a non-OVERWRITE turf), it needs to respect space parallax if relevant. + if (/atom/movable/openspace/turf_proxy) + if (T.z_eventually_space) + // Yes, this is an awful hack; I don't want to add yet another override_* var. + override_depth = OPENTURF_MAX_PLANE - SPACE_PLANE + + var/atom/movable/openspace/mimic/OO = object.bound_overlay + + // If the OO was queued for destruction but was claimed by another OT, stop the destruction timer. + if (OO.destruction_timer) + deltimer(OO.destruction_timer) + OO.destruction_timer = null + + OO.depth = override_depth || min(zlev_maximums[T.z] - original_z, OPENTURF_MAX_DEPTH) + + switch (original_type) + // These types need to be pushed a layer down for bigturfs to function correctly. + if (/atom/movable/openspace/turf_proxy, /atom/movable/openspace/turf_mimic) + OO.depth += 1 + if (/atom/movable/openspace/multiplier) + OO.depth += 1 + + OO.mimiced_type = original_type + OO.override_depth = override_depth + OO.original_z = original_z + + // Multi-queue to maintain ordering of updates to these + // queueing it multiple times will result in only the most recent + // actually processing. + OO.queued += 1 + queued_overlays += OO + + total_updates_discovery += 1 + + ZM_RECORD_STOP + ZM_RECORD_WRITE(discovery_stats, "Depth [OO.depth] on [OO.z]") + + return FALSE + /datum/controller/subsystem/zcopy/proc/flush_z_state(turf/T) - if (T.below.mimic_above_copy) - QDEL_NULL(T.below.mimic_above_copy) - if (T.below.mimic_proxy) - QDEL_NULL(T.below.mimic_proxy) - for (var/atom/movable/openspace/OO in T) - if (istype(OO, /atom/movable/openspace/mimic)) - qdel(OO) + if (T.below) // Z-Mimic turfs aren't necessarily above another turf. + if (T.below.mimic_above_copy) + QDEL_NULL(T.below.mimic_above_copy) + if (T.below.mimic_proxy) + QDEL_NULL(T.below.mimic_proxy) + QDEL_NULL(T.mimic_underlay) + for (var/atom/movable/openspace/mimic/OO in T) + qdel(OO) /datum/controller/subsystem/zcopy/proc/simple_appearance_copy(turf/T, new_appearance, target_plane) if (T.z_flags & ZM_MIMIC_OVERWRITE) @@ -523,7 +644,7 @@ SUBSYSTEM_DEF(zcopy) fixed_underlays[i] = fixed_appearance if (mutated) - for (var/i in 1 to fixed_overlays.len) + for (var/i in 1 to fixed_underlays.len) if (fixed_underlays[i] == null) fixed_underlays[i] = appearance:underlays[i] @@ -551,6 +672,7 @@ SUBSYSTEM_DEF(zcopy) return MA #define FMT_DEPTH(X) (X == null ? "(null)" : X) +#define FMT_OK(X) (X) ? "OK" : "MISMATCH" // This is a dummy object used so overlays can be shown in the analyzer. /atom/movable/openspace/debug @@ -583,7 +705,7 @@ SUBSYSTEM_DEF(zcopy) "", "

Analysis of [T] at [T.x],[T.y],[T.z]

", "Queue occurrences: [T.z_queued]", - "Above space: Apparent [T.z_eventually_space ? "Yes" : "No"], Actual [is_above_space ? "Yes" : "No"] - [T.z_eventually_space == is_above_space ? "OK" : "MISMATCH"]", + "Above space: Apparent [T.z_eventually_space ? "Yes" : "No"], Actual [is_above_space ? "Yes" : "No"] - [FMT_OK(T.z_eventually_space == is_above_space)]", "Z Flags: [english_list(bitfield2list(T.z_flags, global.mimic_defines), "(none)")]", "Has Shadower: [T.shadower ? "Yes" : "No"]", "Has turf proxy: [T.mimic_proxy ? "Yes" : "No"]", @@ -592,11 +714,13 @@ SUBSYSTEM_DEF(zcopy) "Below: [!T.below ? "(nothing)" : "[T.below] at [T.below.x],[T.below.y],[T.below.z]"]", "Depth: [FMT_DEPTH(T.z_depth)] [T.z_depth == OPENTURF_MAX_DEPTH ? "(max)" : ""]", "Generation: [T.z_generation]", - "Update count: Claimed [claimed_update_count], Actual [real_update_count] - [claimed_update_count == real_update_count ? "OK" : "MISMATCH"]", + "Update count: Claimed [claimed_update_count], Actual [real_update_count] - [FMT_OK(claimed_update_count == real_update_count)]", "