From c95e73f61ebdc090ca99eeaee3bd2c705487c8ff Mon Sep 17 00:00:00 2001 From: dj-34 Date: Wed, 14 Dec 2022 22:50:55 +0500 Subject: [PATCH] FIx: Map Conflict Fixer & DMI Conflict Fixer (#1706) * Fix: Map conflict fixer & DMI conflict fixer * Add: Merge Conflict Marker --- code/game/objects/effects/mapping_helpers.dm | 18 + icons/effects/mapping_helpers.dmi | Bin 6712 -> 7346 bytes .../Scripts/17259_dirbump_part1.txt | 6 + .../Scripts/17259_dirbump_part2.txt | 24 + .../Scripts/17980_rust_converter.txt | 2 + .../19252_newscaster_directionality.txt | 8 + tools/UpdatePaths/Scripts/19351_bushes.txt | 3 + tools/UpdatePaths/Update_Paths.bat | 3 + .../__main__.py} | 78 +- tools/UpdatePaths/readme.md | 32 + tools/bootstrap/node | 73 -- tools/bootstrap/node.bat | 20 - tools/bootstrap/node_.ps1 | 58 -- tools/bootstrap/python37._pth | 1 - tools/dmi/resolve_icon_conflicts.sh | 2 - tools/dmitool/README.txt | 5 - tools/dmitool/build.gradle | 16 - tools/dmitool/dmimerge.sh | 8 - tools/dmitool/dmisort.sh | 21 - tools/dmitool/dmitool.jar | Bin 202277 -> 0 bytes tools/dmitool/dmitool.py | 94 --- tools/dmitool/git_merge_installer.bat | 6 - tools/dmitool/git_merge_installer.sh | 6 - tools/dmitool/merging.txt | 14 - tools/dmitool/src/main/java/dmitool/DMI.java | 455 ------------ .../src/main/java/dmitool/DMIDiff.java | 194 ----- .../src/main/java/dmitool/DMIException.java | 24 - .../src/main/java/dmitool/IconState.java | 280 ------- .../src/main/java/dmitool/IconStateDiff.java | 126 ---- .../dmitool/src/main/java/dmitool/Image.java | 32 - tools/dmitool/src/main/java/dmitool/Main.java | 513 ------------- .../main/java/dmitool/NonPalettedImage.java | 14 - .../src/main/java/dmitool/PNGChunk.java | 27 - .../src/main/java/dmitool/PalettedImage.java | 16 - tools/dmitool/src/main/java/dmitool/RGBA.java | 33 - tools/hooks/install.py | 7 +- tools/hooks/merge_frontend.py | 7 +- tools/hooks/python.sh | 4 +- .../Run Icon Conflict Fixer.bat | 4 - tools/icon_merge_tool/icon_merge_tool.py | 87 --- tools/map_conflict_fixer/README.md | 29 - .../Run Map Conflict Fixer - DMM.bat | 4 - .../map_conflict_fixer/map_conflict_fixer.py | 111 --- tools/map_conflict_fixer/map_helpers.py | 687 ------------------ tools/mapmerge2-old/Prepare Maps.bat | 12 - tools/mapmerge2-old/README.md | 52 -- tools/mapmerge2-old/convert.py | 8 - tools/mapmerge2-old/dmi.py | 253 ------- tools/mapmerge2-old/dmm.py | 554 -------------- tools/mapmerge2-old/dmm2tgm.bat | 5 - tools/mapmerge2-old/frontend.py | 127 ---- .../mapmerge2-old/map_scripts/cornersfix.txt | 30 - .../map_scripts/turfs2decals.txt | 465 ------------ tools/mapmerge2-old/mapmerge.bat | 5 - tools/mapmerge2-old/mapmerge.py | 94 --- tools/mapmerge2-old/merge_driver_dmi.py | 177 ----- tools/mapmerge2-old/precommit.py | 57 -- tools/mapmerge2-old/requirements-install.bat | 3 - tools/mapmerge2-old/requirements.txt | 3 - tools/mapmerge2-old/tgm2dmm.bat | 5 - tools/mapmerge2-old/update_paths.py | 163 ----- ...ap Merge.bat => I_Forgot_To_Map_Merge.bat} | 0 tools/mapmerge2/Prepare Maps.bat | 12 - tools/mapmerge2/README.md | 39 +- ...onflicts.bat => Resolve_Map_Conflicts.bat} | 0 ...mmitting.bat => Run_Before_Committing.bat} | 0 tools/mapmerge2/convert.py | 5 +- tools/mapmerge2/dmi.py | 253 ------- tools/mapmerge2/dmm.py | 95 ++- tools/mapmerge2/dmm2tgm.bat | 5 - tools/mapmerge2/dmm_test.py | 3 +- tools/mapmerge2/fixup.py | 3 +- tools/mapmerge2/map_scripts/cornersfix.txt | 30 - tools/mapmerge2/map_scripts/turfs2decals.txt | 465 ------------ tools/mapmerge2/mapmerge.bat | 5 - tools/mapmerge2/mapmerge.py | 6 +- tools/mapmerge2/merge_driver.py | 10 +- tools/mapmerge2/merge_driver_dmi.py | 177 ----- tools/mapmerge2/precommit.py | 32 +- tools/mapmerge2/requirements-install.bat | 3 - tools/mapmerge2/requirements.txt | 3 - tools/mapmerge2/tgm2dmm.bat | 5 - tools/oldChangelog/README.MD | 3 - .../oldChangelog/github_webhook_processor.php | 355 --------- tools/oldChangelog/makeChangelog.bat | 5 - tools/oldChangelog/ss13_genchangelog.py | 217 ------ 86 files changed, 275 insertions(+), 6621 deletions(-) create mode 100644 tools/UpdatePaths/Scripts/17259_dirbump_part1.txt create mode 100644 tools/UpdatePaths/Scripts/17259_dirbump_part2.txt create mode 100644 tools/UpdatePaths/Scripts/17980_rust_converter.txt create mode 100644 tools/UpdatePaths/Scripts/19252_newscaster_directionality.txt create mode 100644 tools/UpdatePaths/Scripts/19351_bushes.txt create mode 100644 tools/UpdatePaths/Update_Paths.bat rename tools/{mapmerge2/update_paths.py => UpdatePaths/__main__.py} (67%) mode change 100755 => 100644 create mode 100644 tools/UpdatePaths/readme.md delete mode 100755 tools/bootstrap/node delete mode 100644 tools/bootstrap/node.bat delete mode 100644 tools/bootstrap/node_.ps1 delete mode 100755 tools/dmi/resolve_icon_conflicts.sh delete mode 100644 tools/dmitool/README.txt delete mode 100644 tools/dmitool/build.gradle delete mode 100644 tools/dmitool/dmimerge.sh delete mode 100644 tools/dmitool/dmisort.sh delete mode 100644 tools/dmitool/dmitool.jar delete mode 100644 tools/dmitool/dmitool.py delete mode 100644 tools/dmitool/git_merge_installer.bat delete mode 100644 tools/dmitool/git_merge_installer.sh delete mode 100644 tools/dmitool/merging.txt delete mode 100644 tools/dmitool/src/main/java/dmitool/DMI.java delete mode 100644 tools/dmitool/src/main/java/dmitool/DMIDiff.java delete mode 100644 tools/dmitool/src/main/java/dmitool/DMIException.java delete mode 100644 tools/dmitool/src/main/java/dmitool/IconState.java delete mode 100644 tools/dmitool/src/main/java/dmitool/IconStateDiff.java delete mode 100644 tools/dmitool/src/main/java/dmitool/Image.java delete mode 100644 tools/dmitool/src/main/java/dmitool/Main.java delete mode 100644 tools/dmitool/src/main/java/dmitool/NonPalettedImage.java delete mode 100644 tools/dmitool/src/main/java/dmitool/PNGChunk.java delete mode 100644 tools/dmitool/src/main/java/dmitool/PalettedImage.java delete mode 100644 tools/dmitool/src/main/java/dmitool/RGBA.java delete mode 100644 tools/icon_merge_tool/Run Icon Conflict Fixer.bat delete mode 100644 tools/icon_merge_tool/icon_merge_tool.py delete mode 100644 tools/map_conflict_fixer/README.md delete mode 100644 tools/map_conflict_fixer/Run Map Conflict Fixer - DMM.bat delete mode 100644 tools/map_conflict_fixer/map_conflict_fixer.py delete mode 100644 tools/map_conflict_fixer/map_helpers.py delete mode 100644 tools/mapmerge2-old/Prepare Maps.bat delete mode 100644 tools/mapmerge2-old/README.md delete mode 100644 tools/mapmerge2-old/convert.py delete mode 100644 tools/mapmerge2-old/dmi.py delete mode 100644 tools/mapmerge2-old/dmm.py delete mode 100644 tools/mapmerge2-old/dmm2tgm.bat delete mode 100644 tools/mapmerge2-old/frontend.py delete mode 100644 tools/mapmerge2-old/map_scripts/cornersfix.txt delete mode 100644 tools/mapmerge2-old/map_scripts/turfs2decals.txt delete mode 100644 tools/mapmerge2-old/mapmerge.bat delete mode 100644 tools/mapmerge2-old/mapmerge.py delete mode 100644 tools/mapmerge2-old/merge_driver_dmi.py delete mode 100644 tools/mapmerge2-old/precommit.py delete mode 100644 tools/mapmerge2-old/requirements-install.bat delete mode 100644 tools/mapmerge2-old/requirements.txt delete mode 100644 tools/mapmerge2-old/tgm2dmm.bat delete mode 100644 tools/mapmerge2-old/update_paths.py rename tools/mapmerge2/{I Forgot To Map Merge.bat => I_Forgot_To_Map_Merge.bat} (100%) delete mode 100644 tools/mapmerge2/Prepare Maps.bat rename tools/mapmerge2/{Resolve Map Conflicts.bat => Resolve_Map_Conflicts.bat} (100%) rename tools/mapmerge2/{Run Before Committing.bat => Run_Before_Committing.bat} (100%) delete mode 100755 tools/mapmerge2/dmi.py delete mode 100644 tools/mapmerge2/dmm2tgm.bat delete mode 100644 tools/mapmerge2/map_scripts/cornersfix.txt delete mode 100644 tools/mapmerge2/map_scripts/turfs2decals.txt delete mode 100644 tools/mapmerge2/mapmerge.bat delete mode 100755 tools/mapmerge2/merge_driver_dmi.py delete mode 100644 tools/mapmerge2/requirements-install.bat delete mode 100644 tools/mapmerge2/requirements.txt delete mode 100644 tools/mapmerge2/tgm2dmm.bat delete mode 100644 tools/oldChangelog/README.MD delete mode 100644 tools/oldChangelog/github_webhook_processor.php delete mode 100644 tools/oldChangelog/makeChangelog.bat delete mode 100644 tools/oldChangelog/ss13_genchangelog.py diff --git a/code/game/objects/effects/mapping_helpers.dm b/code/game/objects/effects/mapping_helpers.dm index f71c64a3b69..1ce62ae880c 100644 --- a/code/game/objects/effects/mapping_helpers.dm +++ b/code/game/objects/effects/mapping_helpers.dm @@ -101,3 +101,21 @@ T.light_power = light_power T.light_range = light_range . = ..() + +// Used by mapmerge2 to denote the existence of a merge conflict (or when it has to complete a "best intent" merge where it dumps the movable contents of an old key and a new key on the same tile). +// We define it explicitly here to ensure that it shows up on the highest possible plane (while giving off a verbose icon) to aide mappers in resolving these conflicts. +// DO NOT USE THIS IN NORMAL MAPPING!!! Linters WILL fail. + +/obj/merge_conflict_marker + name = "Merge Conflict Marker - DO NOT USE" + icon = 'icons/effects/mapping_helpers.dmi' + icon_state = "merge_conflict_marker" + desc = "If you are seeing this in-game: someone REALLY, REALLY, REALLY fucked up. Please make an issue report on GitHub or contact a coder as soon as possible." + plane = POINT_LAYER + +///We REALLY do not want un-addressed merge conflicts in maps for an inexhaustible list of reasons. This should help ensure that this will not be missed in case linters fail to catch it for any reason what-so-ever. +/obj/merge_conflict_marker/Initialize(mapload) + . = ..() + var/msg = "HEY, LISTEN!!! Merge Conflict Marker detected at [AREACOORD(src)]! Please manually address all potential merge conflicts!!!" + warning(msg) + to_chat(world, "[msg]") diff --git a/icons/effects/mapping_helpers.dmi b/icons/effects/mapping_helpers.dmi index 076b18b304fccd178af3a9f096d1ced9fb87d811..a17310f323250471d16e3871261e71c8687eb2e5 100644 GIT binary patch literal 7346 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 PNPx0}hJ2;0Mfm>#Kr1=Z literal 6712 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 diff --git a/tools/UpdatePaths/Scripts/17259_dirbump_part1.txt b/tools/UpdatePaths/Scripts/17259_dirbump_part1.txt new file mode 100644 index 00000000000..d6a31df92a1 --- /dev/null +++ b/tools/UpdatePaths/Scripts/17259_dirbump_part1.txt @@ -0,0 +1,6 @@ +/obj/machinery/firealarm : /obj/machinery/firealarm {@OLD;name="custom placement"} +/obj/structure/extinguisher_cabinet : /obj/structure/extinguisher_cabinet {@OLD;name="custom placement"} +/obj/item/radio/intercom : /obj/item/radio/intercom {@OLD;name="custom placement";dir=2} +/obj/machinery/light_switch : /obj/machinery/light_switch {@OLD;name="custom placement"} +/obj/machinery/alarm : /obj/machinery/alarm {@OLD;name="custom placement"} +/obj/machinery/newscaster : /obj/machinery/newscaster {@OLD;name="custom placement"} diff --git a/tools/UpdatePaths/Scripts/17259_dirbump_part2.txt b/tools/UpdatePaths/Scripts/17259_dirbump_part2.txt new file mode 100644 index 00000000000..c026b696721 --- /dev/null +++ b/tools/UpdatePaths/Scripts/17259_dirbump_part2.txt @@ -0,0 +1,24 @@ +/obj/machinery/firealarm {pixel_x=24; pixel_y=@UNSET} : /obj/machinery/firealarm {@OLD;name="east bump"} +/obj/machinery/firealarm {pixel_x=-24; pixel_y=@UNSET} : /obj/machinery/firealarm {@OLD;name="west bump"} +/obj/machinery/firealarm {pixel_y=24; pixel_x=@UNSET} : /obj/machinery/firealarm {@OLD;name="north bump"} +/obj/machinery/firealarm {pixel_y=-24; pixel_x=@UNSET} : /obj/machinery/firealarm {@OLD;name="south bump"} +/obj/structure/extinguisher_cabinet {pixel_x=27; pixel_y=@UNSET} : /obj/structure/extinguisher_cabinet {@OLD;name="east bump"} +/obj/structure/extinguisher_cabinet {pixel_x=-27; pixel_y=@UNSET} : /obj/structure/extinguisher_cabinet {@OLD;name="west bump"} +/obj/structure/extinguisher_cabinet {pixel_y=30; pixel_x=@UNSET} : /obj/structure/extinguisher_cabinet {@OLD;name="north bump"} +/obj/structure/extinguisher_cabinet {pixel_y=-30; pixel_x=@UNSET} : /obj/structure/extinguisher_cabinet {@OLD;name="south bump"} +/obj/item/radio/intercom {pixel_x=28; pixel_y=@UNSET} : /obj/item/radio/intercom {@OLD;name="east bump"} +/obj/item/radio/intercom {pixel_x=-28; pixel_y=@UNSET} : /obj/item/radio/intercom {@OLD;name="west bump"} +/obj/item/radio/intercom {pixel_y=28; pixel_x=@UNSET} : /obj/item/radio/intercom {@OLD;name="north bump"} +/obj/item/radio/intercom {pixel_y=-28; pixel_x=@UNSET} : /obj/item/radio/intercom {@OLD;name="south bump"} +/obj/machinery/light_switch {pixel_x=24; pixel_y=@UNSET} : /obj/machinery/light_switch {@OLD;name="east bump"} +/obj/machinery/light_switch {pixel_x=-24; pixel_y=@UNSET} : /obj/machinery/light_switch {@OLD;name="west bump"} +/obj/machinery/light_switch {pixel_y=24; pixel_x=@UNSET} : /obj/machinery/light_switch {@OLD;name="north bump"} +/obj/machinery/light_switch {pixel_y=-24; pixel_x=@UNSET} : /obj/machinery/light_switch {@OLD;name="south bump"} +/obj/machinery/alarm {pixel_x=24; pixel_y=@UNSET} : /obj/machinery/alarm {@OLD;name="east bump"} +/obj/machinery/alarm {pixel_x=-24; pixel_y=@UNSET} : /obj/machinery/alarm {@OLD;name="west bump"} +/obj/machinery/alarm {pixel_y=24; pixel_x=@UNSET} : /obj/machinery/alarm {@OLD;name="north bump"} +/obj/machinery/alarm {pixel_y=-24; pixel_x=@UNSET} : /obj/machinery/alarm {@OLD;name="south bump"} +/obj/machinery/newscaster {pixel_x=32; pixel_y=@UNSET} : /obj/machinery/newscaster {@OLD;name="east bump"} +/obj/machinery/newscaster {pixel_x=-32; pixel_y=@UNSET} : /obj/machinery/newscaster {@OLD;name="west bump"} +/obj/machinery/newscaster {pixel_y=32; pixel_x=@UNSET} : /obj/machinery/newscaster {@OLD;name="north bump"} +/obj/machinery/newscaster {pixel_y=-32; pixel_x=@UNSET} : /obj/machinery/newscaster {@OLD;name="south bump"} \ No newline at end of file diff --git a/tools/UpdatePaths/Scripts/17980_rust_converter.txt b/tools/UpdatePaths/Scripts/17980_rust_converter.txt new file mode 100644 index 00000000000..dd3b852f1b7 --- /dev/null +++ b/tools/UpdatePaths/Scripts/17980_rust_converter.txt @@ -0,0 +1,2 @@ +/turf/simulated/wall/r_wall/rust : /turf/simulated/wall/r_wall , /obj/effect/spawner/random_spawners/wall_rusted_always +/turf/simulated/wall/rust : /turf/simulated/wall , /obj/effect/spawner/random_spawners/wall_rusted_always diff --git a/tools/UpdatePaths/Scripts/19252_newscaster_directionality.txt b/tools/UpdatePaths/Scripts/19252_newscaster_directionality.txt new file mode 100644 index 00000000000..a11b12bd995 --- /dev/null +++ b/tools/UpdatePaths/Scripts/19252_newscaster_directionality.txt @@ -0,0 +1,8 @@ +/obj/machinery/newscaster {pixel_x=32} : /obj/machinery/newscaster {dir=8;name="east bump";pixel_x=28} +/obj/machinery/newscaster {pixel_x=-32} : /obj/machinery/newscaster {dir=4;name="west bump";pixel_x=-28} +/obj/machinery/newscaster {pixel_y=32} : /obj/machinery/newscaster {dir=2;name="north bump";pixel_y=28} +/obj/machinery/newscaster {pixel_y=-32} : /obj/machinery/newscaster {dir=1;name="south bump";pixel_y=-28} +/obj/machinery/newscaster/security_unit {pixel_x=32} : /obj/machinery/newscaster/security_unit {dir=8;name="east bump";pixel_x=28} +/obj/machinery/newscaster/security_unit {pixel_x=-32} : /obj/machinery/newscaster/security_unit {dir=4;name="west bump";pixel_x=-28} +/obj/machinery/newscaster/security_unit {pixel_y=32} : /obj/machinery/newscaster/security_unit {dir=2;name="north bump";pixel_y=28} +/obj/machinery/newscaster/security_unit {pixel_y=-32} : /obj/machinery/newscaster/security_unit {dir=1;name="south bump";pixel_y=-28} diff --git a/tools/UpdatePaths/Scripts/19351_bushes.txt b/tools/UpdatePaths/Scripts/19351_bushes.txt new file mode 100644 index 00000000000..e4a44bba0e8 --- /dev/null +++ b/tools/UpdatePaths/Scripts/19351_bushes.txt @@ -0,0 +1,3 @@ +/obj/structure/flora/grass/jungle/b : /obj/structure/flora/grass/jungle +/obj/structure/flora/junglebush/b : /obj/structure/flora/junglebush +/obj/structure/flora/junglebush/c : /obj/structure/flora/junglebush diff --git a/tools/UpdatePaths/Update_Paths.bat b/tools/UpdatePaths/Update_Paths.bat new file mode 100644 index 00000000000..c126388de7e --- /dev/null +++ b/tools/UpdatePaths/Update_Paths.bat @@ -0,0 +1,3 @@ +@echo off +call "%~dp0\..\bootstrap\python" -m UpdatePaths %* +pause diff --git a/tools/mapmerge2/update_paths.py b/tools/UpdatePaths/__main__.py old mode 100755 new mode 100644 similarity index 67% rename from tools/mapmerge2/update_paths.py rename to tools/UpdatePaths/__main__.py index 6359b6bb303..6c2421f5772 --- a/tools/mapmerge2/update_paths.py +++ b/tools/UpdatePaths/__main__.py @@ -1,17 +1,19 @@ # A script and syntax for applying path updates to maps. -import re -import os -import argparse -import frontend -from dmm import * +import re, os, sys, argparse +from mapmerge2 import frontend +from mapmerge2.dmm import * desc = """ Update dmm files given update file/string. Replacement syntax example: - /turf/open/floor/plasteel/warningline : /obj/effect/turf_decal {dir = @OLD ;tag = @SKIP;icon_state = @SKIP} - /turf/open/floor/plasteel/warningline : /obj/effect/turf_decal {@OLD} , /obj/thing {icon_state = @OLD:name; name = "meme"} - /turf/open/floor/plasteel/warningline{dir=2} : /obj/thing + /turf/open/floor/iron/warningline : /obj/effect/turf_decal {dir = @OLD ;tag = @SKIP;icon_state = @SKIP} + /turf/open/floor/iron/warningline : /obj/effect/turf_decal {@OLD} , /obj/thing {icon_state = @OLD:name; name = "meme"} + /turf/open/floor/iron/warningline{dir=2} : /obj/thing + /obj/effect/landmark/start/virologist : @DELETE +Syntax for subtypes also exist, to update a path's type but maintain subtypes: + /obj/structure/closet/crate/@SUBTYPES : /obj/structure/new_box/@SUBTYPES {@OLD} New paths properties: + @DELETE - if used as new path name the old path will be deleted @OLD - if used as property name copies all modified properties from original path to this one property = @SKIP - will not copy this property through when global @OLD is used. property = @OLD - will copy this modified property from original object even if global @OLD is not used @@ -23,14 +25,14 @@ """ default_map_directory = "../../_maps" -replacement_re = re.compile('\s*([^{]*)\s*(\{(.*)\})?') +replacement_re = re.compile(r'\s*(?P[^{]*)\s*(\{(?P.*)\})?') #urgent todo: replace with actual parser, this is slow as janitor in crit -split_re = re.compile('((?:[A-Za-z0-9_\-$]+)\s*=\s*(?:"(?:.+?)"|[^";]*)|@OLD)') +split_re = re.compile(r'((?:[A-Za-z0-9_\-$]+)\s*=\s*(?:"(?:.+?)"|[^";][^;]*)|@OLD);?') def props_to_string(props): - return "{{{0}}}".format(";".join([k+" = "+props[k] for k in props])) + return "{{{}}}".format(";".join([f"{k} = {v}" for k, v in props.items()])) def string_to_props(propstring, verbose = False): @@ -48,8 +50,8 @@ def string_to_props(propstring, verbose = False): def parse_rep_string(replacement_string, verbose = False): # translates /blah/blah {meme = "test",} into path,prop dictionary tuple match = re.match(replacement_re, replacement_string) - path = match.group(1) - props = match.group(3) + path = match['path'] + props = match['props'] if props: prop_dict = string_to_props(props, verbose) else: @@ -65,9 +67,18 @@ def update_path(dmm_data, replacement_string, verbose=False): new_path, new_path_props = parse_rep_string(replacement_def, verbose) new_paths.append((new_path, new_path_props)) + subtypes = "" + if old_path.endswith("/@SUBTYPES"): + old_path = old_path[:-len("/@SUBTYPES")] + if verbose: + print("Looking for subtypes of", old_path) + subtypes = r"(?:/\w+)*" + + replacement_pattern = re.compile(rf"(?P{re.escape(old_path)}(?P{subtypes}))\s*(:?{{(?P.*)}})?$") + def replace_def(match): - if match.group(2): - old_props = string_to_props(match.group(2), verbose) + if match['props']: + old_props = string_to_props(match['props'], verbose) else: old_props = dict() for filter_prop in old_path_props: @@ -83,7 +94,18 @@ def replace_def(match): print("Found match : {0}".format(match.group(0))) out_paths = [] for new_path, new_props in new_paths: - out = new_path + if new_path == "@OLD": + out = match.group('path') + elif new_path == "@DELETE": + if verbose: + print("Deleting match : {0}".format(match.group(0))) + return [None] + elif new_path.endswith("/@SUBTYPES"): + path_start = new_path[:-len("/@SUBTYPES")] + out = path_start + match.group('subtype') + else: + out = new_path + out_props = dict() for prop_name, prop_value in new_props.items(): if prop_name == "@OLD": @@ -106,29 +128,33 @@ def replace_def(match): return out_paths def get_result(element): - p = re.compile("{0}\s*({{(.*)}})?$".format(re.escape(old_path))) - match = p.match(element) + match = replacement_pattern.match(element) if match: - return replace_def(match) # = re.sub(p,replace_def,element) + return replace_def(match) else: return [element] bad_keys = {} + modified_keys = [] keys = list(dmm_data.dictionary.keys()) for definition_key in keys: def_value = dmm_data.dictionary[definition_key] - new_value = tuple(y for x in def_value for y in get_result(x)) + new_value = tuple(y for x in def_value for y in get_result(x) if y != None) if new_value != def_value: dmm_data.overwrite_key(definition_key, new_value, bad_keys) + modified_keys.append(definition_key) dmm_data.reassign_bad_keys(bad_keys) + return modified_keys def update_map(map_filepath, updates, verbose=False): print("Updating: {0}".format(map_filepath)) dmm_data = DMM.from_file(map_filepath) + modified_keys = [] for update_string in updates: - update_path(dmm_data, update_string, verbose) - dmm_data.to_file(map_filepath, True) + modified_keys.extend(update_path(dmm_data, update_string, verbose)) + dmm_data.remove_unused_keys(modified_keys) + dmm_data.to_file(map_filepath) def update_all_maps(map_directory, updates, verbose=False): @@ -141,10 +167,12 @@ def update_all_maps(map_directory, updates, verbose=False): def main(args): if args.inline: + print("Using replacement:", args.update_source) updates = [args.update_source] else: with open(args.update_source) as f: updates = [line for line in f if line and not line.startswith("#") and not line.isspace()] + print(f"Using {len(updates)} replacements from file:", args.update_source) if args.map: update_map(args.map, updates, verbose=args.verbose) @@ -154,7 +182,11 @@ def main(args): if __name__ == "__main__": - parser = argparse.ArgumentParser(description=desc, formatter_class=argparse.RawTextHelpFormatter) + prog = __spec__.name.replace('.__main__', '') + if os.name == 'nt' and len(sys.argv) <= 1: + print("usage: drag-and-drop a path script .txt onto `Update_Paths.bat`\n or") + + parser = argparse.ArgumentParser(prog=prog, description=desc, formatter_class=argparse.RawTextHelpFormatter) parser.add_argument("update_source", help="update file path / line of update notation") parser.add_argument("--map", "-m", help="path to update, defaults to all maps in maps directory") parser.add_argument("--directory", "-d", help="path to maps directory, defaults to _maps/") diff --git a/tools/UpdatePaths/readme.md b/tools/UpdatePaths/readme.md new file mode 100644 index 00000000000..70d2dcc0894 --- /dev/null +++ b/tools/UpdatePaths/readme.md @@ -0,0 +1,32 @@ +HOW TO USE: +Drag one of the scripts in the “Scripts” folder onto the .bat file “Update_Paths” to open it with the .bat file. Let the script run. + +Use this tool before using mapmerge or opening the map in an editor. + +IMPORTANT: +Please tie the script you are making to the associated PR on github and put it in the scripts folder when you are done. + +For example: 17980_rust_converter ties into https://github.com/ParadiseSS13/Paradise/pull/17980 + +HOW TO MAKE A SCRIPT: +This tool updates paths in the game to new paths. For instance: +If you have a path labeled + +/obj/structure/door/airlock/science/closed/rd + +and wanted it to be + +/obj/structure/door/airlock/science/rd/closed + +This tool would update it for you! This is extremely helpful if you want to be nice to people who have to resolve merge conflicts from the PRs that you make updating these areas. + +How do you do it? +Simply open a notepad and type this on a line: + +/obj/structure/door/airlock/science/closed/rd : /obj/structure/door/airlock/science/rd/closed + +The path on the left is the old, the path on the right is the new. It is seperated by a ":" +If you want to make multiple path changes in one script, simply add more changes on new lines. + +If you get lost, look at other scripts for examples. + diff --git a/tools/bootstrap/node b/tools/bootstrap/node deleted file mode 100755 index 6757035d135..00000000000 --- a/tools/bootstrap/node +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/sh -# bootstrap/node -# -# Node-finding script for all `sh` environments, including Linux, MSYS2, -# Git for Windows, and GitHub Desktop. Invokable from CLI or automation. -# -# If a node.exe installed by `node_.ps1` is present, it will be used. -# Otherwise, this script requires a system `node` to be provided. -set -e - -# Convenience variables -Bootstrap="$(dirname "$0")" -Cache="$Bootstrap/.cache" -if [ "$TG_BOOTSTRAP_CACHE" ]; then - Cache="$TG_BOOTSTRAP_CACHE" -fi -OldPWD="$PWD" -cd "$Bootstrap/../.." -. ./dependencies.sh # sets NODE_VERSION_PRECISE -cd "$OldPWD" -NodeVersion="$NODE_VERSION_PRECISE" -NodeFullVersion="node-v$NodeVersion-win-x64" -NodeDir="$Cache/$NodeFullVersion" -NodeExe="$NodeDir/node.exe" -is_vendored="1" - -# If a bootstrapped Node is not present, search on $PATH. -if [ "$(uname)" = "Linux" ] || [ ! -f "$NodeExe" ]; then - if [ "$TG_BOOTSTRAP_NODE_LINUX" ]; then - NodeFullVersion="node-v$NodeVersion-linux-x64" - NodeDir="$Cache/$NodeFullVersion/bin" - NodeExe="$NodeDir/node" - - if [ ! -f "$NodeExe" ]; then - mkdir -p "$Cache" - Archive="$(realpath "$Cache/node-v$NodeVersion.tar.gz")" - curl "https://nodejs.org/download/release/v$NodeVersion/$NodeFullVersion.tar.gz" -o "$Archive" - (cd "$Cache" && tar xf "$Archive") - fi - elif command -v node >/dev/null 2>&1; then - NodeExe="node" - is_vendored="0" - else - echo - if command -v apt-get >/dev/null 2>&1; then - # Ubuntu advice - echo "Please install Node using your system's package manager:" - echo " sudo apt-get install nodejs" - elif uname | grep -q MSYS; then - # MSYS2 (not packaged) or Git for Windows advice - echo "Please run bootstrap/node.bat instead of bootstrap/node once" - echo "to install Node automatically, or install it from https://nodejs.org/" - elif command -v pacman >/dev/null 2>&1; then - # Arch advice - echo "Please install Node using your system's package manager:" - echo " sudo pacman -S nodejs" - else - # Generic advice - echo "Please install Node from https://nodejs.org/ or using your system's package manager." - fi - echo - exit 1 - fi -fi - -# Invoke Node with all command-line arguments -if [ "$is_vendored" = "1" ]; then - PATH="$(readlink -f "$NodeDir"):$PATH" - echo "Using vendored Node $("$NodeExe" --version)" -else - echo "Using system-wide Node $("$NodeExe" --version)" -fi -exec "$NodeExe" "$@" diff --git a/tools/bootstrap/node.bat b/tools/bootstrap/node.bat deleted file mode 100644 index a3fca88674d..00000000000 --- a/tools/bootstrap/node.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off -set NODE_SKIP_PLATFORM_CHECK=1 -call powershell -NoLogo -ExecutionPolicy Bypass -File "%~dp0\node_.ps1" Download-Node -for /f "tokens=* USEBACKQ" %%s in (` - call powershell -NoLogo -ExecutionPolicy Bypass -File "%~dp0\node_.ps1" Get-Path -`) do ( - set "PATH=%%s;%PATH%" -) -where node.exe >nul 2>nul -if %errorlevel% == 0 ( - echo | set /p printed_str="Using vendored Node " - call node.exe --version - call node.exe %* - goto exit_with_last_error_level -) -echo "node.bat: Failed to bootstrap Node!" -%COMSPEC% /c exit 1 - -:exit_with_last_error_level -if not %errorlevel% == 0 %COMSPEC% /c exit %errorlevel% >nul diff --git a/tools/bootstrap/node_.ps1 b/tools/bootstrap/node_.ps1 deleted file mode 100644 index b75f6c40725..00000000000 --- a/tools/bootstrap/node_.ps1 +++ /dev/null @@ -1,58 +0,0 @@ -## bootstrap/node_.ps1 -## Downloads a Node version to a cache directory and invokes it. - -$ErrorActionPreference = "Stop" - -function Extract-Variable { - param([string] $Path, [string] $Key) - foreach ($Line in Get-Content $Path) { - if ($Line.StartsWith("export $Key=")) { - return $Line.Substring("export $Key=".Length) - } - } - throw "Couldn't find value for $Key in $Path" -} - -function Download-Node { - if (Test-Path $NodeTarget -PathType Leaf) { - return - } - Write-Output "Downloading Node v$NodeVersion (may take a while)" - New-Item $NodeTargetDir -ItemType Directory -ErrorAction silentlyContinue | Out-Null - $WebClient = New-Object Net.WebClient - $WebClient.DownloadFile($NodeSource, $NodeTarget) -} - -## Convenience variables -$BaseDir = Split-Path $script:MyInvocation.MyCommand.Path -$Cache = "$BaseDir\.cache" -if ($Env:TG_BOOTSTRAP_CACHE) { - $Cache = $Env:TG_BOOTSTRAP_CACHE -} -$NodeVersion = Extract-Variable -Path "$BaseDir\..\..\_build_dependencies.sh" -Key "NODE_VERSION_PRECISE" -$NodeSource = "https://nodejs.org/download/release/v$NodeVersion/win-x64/node.exe" -$NodeTargetDir = "$Cache\node-v$NodeVersion-x64" -$NodeTarget = "$NodeTargetDir\node.exe" - -## Just print the path and exit -if ($Args.length -eq 1 -and $Args[0] -eq "Get-Path") { - Write-Output "$NodeTargetDir" - exit 0 -} - -## Just download node and exit -if ($Args.length -eq 1 -and $Args[0] -eq "Download-Node") { - Download-Node - exit 0 -} - -## Download node -Download-Node - -## Set PATH so that recursive calls find it -$Env:PATH = "$NodeTargetDir;$ENV:Path" - -## Invoke Node with all command-line arguments -$ErrorActionPreference = "Continue" -& "$NodeTarget" @Args -exit $LastExitCode diff --git a/tools/bootstrap/python37._pth b/tools/bootstrap/python37._pth index 4fe54372613..47d58cdcdb2 100644 --- a/tools/bootstrap/python37._pth +++ b/tools/bootstrap/python37._pth @@ -2,5 +2,4 @@ python37.zip . ..\..\.. -# Uncomment to run site.main() automatically import site diff --git a/tools/dmi/resolve_icon_conflicts.sh b/tools/dmi/resolve_icon_conflicts.sh deleted file mode 100755 index 708794d408e..00000000000 --- a/tools/dmi/resolve_icon_conflicts.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exec "$(dirname "$0")/../bootstrap/python" -m dmi.merge_driver --posthoc "$@" diff --git a/tools/dmitool/README.txt b/tools/dmitool/README.txt deleted file mode 100644 index 409ab873c3d..00000000000 --- a/tools/dmitool/README.txt +++ /dev/null @@ -1,5 +0,0 @@ -Uses PNGJ: https://code.google.com/p/pngj/. - -For help, use "java -jar dmitool.jar help". - -Requires Java 7. \ No newline at end of file diff --git a/tools/dmitool/build.gradle b/tools/dmitool/build.gradle deleted file mode 100644 index 2e5fbc5b08e..00000000000 --- a/tools/dmitool/build.gradle +++ /dev/null @@ -1,16 +0,0 @@ -apply plugin: 'java' - -repositories { - mavenCentral() -} - -dependencies { - compile group: 'ar.com.hjg', name: 'pngj', version: '2.1.0' -} - -jar { - from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } - manifest { - attributes 'Main-Class': 'dmitool.Main' - } -} \ No newline at end of file diff --git a/tools/dmitool/dmimerge.sh b/tools/dmitool/dmimerge.sh deleted file mode 100644 index dbe846fc6a9..00000000000 --- a/tools/dmitool/dmimerge.sh +++ /dev/null @@ -1,8 +0,0 @@ -java -jar tools/dmitool/dmitool.jar merge $1 $2 $3 $2 -if [ "$?" -gt 0 ] -then - echo "Unable to automatically resolve all icon_state conflicts, please merge manually." - exit 1 -fi - -exit 0 diff --git a/tools/dmitool/dmisort.sh b/tools/dmitool/dmisort.sh deleted file mode 100644 index 8e595b9292c..00000000000 --- a/tools/dmitool/dmisort.sh +++ /dev/null @@ -1,21 +0,0 @@ -FILE_DIR=0 -echo "This script will loop through a given folder and its sub-folders and sort all icons inside of .dmi files." -echo -n "Enter the path of the directory that needs its .dmi icons sorted (and that's a sub-folder of the folder this file is in): " -read FILE_DIR - -FILES_SORTED=0 -for f in $(find $FILE_DIR/*) - do - if [[ $f == *.dmi ]] - then - ((FILES_SORTED++)) - java -jar dmitool.jar sort $f $f - fi -done - -if [ -d "$FILE_DIR" ] - then - echo "Done. Sorted through" $FILES_SORTED "files." -fi - -read diff --git a/tools/dmitool/dmitool.jar b/tools/dmitool/dmitool.jar deleted file mode 100644 index 4cfa49f36de43117f01bfdf95913125b0fb3e5b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 202277 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
    - ulT = authorT.next_sibling - while(ulT.name != 'ul'): - ulT = ulT.next_sibling - changes = [] - - for changeT in ulT.children: - if changeT.name != 'li': continue - val = changeT.decode_contents(formatter="html") - newdat = {changeT['class'][0] + '': val + ''} - if newdat not in changes: - changes += [newdat] - - if len(changes) > 0: - entry[author] = changes - if date in all_changelog_entries: - all_changelog_entries[date].update(entry) - else: - all_changelog_entries[date] = entry - -del_after = [] -print('Reading changelogs...') -for fileName in glob.glob(os.path.join(args.ymlDir, "*.yml")): - name, ext = os.path.splitext(os.path.basename(fileName)) - if name.startswith('.'): continue - if name == 'example': continue - fileName = os.path.abspath(fileName) - print(' Reading {}...'.format(fileName)) - cl = {} - with open(fileName, 'r') as f: - cl = yaml.load(f) - f.close() - if today not in all_changelog_entries: - all_changelog_entries[today] = {} - author_entries = all_changelog_entries[today].get(cl['author'], []) - if len(cl['changes']): - new = 0 - for change in cl['changes']: - if change not in author_entries: - (change_type, _) = dictToTuples(change)[0] - if change_type not in validPrefixes: - print(' {0}: Invalid prefix {1}'.format(fileName, change_type), file=sys.stderr) - author_entries += [change] - new += 1 - all_changelog_entries[today][cl['author']] = author_entries - if new > 0: - print(' Added {0} new changelog entries.'.format(new)) - - if cl.get('delete-after', False): - if os.path.isfile(fileName): - if args.dryRun: - print(' Would delete {0} (delete-after set)...'.format(fileName)) - else: - del_after += [fileName] - - if args.dryRun: continue - - cl['changes'] = [] - with open(fileName, 'w') as f: - yaml.dump(cl, f, default_flow_style=False) - -targetDir = os.path.dirname(args.targetFile) - -with open(args.targetFile.replace('.htm', '.dry.htm') if args.dryRun else args.targetFile, 'w') as changelog: - with open(os.path.join(targetDir, 'templates', 'header.html'), 'r') as h: - for line in h: - changelog.write(line) - - for _date in reversed(sorted(all_changelog_entries.keys())): - entry_htm = '\n' - entry_htm += '\t\t\t

    {date}

    \n'.format(date=_date.strftime(dateformat)) - write_entry = False - for author in sorted(all_changelog_entries[_date].keys()): - if len(all_changelog_entries[_date]) == 0: continue - author_htm = '\t\t\t

    {author} updated:

    \n'.format(author=author) - author_htm += '\t\t\t
      \n' - changes_added = [] - for (css_class, change) in (dictToTuples(e)[0] for e in all_changelog_entries[_date][author]): - if change in changes_added: continue - write_entry = True - changes_added += [change] - author_htm += '\t\t\t\t
    • {change}
    • \n'.format(css_class=css_class, change=change.strip()) - author_htm += '\t\t\t
    \n' - if len(changes_added) > 0: - entry_htm += author_htm - if write_entry: - changelog.write(entry_htm) - - with open(os.path.join(targetDir, 'templates', 'footer.html'), 'r') as h: - for line in h: - changelog.write(line) - - -with open(changelog_cache, 'w') as f: - cache_head = 'DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.' - yaml.dump_all([cache_head, all_changelog_entries], f, default_flow_style=False) - -if len(del_after): - print('Cleaning up...') - for fileName in del_after: - if os.path.isfile(fileName): - print(' Deleting {0} (delete-after set)...'.format(fileName)) - os.remove(fileName)

wHqj9#{$@Uhav+Q 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 Af&c&j diff --git a/tools/dmitool/dmitool.py b/tools/dmitool/dmitool.py deleted file mode 100644 index 390f0d745ff..00000000000 --- a/tools/dmitool/dmitool.py +++ /dev/null @@ -1,94 +0,0 @@ -""" Python 2.7 wrapper for dmitool. -""" - -import os -from subprocess import Popen, PIPE - -_JAVA_PATH = ["java"] -_DMITOOL_CMD = ["-jar", "dmitool.jar"] - -def _dmitool_call(*dmitool_args, **popen_args): - return Popen(_JAVA_PATH + _DMITOOL_CMD + [str(arg) for arg in dmitool_args], **popen_args) - -def _safe_parse(dict, key, deferred_value): - try: - dict[key] = deferred_value() - except Exception as e: - print "Could not parse property '%s': %s"%(key, e) - return e - return False - -def version(): - """ Returns the version as a string. """ - stdout, stderr = _dmitool_call("version", stdout=PIPE).communicate() - return str(stdout).strip() - -def help(): - """ Returns the help text as a string. """ - stdout, stderr = _dmitool_call("help", stdout=PIPE).communicate() - return str(stdout).strip() - -def info(filepath): - """ Totally not a hack that parses the output from dmitool into a dictionary. - May break at any moment. - """ - subproc = _dmitool_call("info", filepath, stdout=PIPE) - stdout, stderr = subproc.communicate() - - result = {} - data = stdout.split(os.linesep)[1:] - #for s in data: print s - - #parse header line - if len(data) > 0: - header = data.pop(0).split(",") - #don't need to parse states, it's redundant - _safe_parse(result, "images", lambda: int(header[0].split()[0].strip())) - _safe_parse(result, "size", lambda: header[2].split()[1].strip()) - - #parse state information - states = [] - for item in data: - if not len(item): continue - - stateinfo = {} - item = item.split(",", 3) - _safe_parse(stateinfo, "name", lambda: item[0].split()[1].strip(" \"")) - _safe_parse(stateinfo, "dirs", lambda: int(item[1].split()[0].strip())) - _safe_parse(stateinfo, "frames", lambda: int(item[2].split()[0].strip())) - if len(item) > 3: - stateinfo["misc"] = item[3] - - states.append(stateinfo) - - result["states"] = states - return result - -def extract_state(input_path, output_path, icon_state, direction=None, frame=None): - """ Extracts an icon state as a png to a given path. - If provided direction should be a string, one of S, N, E, W, SE, SW, NE, NW. - If provided frame should be a frame number or a string of two frame number separated by a dash. - """ - args = ["extract", input_path, icon_state, output_path] - if direction is not None: args.extend(("direction" , str(direction))) - if frame is not None: args.extend(("frame" , str(frame))) - return _dmitool_call(*args) - -def import_state(target_path, input_path, icon_state, replace=False, delays=None, rewind=False, loop=None, ismovement=False, direction=None, frame=None): - """ Inserts an input png given by the input_path into the target_path. - """ - args = ["import", target_path, icon_state, input_path] - - if replace: args.append("nodup") - if rewind: args.append("rewind") - if ismovement: args.append("movement") - if delays: args.extend(("delays", ",".join(delays))) - if direction is not None: args.extend(("direction", direction)) - if frame is not None: args.extend(("frame", frame)) - - if loop in ("inf", "infinity"): - args.append("loop") - elif loop: - args.extend(("loopn", loop)) - - return _dmitool_call(*args) diff --git a/tools/dmitool/git_merge_installer.bat b/tools/dmitool/git_merge_installer.bat deleted file mode 100644 index c7ba2fa23a1..00000000000 --- a/tools/dmitool/git_merge_installer.bat +++ /dev/null @@ -1,6 +0,0 @@ -@echo off -set tab= -echo. >> ../../.git/config -echo [merge "merge-dmi"] >> ../../.git/config -echo %tab%name = iconfile merge driver >> ../../.git/config -echo %tab%driver = ./tools/dmitool/dmimerge.sh %%O %%A %%B >> ../../.git/config diff --git a/tools/dmitool/git_merge_installer.sh b/tools/dmitool/git_merge_installer.sh deleted file mode 100644 index e0c48823b11..00000000000 --- a/tools/dmitool/git_merge_installer.sh +++ /dev/null @@ -1,6 +0,0 @@ -F="../../.git/config" - -echo '' >> $F -echo '[merge "merge-dmi"]' >> $F -echo ' name = iconfile merge driver' >> $F -echo ' driver = ./tools/dmitool/dmimerge.sh %O %A %B' >> $F diff --git a/tools/dmitool/merging.txt b/tools/dmitool/merging.txt deleted file mode 100644 index 639a634bfb7..00000000000 --- a/tools/dmitool/merging.txt +++ /dev/null @@ -1,14 +0,0 @@ -1. Install java(http://www.java.com/en/download/index.jsp) -2. Make sure java is in your PATH. To test this, open git bash, and type "java". If it says unknown command, you need to add JAVA/bin to your PATH variable (A guide for this can be found at https://www.java.com/en/download/help/path.xml ). - -Merging -The easiest way to do merging is to install the merge driver. For this, open `Baystation12/.git/config` in a text editor, and paste the following lines to the end of it: - -[merge "merge-dmi"] - name = iconfile merge driver - driver = ./tools/dmitool/dmimerge.sh %O %A %B - -You may optionally instead run git_merge_installer.bat or git_merge_installer.sh which should automatically insert these lines for you at the appropriate location. - -After this, merging DMI files should happen automagically unless there are conflicts (an icon_state that both you and someone else changed). -If there are conflicts, you will unfortunately still be stuck with opening both versions in the editor, and manually resolving the issues with those states. diff --git a/tools/dmitool/src/main/java/dmitool/DMI.java b/tools/dmitool/src/main/java/dmitool/DMI.java deleted file mode 100644 index bb560107ae9..00000000000 --- a/tools/dmitool/src/main/java/dmitool/DMI.java +++ /dev/null @@ -1,455 +0,0 @@ -package dmitool; - -import ar.com.hjg.pngj.ImageInfo; -import ar.com.hjg.pngj.ImageLineInt; -import ar.com.hjg.pngj.PngReader; -import ar.com.hjg.pngj.PngWriter; -import ar.com.hjg.pngj.PngjInputException; -import ar.com.hjg.pngj.chunks.PngChunkPLTE; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Deque; -import java.util.HashMap; -import java.util.List; - -public class DMI implements Comparator { - int w, h; - List images; - int totalImages = 0; - RGBA[] palette; - boolean isPaletted; - - public DMI(int w, int h) { - this.w = w; - this.h = h; - images = new ArrayList<>(); - isPaletted = false; - palette = null; - } - - public DMI(String f) throws DMIException, FileNotFoundException { - this(new File(f)); - } - - public DMI(File f) throws DMIException, FileNotFoundException { - if(f.length() == 0) { // Empty .dmi is empty file - w = 32; - h = 32; - images = new ArrayList<>(); - isPaletted = false; - palette = null; - return; - } - InputStream in = new FileInputStream(f); - PngReader pngr; - try { - pngr = new PngReader(in); - } catch(PngjInputException pie) { - throw new DMIException("Bad file format!", pie); - } - String descriptor = pngr.getMetadata().getTxtForKey("Description"); - String[] lines = descriptor.split("\n"); - - if(Main.VERBOSITY > 0) System.out.println("Descriptor has " + lines.length + " lines."); - if(Main.VERBOSITY > 3) { - System.out.println("Descriptor:"); - System.out.println(descriptor); - } - - /* length 6 is: - # BEGIN DMI - version = 4.0 - state = "state" - dirs = 1 - frames = 1 - # END DMI - */ - if(lines.length < 6) throw new DMIException(null, 0, "Descriptor too short!"); - - if(!"# BEGIN DMI".equals(lines[0])) throw new DMIException(lines, 0, "Expected '# BEGIN DMI'"); - if(!"# END DMI".equals(lines[lines.length-1])) throw new DMIException(lines, lines.length-1, "Expected '# END DMI'"); - if(!"version = 4.0".equals(lines[1])) throw new DMIException(lines, 1, "Unknown version, expected 'version = 4.0'"); - - this.w = 32; - this.h = 32; - - int i = 2; - - if(lines[i].startsWith("\twidth = ")) { - this.w = Integer.parseInt(lines[2].substring("\twidth = ".length())); - i++; - } - if(lines[i].startsWith("\theight = ")) { - this.h = Integer.parseInt(lines[3].substring("\theight = ".length())); - i++; - } - - List states = new ArrayList<>(); - - while(i < lines.length - 1) { - long imagesInState = 1; - if(!lines[i].startsWith("state = \"") || !lines[i].endsWith("\"")) throw new DMIException(lines, i, "Error reading state string"); - String stateName = lines[i].substring("state = \"".length(), lines[i].length()-1); - i++; - int dirs = 1; - int frames = 1; - float[] delays = null; - boolean rewind = false; - int loop = -1; - String hotspot = null; - boolean movement = false; - while(lines[i].startsWith("\t")) { - if(lines[i].startsWith("\tdirs = ")) { - dirs = Integer.parseInt(lines[i].substring("\tdirs = ".length())); - imagesInState *= dirs; - i++; - } else if(lines[i].startsWith("\tframes = ")) { - frames = Integer.parseInt(lines[i].substring("\tframes = ".length())); - imagesInState *= frames; - i++; - } else if(lines[i].startsWith("\tdelay = ")) { - String delayString = lines[i].substring("\tdelay = ".length()); - String[] delayVals = delayString.split(","); - delays = new float[delayVals.length]; - for(int d=0; d 0) System.out.println(pal.getNentries() + " palette entries"); - - palette = new RGBA[pal.getNentries()]; - int[] rgb = new int[3]; - for(int q=0; q 0) System.out.println("Non-paletted image"); - } - - int iw = pngr.imgInfo.cols; - int ih = pngr.imgInfo.rows; - - if(totalImages > iw * ih) - throw new DMIException(null, 0, "Impossible number of images!"); - - if(Main.VERBOSITY > 0) System.out.println("Image size " + iw+"x"+ih); - int[][] px = new int[ih][]; - - for(int y=0; y statesY) - // this should NEVER happen, we pre-check it - throw new DMIException(null, 0, "CRITICAL: End of image reached with states to go!"); - } - } - if(is.delays != null) { - if((Main.STRICT && is.delays.length*is.dirs != img.length) || is.delays.length*is.dirs < img.length) - throw new DMIException(null, 0, "Delay array size mismatch: " + is.delays.length*is.dirs + " vs " + img.length + "!"); - } - is.images = img; - } - } - - public IconState getIconState(String name) { - for(IconState is: images) { - if(is.name.equals(name)) { - return is; - } - } - return null; - } - - /** - * Makes a copy, unless name is null. - */ - public void addIconState(String name, IconState is) { - if(name == null) { - images.add(is); - totalImages += is.dirs * is.frames; - } else { - IconState newState = (IconState)is.clone(); - newState.name = name; - images.add(newState); - totalImages += is.dirs * is.frames; - } - } - - public boolean removeIconState(String name) { - for(IconState is: images) { - if(is.name.equals(name)) { - images.remove(is); - totalImages -= is.dirs * is.frames; - return true; - } - } - return false; - } - - public boolean setIconState(IconState is) { - for(int i=0; i 0) System.out.println("Fixing PNG chunks..."); - out.writeInt(in.readInt()); - out.writeInt(in.readInt()); - - Deque notZTXT = new ArrayDeque<>(); - - PNGChunk c = null; - - while(c == null || c.type != IEND) { - c = new PNGChunk(in); - if(c.type == zTXt && notZTXT != null) { - PNGChunk cc = null; - while(cc == null || cc.type != IHDR) { - cc = notZTXT.pop(); - cc.write(out); - } - c.write(out); - while(notZTXT.size() != 0) { - PNGChunk pc = notZTXT.pop(); - pc.write(out); - } - notZTXT = null; - } else if(notZTXT != null) { - notZTXT.add(c); - } else { - c.write(out); - } - } - if(Main.VERBOSITY > 0) System.out.println("Chunks fixed."); - } - - @Override public int compare(IconState arg0, IconState arg1) { - return arg0.name.compareTo(arg1.name); - } - - public void writeDMI(OutputStream os) throws IOException { - writeDMI(os, false); - } - public void writeDMI(OutputStream os, boolean sortStates) throws IOException { - if(totalImages == 0) { // Empty .dmis are empty files - os.close(); - return; - } - - // Setup chunk-fix buffer - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - if(sortStates) { - Collections.sort(images, this); - } - - // Write the dmi into the buffer - int sx = (int)Math.ceil(Math.sqrt(totalImages)); - int sy = totalImages / sx; - if(sx*sy < totalImages) { - sy++; - } - if(Main.VERBOSITY > 0) System.out.println("Image size: " + w + "x" + h + "; number of images " + sx + "x" + sy + " (" + totalImages + ")"); - int ix = sx * w; - int iy = sy * h; - ImageInfo ii = new ImageInfo(ix, iy, 8, true); - PngWriter out = new PngWriter(baos, ii); - out.setCompLevel(9); // Maximum compression - String description = getDescriptor(); - if(Main.VERBOSITY > 0) System.out.println("Descriptor has " + (description.split("\n").length) + " lines."); - out.getMetadata().setText("Description", description, true, true); - - Image[][] img = new Image[sx][sy]; - { - int k = 0; - int r = 0; - for(IconState is: images) { - for(Image i: is.images) { - img[k++][r] = i; - - if(k == sx) { - k = 0; - r++; - } - } - } - } - - for(int irow=0; irow myIS = new HashMap<>(); - HashMap dmiIS = new HashMap<>(); - - for(IconState is: images) { - myIS.put(is.name, is); - } - for(IconState is: dmi.images) { - dmiIS.put(is.name, is); - } - if(!myIS.keySet().equals(dmiIS.keySet())) return false; - for(String s: myIS.keySet()) { - if(!myIS.get(s).equals(dmiIS.get(s))) return false; - } - - return true; - } -} diff --git a/tools/dmitool/src/main/java/dmitool/DMIDiff.java b/tools/dmitool/src/main/java/dmitool/DMIDiff.java deleted file mode 100644 index 431d9c1d15a..00000000000 --- a/tools/dmitool/src/main/java/dmitool/DMIDiff.java +++ /dev/null @@ -1,194 +0,0 @@ -package dmitool; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -public class DMIDiff { - Map newIconStates; - Map modifiedIconStates = new HashMap<>(); - Set removedIconStates; - - DMIDiff() { - newIconStates = new HashMap<>(); - removedIconStates = new HashSet<>(); - } - - public DMIDiff(DMI base, DMI mod) { - if(base.h != mod.h || base.w != mod.w) throw new IllegalArgumentException("Cannot compare non-identically-sized DMIs!"); - - HashMap baseIS = new HashMap<>(); - for(IconState is: base.images) { - baseIS.put(is.name, is); - } - - HashMap modIS = new HashMap<>(); - for(IconState is: mod.images) { - modIS.put(is.name, is); - } - - newIconStates = ((HashMap)modIS.clone()); - for(String s: baseIS.keySet()) { - newIconStates.remove(s); - } - - removedIconStates = new HashSet<>(); - removedIconStates.addAll(baseIS.keySet()); - removedIconStates.removeAll(modIS.keySet()); - - Set retainedStates = new HashSet<>(); - retainedStates.addAll(baseIS.keySet()); - retainedStates.retainAll(modIS.keySet()); - - for(String s: retainedStates) { - if(!baseIS.get(s).equals(modIS.get(s))) { - modifiedIconStates.put(s, new IconStateDiff(baseIS.get(s), modIS.get(s))); - } - } - } - /** - * ASSUMES NO MERGE CONFLICTS - MERGE DIFFS FIRST. - */ - public void applyToDMI(DMI dmi) { - for(String s: removedIconStates) { - dmi.removeIconState(s); - } - for(String s: modifiedIconStates.keySet()) { - dmi.setIconState(modifiedIconStates.get(s).newState); - } - for(String s: newIconStates.keySet()) { - dmi.addIconState(null, newIconStates.get(s)); - } - } - - /** - * @param other The diff to merge with - * @param conflictDMI A DMI to add conflicted icon_states to - * @param merged An empty DMIDiff to merge into - * @param aName The log name for this diff - * @param bName The log name for {@code other} - * @return A Set containing all icon_states which conflicted, along with what was done in each diff, in the format "icon_state: here|there"; here and there are one of "added", "modified", and "removed" - */ - public Set mergeDiff(DMIDiff other, DMI conflictDMI, DMIDiff merged, String aName, String bName) { - HashSet myTouched = new HashSet<>(); - myTouched.addAll(removedIconStates); - myTouched.addAll(newIconStates.keySet()); - myTouched.addAll(modifiedIconStates.keySet()); - - HashSet otherTouched = new HashSet<>(); - otherTouched.addAll(other.removedIconStates); - otherTouched.addAll(other.newIconStates.keySet()); - otherTouched.addAll(other.modifiedIconStates.keySet()); - - HashSet bothTouched = (HashSet)myTouched.clone(); - bothTouched.retainAll(otherTouched); // this set now contains the list of icon_states that *both* diffs modified, which we'll put in conflictDMI for manual merge (unless they were deletions - - if(Main.VERBOSITY > 0) { - System.out.println("a: " + Arrays.toString(myTouched.toArray())); - System.out.println("b: " + Arrays.toString(otherTouched.toArray())); - System.out.println("both: " + Arrays.toString(bothTouched.toArray())); - } - - HashSet whatHappened = new HashSet<>(); - - for(String s: bothTouched) { - String here, there; - if(removedIconStates.contains(s)) { - here = "removed"; - } else if(newIconStates.containsKey(s)) { - here = "added"; - } else if(modifiedIconStates.containsKey(s)) { - here = "modified"; - } else { - System.out.println("Unknown error; state="+s); - here = "???"; - } - - if(other.removedIconStates.contains(s)) { - there = "removed"; - } else if(other.newIconStates.containsKey(s)) { - there = "added"; - } else if(other.modifiedIconStates.containsKey(s)) { - there = "modified"; - } else { - System.out.println("Unknown error; state="+s); - there = "???"; - } - - whatHappened.add(s + ": " + here + "|" + there); - } - - // Removals - for(String s: removedIconStates) { - if(!bothTouched.contains(s)) { - merged.removedIconStates.add(s); - } - } - for(String s: other.removedIconStates) { - if(!bothTouched.contains(s)) { - merged.removedIconStates.add(s); - } - } - - // Modifications - for(String s: modifiedIconStates.keySet()) { - if(!bothTouched.contains(s)) { - merged.modifiedIconStates.put(s, modifiedIconStates.get(s)); - } else { - conflictDMI.addIconState(aName + "|" + s, modifiedIconStates.get(s).newState); - } - } - for(String s: other.modifiedIconStates.keySet()) { - if(!bothTouched.contains(s)) { - merged.modifiedIconStates.put(s, other.modifiedIconStates.get(s)); - } else { - conflictDMI.addIconState(bName + "|" + s, other.modifiedIconStates.get(s).newState); - } - } - - // Additions - for(String s: newIconStates.keySet()) { - if(!bothTouched.contains(s)) { - merged.newIconStates.put(s, newIconStates.get(s)); - } else { - conflictDMI.addIconState(aName + s, newIconStates.get(s)); - } - } - for(String s: other.newIconStates.keySet()) { - if(!bothTouched.contains(s)) { - merged.newIconStates.put(s, other.newIconStates.get(s)); - } else { - conflictDMI.addIconState(bName + s, other.newIconStates.get(s)); - } - } - - return whatHappened; - } - - @Override public String toString() { - String s = ""; - String t = "\t"; - String q = "\""; - String n = "\n"; - if(!removedIconStates.isEmpty()) { - s += "Removed:\n"; - for(String state: removedIconStates) - s += t + q + state + q + n; - } - if(!modifiedIconStates.isEmpty()) { - s += "Modified:\n"; - for(String state: modifiedIconStates.keySet()) - s += t + q + state + q + " [" + modifiedIconStates.get(state).toString() + "]\n"; - } - if(!newIconStates.isEmpty()) { - s += "Added:\n"; - for(String state: newIconStates.keySet()) - s += t + q + state + q + " " + newIconStates.get(state).infoStr() + n; - } - if("".equals(s)) - return "No changes"; - return s; - } -} \ No newline at end of file diff --git a/tools/dmitool/src/main/java/dmitool/DMIException.java b/tools/dmitool/src/main/java/dmitool/DMIException.java deleted file mode 100644 index e9293162894..00000000000 --- a/tools/dmitool/src/main/java/dmitool/DMIException.java +++ /dev/null @@ -1,24 +0,0 @@ -package dmitool; - -public class DMIException extends Exception { - String[] desc = null; - int line = 0; - public DMIException(String[] descriptor, int line, String what) { - super(what); - desc = descriptor; - this.line = line; - } - public DMIException(String what) { - super(what); - } - public DMIException(String what, Exception cause) { - super(what, cause); - } - - @Override public String getMessage() { - if(desc != null) - return "\"" + desc[line] + "\" - " + super.getMessage(); - - return super.getMessage(); - } -} \ No newline at end of file diff --git a/tools/dmitool/src/main/java/dmitool/IconState.java b/tools/dmitool/src/main/java/dmitool/IconState.java deleted file mode 100644 index 2a2202c71cd..00000000000 --- a/tools/dmitool/src/main/java/dmitool/IconState.java +++ /dev/null @@ -1,280 +0,0 @@ -package dmitool; - -import java.util.Arrays; -import ar.com.hjg.pngj.ImageInfo; -import ar.com.hjg.pngj.ImageLineInt; -import ar.com.hjg.pngj.PngWriter; -import ar.com.hjg.pngj.PngReader; -import ar.com.hjg.pngj.PngjInputException; -import java.io.InputStream; -import java.io.OutputStream; - -public class IconState { - String name; - int dirs; - int frames; - float[] delays; - Image[] images; // dirs come first - boolean rewind; - int loop; - String hotspot; - boolean movement; - - public String getInfoLine() { - String extraInfo = ""; - if(rewind) extraInfo += " rewind"; - if(frames != 1) { - extraInfo += " loop(" + (loop==-1 ? "infinite" : loop) + ")"; - } - if(hotspot != null) extraInfo += " hotspot('" + hotspot + "')"; - if(movement) extraInfo += " movement"; - if(extraInfo.equals("")) { - return String.format("state \"%s\", %d dir(s), %d frame(s)", name, dirs, frames); - } else { - return String.format("state \"%s\", %d dir(s), %d frame(s),%s", name, dirs, frames, extraInfo); - } - } - - @Override public IconState clone() { - IconState is = new IconState(name, dirs, frames, images.clone(), delays==null ? null : delays.clone(), rewind, loop, hotspot, movement); - is.delays = delays != null ? delays.clone() : null; - is.rewind = rewind; - - return is; - } - - public IconState(String name, int dirs, int frames, Image[] images, float[] delays, boolean rewind, int loop, String hotspot, boolean movement) { - if(delays != null) { - if(Main.STRICT && delays.length != frames) { - throw new IllegalArgumentException("Delays and frames must be the same length!"); - } - } - this.name = name; - this.dirs = dirs; - this.frames = frames; - this.images = images; - this.rewind = rewind; - this.loop = loop; - this.hotspot = hotspot; - this.delays = delays; - this.movement = movement; - } - void setDelays(float[] delays) { - this.delays = delays; - } - void setRewind(boolean b) { - rewind = b; - } - @Override public boolean equals(Object obj) { - if(obj == this) return true; - if(!(obj instanceof IconState)) return false; - - IconState is = (IconState)obj; - - if(!is.name.equals(name)) return false; - if(is.dirs != dirs) return false; - if(is.frames != frames) return false; - if(!Arrays.equals(images, is.images)) return false; - if(is.rewind != rewind) return false; - if(is.loop != loop) return false; - if(!Arrays.equals(delays, is.delays)) return false; - if(!(is.hotspot == null ? hotspot == null : is.hotspot.equals(hotspot))) return false; - if(is.movement != movement) return false; - - return true; - } - public String infoStr() { - return "[" + frames + " frame(s), " + dirs + " dir(s)]"; - } - public String getDescriptorFragment() { - String s = ""; - String q = "\""; - String n = "\n"; - s += "state = " + q + name + q + n; - s += "\tdirs = " + dirs + n; - s += "\tframes = " + frames + n; - if(delays != null) { - s += "\tdelay = " + delayArrayToString(delays) + n; - } - if(rewind) { - s += "\trewind = 1\n"; - } - if(loop != -1) { - s += "\tloop = " + loop + n; - } - if(hotspot != null) { - s += "\thotspot = " + hotspot + n; - } - if(movement) { - s += "\tmovement = 1\n"; - } - return s; - } - - private static String delayArrayToString(float[] d) { - String s = ""; - for(float f: d) { - s += ","+f; - } - return s.substring(1); - } - - /** - * Dump the state to the given OutputStream in PNG format. Frames will be dumped along the X axis of the image, and directions will be dumped along the Y. - */ - public void dumpToPNG(OutputStream outS, int minDir, int maxDir, int minFrame, int maxFrame) { - int totalDirs = maxDir - minDir + 1; - int totalFrames = maxFrame - minFrame + 1; - - int w = images[minDir + minFrame * this.dirs].w; - int h = images[minDir + minFrame * this.dirs].h; - - if(Main.VERBOSITY > 0) System.out.println("Writing " + totalDirs + " dir(s), " + totalFrames + " frame(s), " + totalDirs*totalFrames + " image(s) total."); - ImageInfo ii = new ImageInfo(totalFrames * w, totalDirs * h, 8, true); - PngWriter out = new PngWriter(outS, ii); - out.setCompLevel(9); - - Image[][] img = new Image[totalFrames][totalDirs]; - { - for(int i=0; i= frames) - throw new IllegalArgumentException("Provided frame is out of range: " + frame); - if(dir < 0 || dir >= dirs) - throw new IllegalArgumentException("Provided dir is out of range: " + dir); - - images[getIndex(dir, frame)] = splice; - } -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tools/dmitool/src/main/java/dmitool/IconStateDiff.java b/tools/dmitool/src/main/java/dmitool/IconStateDiff.java deleted file mode 100644 index a5d30db7fe0..00000000000 --- a/tools/dmitool/src/main/java/dmitool/IconStateDiff.java +++ /dev/null @@ -1,126 +0,0 @@ -package dmitool; - -import java.util.HashMap; -import java.util.HashSet; - -public class IconStateDiff { - static class ISAddress { - int dir; - int frame; - - public ISAddress(int dir, int frame) { - this.dir = dir; - this.frame = frame; - } - - public String infoStr(int maxDir, int maxFrame) { - if(maxDir == 1 && maxFrame == 1) { - return ""; - } else if(maxDir == 1) { - return "{" + frame + "}"; - } else if(maxFrame == 1) { - return "{" + Main.dirs[dir] + "}"; - } else { - return "{" + Main.dirs[dir] + " " + frame + "}"; - } - } - } - int oldFrameCount = 0; - int oldDirectionCount = 0; - boolean oldRewind = false; - int oldLoop = -1; - String oldHotspot = null; - - int newFrameCount = 0; - int newDirectionCount = 0; - boolean newRewind = false; - int newLoop = -1; - String newHotspot = null; - - IconState newState; - HashMap modifiedFrames = new HashMap<>(); - HashMap newFrames = new HashMap<>(); - HashSet removedFrames = new HashSet<>(); - - public IconStateDiff(IconState base, IconState mod) { - int maxDir = Math.max(base.dirs, mod.dirs); - int maxFrame = Math.max(base.frames, mod.frames); - - oldFrameCount = base.frames; - oldDirectionCount = base.dirs; - oldRewind = base.rewind; - oldLoop = base.loop; - oldHotspot = base.hotspot; - - newFrameCount = mod.frames; - newDirectionCount = mod.dirs; - newRewind = mod.rewind; - newLoop = mod.loop; - newHotspot = mod.hotspot; - - newState = mod; - - Image baseI, modI; - for(int d=0; d d && base.frames > f) { - baseI = base.images[f * base.dirs + d]; - } else baseI = null; - if(mod.dirs > d && mod.frames > f) { - modI = mod.images[f * mod.dirs + d]; - } else modI = null; - - if(baseI == null && modI == null) continue; - - if(baseI == null) newFrames.put(new ISAddress(d, f), modI); - else if(modI == null) removedFrames.add(new ISAddress(d, f)); - else if(!baseI.equals(modI)) { - modifiedFrames.put(new ISAddress(d, f), modI); - } - } - } - } - - @Override public String toString() { - String s = ""; - String tmp; - - if(newDirectionCount != oldDirectionCount) - s += " | dirs " + oldDirectionCount + "->" + newDirectionCount; - - if(newFrameCount != oldFrameCount) - s += " | frames " + oldFrameCount + "->" + newFrameCount; - - if(newRewind != oldRewind) { - s += " | rewind " + oldRewind + "->" + newRewind; - } - - if(newLoop != oldLoop) { - s += " | loop " + oldLoop + "->" + newLoop; - } - - if(newHotspot == null ? oldHotspot != null : !newHotspot.equals(oldHotspot)) { - s += " | hotspot " + oldHotspot + "->" + newHotspot; - } - - if(!modifiedFrames.isEmpty()) { - int total_frames = Math.min(oldFrameCount, newFrameCount) * Math.min(oldDirectionCount, newDirectionCount); - tmp = ""; - for(ISAddress isa: modifiedFrames.keySet()) { - String str = isa.infoStr(oldDirectionCount, oldFrameCount); - if(!"".equals(str)) { - tmp += ", " + str; - } - } - if(!"".equals(tmp)) { - s += " | modified " + modifiedFrames.size() + " of " + total_frames + ": " + tmp.substring(1); - } else { - s += " | modified " + modifiedFrames.size() + " of " + total_frames; - } - } - - if("".equals(s)) - return "No change"; - return s.substring(3); - } -} \ No newline at end of file diff --git a/tools/dmitool/src/main/java/dmitool/Image.java b/tools/dmitool/src/main/java/dmitool/Image.java deleted file mode 100644 index 2ea7ff41920..00000000000 --- a/tools/dmitool/src/main/java/dmitool/Image.java +++ /dev/null @@ -1,32 +0,0 @@ -package dmitool; - -import java.io.IOException; -import java.io.OutputStream; - -public abstract class Image { - int w, h; - - abstract RGBA getPixel(int x, int y); - - public Image(int w, int h) { - this.w = w; - this.h = h; - } - - @Override public boolean equals(Object obj) { - if(obj == this) return true; - if(!(obj instanceof Image)) return false; - - Image im = (Image) obj; - - if(w != im.w || h != im.h) return false; - - for(int i=0; i argq = new ArrayDeque<>(); - for(String s: args) { - argq.addLast(s); - } - if(argq.size() == 0) { - System.out.println("No command found; use 'help' for help"); - return; - } - String switches = argq.peekFirst(); - if(switches.startsWith("-")) { - for(char c: switches.substring(1).toCharArray()) { - switch(c) { - case 'v': VERBOSITY++; break; - case 'q': VERBOSITY--; break; - case 'S': STRICT = true; break; - } - } - argq.pollFirst(); - } - String op = argq.pollFirst(); - - switch(op) { - case "diff": { - if(argq.size() < 2) { - System.out.println("Insufficient arguments for command!"); - System.out.println(helpStr); - return; - } - String a = argq.pollFirst(); - String b = argq.pollFirst(); - - if(VERBOSITY >= 0) System.out.println("Loading " + a); - DMI dmi = doDMILoad(a); - if(VERBOSITY >= 0) dmi.printInfo(); - - if(VERBOSITY >= 0) System.out.println("Loading " + b); - DMI dmi2 = doDMILoad(b); - if(VERBOSITY >= 0) dmi2.printInfo(); - - DMIDiff dmid = new DMIDiff(dmi, dmi2); - System.out.println(dmid); - break; - } - case "sort": { - if(argq.size() < 1) { - System.out.println("Insufficient arguments for command!"); - System.out.println(helpStr); - return; - } - String f = argq.pollFirst(); - - if(VERBOSITY >= 0) System.out.println("Loading " + f); - DMI dmi = doDMILoad(f); - if(VERBOSITY >= 0) dmi.printInfo(); - - if(VERBOSITY >= 0) System.out.println("Saving " + f); - dmi.writeDMI(new FileOutputStream(f), true); - break; - } - case "merge": { - if(argq.size() < 4) { - System.out.println("Insufficient arguments for command!"); - System.out.println(helpStr); - return; - } - String baseF = argq.pollFirst(), - aF = argq.pollFirst(), - bF = argq.pollFirst(), - mergedF = argq.pollFirst(); - if(VERBOSITY >= 0) System.out.println("Loading " + baseF); - DMI base = doDMILoad(baseF); - if(VERBOSITY >= 0) base.printInfo(); - - if(VERBOSITY >= 0) System.out.println("Loading " + aF); - DMI aDMI = doDMILoad(aF); - if(VERBOSITY >= 0) aDMI.printInfo(); - - if(VERBOSITY >= 0) System.out.println("Loading " + bF); - DMI bDMI = doDMILoad(bF); - if(VERBOSITY >= 0) bDMI.printInfo(); - - DMIDiff aDiff = new DMIDiff(base, aDMI); - DMIDiff bDiff = new DMIDiff(base, bDMI); - DMIDiff mergedDiff = new DMIDiff(); - DMI conflictDMI = new DMI(32, 32); - - Set cf = aDiff.mergeDiff(bDiff, conflictDMI, mergedDiff, aF, bF); - - mergedDiff.applyToDMI(base); - - base.writeDMI(new FileOutputStream(mergedF)); - - if(!cf.isEmpty()) { - if(VERBOSITY >= 0) for(String s: cf) { - System.out.println(s); - } - conflictDMI.writeDMI(new FileOutputStream(mergedF + ".conflict.dmi"), true); - System.out.println("Add/modify conflicts placed in '" + mergedF + ".conflict.dmi'"); - System.exit(1); // Git expects non-zero on merge conflict - } else { - System.out.println("No conflicts"); - System.exit(0); - } - break; - } - case "extract": { - if(argq.size() < 3) { - System.out.println("Insufficient arguments for command!"); - System.out.println(helpStr); - return; - } - String file = argq.pollFirst(), - state = argq.pollFirst(), - outFile = argq.pollFirst(); - - DMI dmi = doDMILoad(file); - if(VERBOSITY >= 0) dmi.printInfo(); - - IconState is = dmi.getIconState(state); - if(is == null) { - System.out.println("icon_state '"+state+"' does not exist!"); - return; - } - // minDir, Maxdir, minFrame, Maxframe - int mDir=0, Mdir=is.dirs-1; - int mFrame=0, Mframe=is.frames-1; - - while(argq.size() > 1) { - String arg = argq.pollFirst(); - - switch(arg) { - case "d": - case "dir": - case "dirs": - case "direction": - case "directions": - String dString = argq.pollFirst(); - if(dString.contains("-")) { - String[] splitD = dString.split("-"); - if(splitD.length == 2) { - mDir = parseDir(splitD[0], is); - Mdir = parseDir(splitD[1], is); - } else { - System.out.println("Illegal dir string: '" + dString + "'!"); - return; - } - } else { - mDir = parseDir(dString, is); - Mdir = mDir; - } - // Invalid value check, warnings are printed in parseDir() - if(mDir == -1 || Mdir == -1) return; - if(Mdir < mDir) { - System.out.println("Maximum dir greater than minimum dir!"); - System.out.println("Textual direction order is S, N, E, W, SE, SW, NE, NW increasing 0 (S) to 7 (NW)"); - return; - } - break; - case "f": - case "frame": - case "frames": - String fString = argq.pollFirst(); - if(fString.contains("-")) { - String[] splitF = fString.split("-"); - if(splitF.length == 2) { - mFrame = parseFrame(splitF[0], is); - Mframe = parseFrame(splitF[1], is); - } else { - System.out.println("Illegal frame string: '" + fString + "'!"); - return; - } - } else { - mFrame = parseFrame(fString, is); - Mframe = mFrame; - } - // Invalid value check, warnings are printed in parseFrame() - if(mFrame == -1 || Mframe == -1) return; - if(Mframe < mFrame) { - System.out.println("Maximum frame greater than minimum frame!"); - return; - } - break; - default: - System.out.println("Unknown argument '" + arg + "' detected, ignoring."); - } - } - if(!argq.isEmpty()) { - System.out.println("Extra argument '" + argq.pollFirst() + "' detected, ignoring."); - } - is.dumpToPNG(new FileOutputStream(outFile), mDir, Mdir, mFrame, Mframe); - break; - } - case "import": { - if(argq.size() < 3) { - System.out.println("Insufficient arguments for command!"); - System.out.println(helpStr); - return; - } - String dmiFile = argq.pollFirst(), - stateName = argq.pollFirst(), - pngFile = argq.pollFirst(); - - boolean noDup = false; - boolean rewind = false; - int loop = 0; - boolean movement = false; - String hotspot = null; - float[] delays = null; - String replaceDir = null; - String replaceFrame = null; - while(!argq.isEmpty()) { - String s = argq.pollFirst(); - switch(s.toLowerCase()) { - case "nodup": - case "nd": - case "n": - noDup = true; - break; - case "rewind": - case "rw": - case "r": - rewind = true; - break; - case "loop": - case "lp": - case "l": - loop = -1; - break; - case "loopn": - case "lpn": - case "ln": - if(!argq.isEmpty()) { - String loopTimes = argq.pollFirst(); - try { - loop = Integer.parseInt(loopTimes); - } catch(NumberFormatException nfe) { - System.out.println("Illegal number '" + loopTimes + "' as argument to '" + s + "'!"); - return; - } - } else { - System.out.println("Argument '" + s + "' requires a numeric argument following it!"); - return; - } - break; - case "movement": - case "move": - case "mov": - case "m": - movement = true; - break; - case "delays": - case "delay": - case "del": - case "d": - if(!argq.isEmpty()) { - String delaysString = argq.pollFirst(); - String[] delaysSplit = delaysString.split(","); - delays = new float[delaysSplit.length]; - for(int i=0; i= 0) System.out.println("Loading " + dmiFile); - DMI toImportTo = doDMILoad(dmiFile); - if(VERBOSITY >= 0) toImportTo.printInfo(); - IconState is = IconState.importFromPNG(toImportTo, new FileInputStream(pngFile), stateName, delays, rewind, loop, hotspot, movement); - - //image insertion - if(replaceDir != null || replaceFrame != null) { - - IconState targetIs = toImportTo.getIconState(stateName); - if(targetIs == null) { - System.out.println("'direction' or 'frame' specified and no icon state '" + stateName + "' found, aborting!"); - return; - } - if(is.images.length == 0) { - System.out.println("'direction' or 'frame' specified and imported is empty, aborting!"); - return; - } - - if(!noDup) targetIs = targetIs.clone(); - - int dirToReplace, frameToReplace; - if(replaceDir != null && replaceFrame != null) { - frameToReplace = parseFrame(replaceFrame, targetIs); - dirToReplace = parseDir(replaceDir, targetIs); - targetIs.insertImage(dirToReplace, frameToReplace, is.images[0]); - } - else if(replaceDir != null) { - dirToReplace = parseDir(replaceDir, targetIs); - targetIs.insertDir(dirToReplace, is.images); - } - else if(replaceFrame != null) { - frameToReplace = parseFrame(replaceFrame, targetIs); - targetIs.insertFrame(frameToReplace, is.images); - } - - if(!noDup) toImportTo.addIconState(null, targetIs); - } - else { - if(noDup) { - if(!toImportTo.setIconState(is)) { - toImportTo.addIconState(null, is); - } - } else { - toImportTo.addIconState(null, is); - } - } - - if(VERBOSITY >= 0) toImportTo.printInfo(); - - if(VERBOSITY >= 0) System.out.println("Saving " + dmiFile); - toImportTo.writeDMI(new FileOutputStream(dmiFile)); - break; - } - case "verify": { - if(argq.size() < 1) { - System.out.println("Insufficient arguments for command!"); - System.out.println(helpStr); - return; - } - String vF = argq.pollFirst(); - if(VERBOSITY >= 0) System.out.println("Loading " + vF); - DMI v = doDMILoad(vF); - if(VERBOSITY >= 0) v.printInfo(); - break; - } - case "info": { - if(argq.size() < 1) { - System.out.println("Insufficient arguments for command!"); - System.out.println(helpStr); - return; - } - String infoFile = argq.pollFirst(); - if(VERBOSITY >= 0) System.out.println("Loading " + infoFile); - DMI info = doDMILoad(infoFile); - info.printInfo(); - info.printStateList(); - break; - } - case "version": - System.out.println(VERSION); - return; - default: - System.out.println("Command '" + op + "' not found!"); - case "help": - System.out.println(helpStr); - break; - } - } - - static int parseDir(String s, IconState is) { - try { - int i = Integer.parseInt(s); - if(0 <= i && i < is.dirs) { - return i; - } else { - System.out.println("Direction not in valid range [0, "+(is.dirs-1)+"]!"); - return -1; - } - } catch(NumberFormatException nfe) { - for(int q=0; q= 0 and index < len(icon_conflicts): - valid_indices.append(index) - elif len(index_range) == 2: - index0 = string_to_num(index_range[0]) - index1 = string_to_num(index_range[1]) - if index0 >= 0 and index0 <= index1 and index1 < len(icon_conflicts): - valid_indices.extend(range(index0, index1 + 1)) - - if not len(valid_indices): - print("No icons selected, exiting.") - sys.exit() - - print("Attempting to fix the following icon files:") - for i in valid_indices: - print(icon_conflicts[i]) - input("Press Enter to start.") - - for i in valid_indices: - path = icon_conflicts[i] - print("{}: {}".format("Merging", path)) - - common_ancestor_hash = run_shell_command("git merge-base MERGE_HEAD HEAD").strip() - - ours_icon = NamedTemporaryFile(delete=False) - theirs_icon = NamedTemporaryFile(delete=False) - base_icon = NamedTemporaryFile(delete=False) - - ours_icon.write(run_shell_command_binary("git show ORIG_HEAD:{}".format(path))) - theirs_icon.write(run_shell_command_binary("git show master220:{}".format(path))) - base_icon.write(run_shell_command_binary("git show {}:{}".format(common_ancestor_hash, path))) - - # So it being "open" doesn't prevent other programs from using it - ours_icon.close() - theirs_icon.close() - base_icon.close() - - merge_command = "java -jar {} merge {} {} {} {}".format(relative_root + dmitool_path, base_icon.name, ours_icon.name, theirs_icon.name, relative_root + path + ".fixed") - - print(merge_command) - print(run_shell_command(merge_command)) - os.remove(ours_icon.name) - os.remove(theirs_icon.name) - os.remove(base_icon.name) - print(".") - -main(sys.argv[1]) diff --git a/tools/map_conflict_fixer/README.md b/tools/map_conflict_fixer/README.md deleted file mode 100644 index 5af8d3aadf0..00000000000 --- a/tools/map_conflict_fixer/README.md +++ /dev/null @@ -1,29 +0,0 @@ -#Map Conflict Fixer/Helper# -The map conflict fixer is a script that can help you fix map conflicts easier and faster. Here's how it works: - -###Before using### -You need git for this, of course. -Make sure your development branch is up to date before starting a map edit to ensure the script outputs a correct fix. - -##Dictionary mode## -Dictionary conflicts are the easiest to fix, you simply need to create more models to accommodate your changes and everyone elses. - -When you run in this mode, if the script finishes successfuly the map should be ready to be commited. - -If the script fails in dictionary mode, you can run it again in full fix mode. - -##Full Fix mode## -When you and someone else edit the same coordinate, there is no easy way to fix the conflict. You need to get your hands dirty. - -The script will mark every tile with a marker type to help you identify what needs fixing in the map editor. - -After you edit and fix a marked map, you should run it through the map merger. The .backup file should be the same you used before. - -###Priorities### -In Full Fix mode, the script needs to know which map version has higher priority, yours or someone elses. This important so tiles with multiple area and turf types aren't created. - -Your version has priority - In each conflicted coordinate, your floor type and your area type will be used -Their version has priority - In each conflicted coordinate, your floor type and your area type will not be used - -##IMPORTANT## -This script is in a testing phase and you should not consider any output to be safe. Always verify the maps this script produced to make sure nothing is out of place. diff --git a/tools/map_conflict_fixer/Run Map Conflict Fixer - DMM.bat b/tools/map_conflict_fixer/Run Map Conflict Fixer - DMM.bat deleted file mode 100644 index d66102a3295..00000000000 --- a/tools/map_conflict_fixer/Run Map Conflict Fixer - DMM.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -SET RELATIVEROOT="../../" -python map_conflict_fixer.py %1 %RELATIVEROOT% 0 -pause diff --git a/tools/map_conflict_fixer/map_conflict_fixer.py b/tools/map_conflict_fixer/map_conflict_fixer.py deleted file mode 100644 index 5e64657ad89..00000000000 --- a/tools/map_conflict_fixer/map_conflict_fixer.py +++ /dev/null @@ -1,111 +0,0 @@ -import map_helpers -import sys -import os -import time - -# Credits to tg for this - -def main(relative_root, tgm=0): - git_version = map_helpers.run_shell_command("git version") - if not git_version: - print("ERROR: Failed to run git. Make sure it is installed and in your PATH.") - return False - - print("--- DISCLAIMER ---") - print("This script is in a testing phase. Verify all the results yourself to make sure you got what you expected. Make sure to read the readme to learn how to use this.") - input("Press Enter to GO\n") - - file_conflicts = map_helpers.run_shell_command("git diff --name-only --diff-filter=U").split("\n") - map_conflicts = [path for path in file_conflicts if path[len(path)-3::] == "dmm"] - - for i in range(0, len(map_conflicts)): - print("[{}]: {}".format(i, map_conflicts[i])) - selection = input("Choose maps you want to fix (example: 1,3-5,12):\n") - selection = selection.replace(" ", "") - selection = selection.split(",") - - #shamelessly copied from mapmerger cli - valid_indices = list() - for m in selection: - index_range = m.split("-") - if len(index_range) == 1: - index = map_helpers.string_to_num(index_range[0]) - if index >= 0 and index < len(map_conflicts): - valid_indices.append(index) - elif len(index_range) == 2: - index0 = map_helpers.string_to_num(index_range[0]) - index1 = map_helpers.string_to_num(index_range[1]) - if index0 >= 0 and index0 <= index1 and index1 < len(map_conflicts): - valid_indices.extend(range(index0, index1 + 1)) - - if not len(valid_indices): - print("No map selected, exiting.") - sys.exit() - - print("Attempting to fix the following maps:") - for i in valid_indices: - print(map_conflicts[i]) - - - marker = None - priority = 0 - print("\nFixing modes:") - print("[{}]: Dictionary conflict fixing mode".format(map_helpers.MAP_FIX_DICTIONARY)) - print("[{}]: Full map conflict fixing mode".format(map_helpers.MAP_FIX_FULL)) - mode = map_helpers.string_to_num(input("Select fixing mode [Dictionary]: ")) - if mode != map_helpers.MAP_FIX_FULL: - mode = map_helpers.MAP_FIX_DICTIONARY - print("DICTIONARY mode selected.") - else: - marker = input("FULL mode selected. Input a marker [/obj/effect/debugging/mapfix_marker]: ") - if not marker: - marker = "/obj/effect/debugging/mapfix_marker" - print("Marker selected: {}".format(marker)) - - print("\nVersion priorities:") - print("[{}]: Your version".format(map_helpers.MAP_FIX_PRIORITY_OURS)) - print("[{}]: Their version".format(map_helpers.MAP_FIX_PRIORITY_THEIRS)) - priority = map_helpers.string_to_num(input("Select priority [Yours]: ")) - if priority != map_helpers.MAP_FIX_PRIORITY_THEIRS: - priority = map_helpers.MAP_FIX_PRIORITY_OURS - print("Your version will be prioritized.") - else: - print("Their version will be prioritized.") - - ed = "FIXED" if mode == map_helpers.MAP_FIX_DICTIONARY else "MARKED" - ing = "FIXING" if mode == map_helpers.MAP_FIX_DICTIONARY else "MARKING" - - print("\nMaps will be converted to TGM.") - print("Writing maps to 'file_path/file_name.fixed.dmm'. Please verify the results before commiting.") - if mode == map_helpers.MAP_FIX_FULL: - print("After editing the marked maps, run them through the map merger!") - input("Press Enter to start.") - - print(".") - time.sleep(0.3) - print(".") - - for i in valid_indices: - path = map_conflicts[i] - print("{}: {}".format(ing, path)) - ours_map_raw_text = map_helpers.run_shell_command("git show HEAD:{}".format(path)) - theirs_map_raw_text = map_helpers.run_shell_command("git show MERGE_HEAD:{}".format(path)) - - common_ancestor_hash = map_helpers.run_shell_command("git merge-base HEAD MERGE_HEAD").strip() - base_map_raw_text = map_helpers.run_shell_command("git show {}:{}".format(common_ancestor_hash, path)) - - ours_map = map_helpers.parse_map(ours_map_raw_text) - theirs_map = map_helpers.parse_map(theirs_map_raw_text) - base_map = map_helpers.parse_map(base_map_raw_text) - - if map_helpers.fix_map_git_conflicts(base_map, ours_map, theirs_map, mode, marker, priority, relative_root+path, tgm): - print("{}: {}".format(ed, path)) - print(".") - -output_tgm = None -try: - output_tgm = int(sys.argv[2]) -except ValueError: - output_tgm = 0 - -main(sys.argv[1], output_tgm) diff --git a/tools/map_conflict_fixer/map_helpers.py b/tools/map_conflict_fixer/map_helpers.py deleted file mode 100644 index 45f27e8c92c..00000000000 --- a/tools/map_conflict_fixer/map_helpers.py +++ /dev/null @@ -1,687 +0,0 @@ -import sys -import subprocess - -tgm_header = "//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE" - -try: - version = sys.version_info - if version.major < 3 or (version.major == 3 and version.minor < 5): - print("ERROR: You are running an incompatible version of Python. The current minimum version required is [3.5].\nYour version: {}".format(sys.version)) - sys.exit() -except: - print("ERROR: Something went wrong, you might be running an incompatible version of Python. The current minimum version required is [3.5].\nYour version: {}".format(sys.version)) - sys.exit() - -import collections - -error = {0:"OK", 1:"WARNING: Detected key length difference, not merging.", 2:"WARNING: Detected map size difference, not merging."} - -def merge_map(newfile, backupfile, tgm): - key_length = 1 - maxx = 1 - maxy = 1 - - new_map = parse_map(get_map_raw_text(newfile)) - old_map = parse_map(get_map_raw_text(backupfile)) - - if new_map["key_length"] != old_map["key_length"]: - if tgm: - write_dictionary_tgm(newfile, new_map["dictionary"]) - write_grid_coord_small(newfile, new_map["grid"]) - return 1 - else: - key_length = old_map["key_length"] - - if new_map["maxx"] != old_map["maxx"] or new_map["maxy"] != old_map["maxy"]: - if tgm: - write_dictionary_tgm(newfile, new_map["dictionary"]) - write_grid_coord_small(newfile, new_map["grid"]) - return 2 - else: - maxx = old_map["maxx"] - maxy = old_map["maxy"] - - new_dict = new_map["dictionary"] - new_grid = new_map["grid"] - old_dict = sort_dictionary(old_map["dictionary"]) #impose order; old_dict is used in the end as the merged dictionary - old_grid = old_map["grid"] - - merged_grid = dict() - known_keys = dict() - unused_keys = list(old_dict.keys()) - - #both new and old dictionary in lists, for faster key lookup by tile tuple - old_dict_keys = list(old_dict.keys()) - old_dict_values = list(old_dict.values()) - new_dict_keys = list(new_dict.keys()) - new_dict_values = list(new_dict.values()) - - #step one: parse the new version, compare it to the old version, merge both - for y in range(1, maxy+1): - for x in range(1, maxx+1): - - new_key = new_grid[x,y] - #if this key has been processed before, it can immediately be merged - if new_key in known_keys: - merged_grid[x,y] = known_keys[new_key] - continue - - old_key = old_grid[x,y] - old_tile = old_dict[old_key] - new_tile = new_dict[new_key] - - if new_tile == old_tile: #this tile is the exact same as before, so the old key is used - merged_grid[x,y] = old_key - known_keys[new_key] = old_key - unused_keys.remove(old_key) - continue - - #the tile is different here, but if it exists in the old dictionary, its old key can be used - newold_key = get_key(old_dict_keys, old_dict_values, new_tile) - if newold_key != None: - merged_grid[x,y] = newold_key - known_keys[new_key] = newold_key - try: - unused_keys.remove(newold_key) - except ValueError: - print("NOTICE: Correcting duplicate dictionary entry. ({})".format(new_key)) - - #the tile is brand new and it needs a new key, but if the old key isn't being used any longer it can be used instead - elif get_key(new_dict_keys, new_dict_values, old_tile) == None: - merged_grid[x,y] = old_key - old_dict[old_key] = new_tile - known_keys[new_key] = old_key - unused_keys.remove(old_key) - - #all other options ruled out, a brand new key is generated for the brand new tile - else: - fresh_key = generate_new_key(old_dict) - old_dict[fresh_key] = new_tile - merged_grid[x,y] = fresh_key - -## #step two: clean the dictionary if it has too many unused keys -## if len(unused_keys) > min(100, (len(old_dict) * 0.5)): -## print("NOTICE: Trimming the dictionary.") -## old_dict = trim_dictionary(old_dict) - - #step three: write the map to file - if tgm: - write_dictionary_tgm(newfile, old_dict) - write_grid_coord_small(newfile, merged_grid, maxx, maxy) - else: - write_dictionary(newfile, old_dict) - write_grid(newfile, merged_grid, maxx, maxy) - return 0 - -####################### -#write to file helpers# -def write_dictionary_tgm(filename, dictionary): #write dictionary in tgm format - with open(filename, "w") as output: - output.write("{}\n".format(tgm_header)) - for key, list_ in dictionary.items(): - output.write("\"{}\" = (\n".format(key)) - - for thing in list_: - buffer = "" - in_quote_block = False - in_varedit_block = False - for char in thing: - - if in_quote_block: - if char == "\"": - in_quote_block = False - buffer = buffer + char - continue - elif char == "\"": - in_quote_block = True - buffer = buffer + char - continue - - if not in_varedit_block: - if char == "{": - in_varedit_block = True - buffer = buffer + "{\n\t" - continue - else: - if char == ";": - buffer = buffer + ";\n\t" - continue - elif char == "}": - buffer = buffer + "\n\t}" - in_varedit_block = False - continue - - buffer = buffer + char - - if list_.index(thing) != len(list_) - 1: - buffer = buffer + ",\n" - output.write(buffer) - - output.write(")\n") - - -def write_grid_coord_small(filename, grid, maxx, maxy): #thanks to YotaXP for finding out about this one - with open(filename, "a") as output: - output.write("\n") - - for x in range(1, maxx+1): - output.write("({},{},1) = {{\"\n".format(x, 1, 1)) - for y in range(1, maxy): - output.write("{}\n".format(grid[x,y])) - output.write("{}\n\"}}\n".format(grid[x,maxy])) - - -def write_dictionary(filename, dictionary): #writes a tile dictionary the same way Dreammaker does - with open(filename, "w") as output: - for key, value in dictionary.items(): - output.write("\"{}\" = ({})\n".format(key, ",".join(value))) - - -def write_grid(filename, grid, maxx, maxy): #writes a map grid the same way Dreammaker does - with open(filename, "a") as output: - output.write("\n") - output.write("(1,1,1) = {\"\n") - - for y in range(1, maxy+1): - for x in range(1, maxx+1): - try: - output.write(grid[x,y]) - except KeyError: - print("Key error: ({},{})".format(x,y)) - output.write("\n") - output.write("\"}") - output.write("\n") - -#################### -#dictionary helpers# -def search_key(dictionary, data): - for key, value in dictionary.items(): - if value == data: - return key - return None - -def get_key(keys, values, data): - try: - return keys[values.index(data)] - except: - return None - -def trim_dictionary(dictionary): #rewrites dictionary into an ordered dictionary with no unused keys - trimmed_dict = collections.OrderedDict() - key_length = len(list(dictionary.keys())[0]) - key = "" - for tile in dictionary.values(): - key = get_next_key(key, key_length) - trimmed_dict[key] = tile - return trimmed_dict - -def sort_dictionary(dictionary): - sorted_dict = collections.OrderedDict() - keys = list(dictionary.keys()) - keys.sort(key=key_int_value) - for key in keys: - sorted_dict[key] = dictionary[key] - return sorted_dict - -############ -#map parser# -def get_map_raw_text(mapfile): - with open(mapfile, "r") as reading: - return reading.read() - -def parse_map(map_raw_text): #still does not support more than one z level per file, but should parse any format - in_quote_block = False - in_key_block = False - in_data_block = False - in_varedit_block = False - after_data_block = False - escaping = False - skip_whitespace = False - - dictionary = collections.OrderedDict() - curr_key = "" - curr_datum = "" - curr_data = list() - - in_map_block = False - in_coord_block = False - in_map_string = False - iter_x = 0 - adjust_y = True - - curr_num = "" - reading_coord = "x" - - key_length = 0 - - maxx = 0 - maxy = 0 - - curr_x = 0 - curr_y = 0 - curr_z = 1 - grid = dict() - - for char in map_raw_text: - - if not in_map_block: - - if char == "\n" or char == "\t": - continue - - if in_data_block: - - if in_varedit_block: - - if in_quote_block: - if char == "\\": - curr_datum = curr_datum + char - escaping = True - continue - - if escaping: - curr_datum = curr_datum + char - escaping = False - continue - - if char == "\"": - curr_datum = curr_datum + char - in_quote_block = False - continue - - curr_datum = curr_datum + char - continue - - if skip_whitespace and char == " ": - skip_whitespace = False - continue - skip_whitespace = False - - if char == "\"": - curr_datum = curr_datum + char - in_quote_block = True - continue - - if char == ";": - skip_whitespace = True - curr_datum = curr_datum + char - continue - - if char == "}": - curr_datum = curr_datum + char - in_varedit_block = False - continue - - curr_datum = curr_datum + char - continue - - if char == "{": - curr_datum = curr_datum + char - in_varedit_block = True - continue - - if char == ",": - curr_data.append(curr_datum) - curr_datum = "" - continue - - if char == ")": - curr_data.append(curr_datum) - dictionary[curr_key] = tuple(curr_data) - curr_data = list() - curr_datum = "" - curr_key = "" - in_data_block = False - after_data_block = True - continue - - curr_datum = curr_datum + char - continue - - if in_key_block: - if char == "\"": - in_key_block = False - key_length = len(curr_key) - else: - curr_key = curr_key + char - continue - #else we're looking for a key block, a data block or the map block - - if char == "\"": - in_key_block = True - after_data_block = False - continue - - if char == "(": - if after_data_block: - in_map_block = True - in_coord_block = True - after_data_block = False - curr_key = "" - continue - else: - in_data_block = True - after_data_block = False - continue - - else: - - if in_coord_block: - if char == ",": - if reading_coord == "x": - curr_x = string_to_num(curr_num) - if curr_x > maxx: - maxx = curr_x - iter_x = 0 - curr_num = "" - reading_coord = "y" - elif reading_coord == "y": - curr_y = string_to_num(curr_num) - if curr_y > maxy: - maxy = curr_y - curr_num = "" - reading_coord = "z" - else: - pass - continue - - if char == ")": - in_coord_block = False - reading_coord = "x" - curr_num = "" - #read z here if needed - continue - - curr_num = curr_num + char - continue - - if in_map_string: - - if char == "\"": - in_map_string = False - adjust_y = True - curr_y -= 1 - continue - - if char == "\n": - if adjust_y: - adjust_y = False - else: - curr_y += 1 - if curr_x > maxx: - maxx = curr_x - if iter_x > 1: - curr_x = 1 - iter_x = 0 - continue - - - curr_key = curr_key + char - if len(curr_key) == key_length: - iter_x += 1 - if iter_x > 1: - curr_x += 1 - - grid[curr_x, curr_y] = curr_key - curr_key = "" - continue - - - #else look for coordinate block or a map string - - if char == "(": - in_coord_block = True - continue - if char == "\"": - in_map_string = True - continue - - if curr_y > maxy: - maxy = curr_y - - data = dict() - data["dictionary"] = dictionary - data["grid"] = grid - data["key_length"] = key_length - data["maxx"] = maxx - data["maxy"] = maxy - return data - -############# -#key helpers# -def generate_new_key(dictionary): - last_key = next(reversed(dictionary)) - return get_next_key(last_key, len(last_key)) - -def get_next_key(key, key_length): - if key == "": - return "".join("a" for _ in range(key_length)) - - length = len(key) - new_key = "" - carry = 1 - for char in key[::-1]: - if carry <= 0: - new_key = new_key + char - continue - if char == 'Z': - new_key = new_key + 'a' - carry += 1 - length -= 1 - if length <= 0: - return "OVERFLOW" - elif char == 'z': - new_key = new_key + 'A' - else: - new_key = new_key + chr(ord(char) + 1) - if carry > 0: - carry -= 1 - return new_key[::-1] - -def key_int_value(key): - value = 0 - b = 0 - for digit in reversed(key): - value += base52.index(digit) * (52 ** b) - b += 1 - return value - -def key_compare(keyA, keyB): #thanks byond for not respecting ascii - pos = 0 - for a in keyA: - pos += 1 - count = pos - for b in keyB: - if(count > 1): - count -= 1 - continue - if a.islower() and b.islower(): - if(a < b): - return -1 - if(a > b): - return 1 - break - if a.islower() and b.isupper(): - return -1 - if a.isupper() and b.islower(): - return 1 - if a.isupper() and b.isupper(): - if(a < b): - return -1 - if(a > b): - return 1 - break - return 0 - - -def key_difference(keyA, keyB): #subtract keyB from keyA - if len(keyA) != len(keyB): - return "you fucked up" - - Ayek = keyA[::-1] - Byek = keyB[::-1] - - result = 0 - for i in range(0, len(keyA)): - base = 52**i - A = 26 if Ayek[i].isupper() else 0 - B = 26 if Byek[i].isupper() else 0 - result += ( (ord(Byek[i].lower()) + B) - (ord(Ayek[i].lower()) + A) ) * base - return result - -############# -#other stuff# - -#Base 52 a-z A-Z dictionary (it's a python list) for fast conversion -base52 = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o', - 'p','q','r','s','t','u','v','w','x','y','z','A','B','C','D', - 'E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S', - 'T','U','V','W','X','Y','Z'] - -def string_to_num(s): - try: - return int(s) - except ValueError: - return -1 - -#################### -#map conflict fixer# - -MAP_FIX_DICTIONARY = 0 -MAP_FIX_FULL = 1 -MAP_FIX_PRIORITY_OURS = 0 -MAP_FIX_PRIORITY_THEIRS = 1 - -def fix_map_git_conflicts(base_map, ours_map, theirs_map, mode, marker, priority, path, tgm): #attempts to fix git map conflicts automagically - #mode values: - # 0 - Dictionary mode, only fixes dictionary conflicts and fails at coordinate conflicts - # 1 - Full mode, fixes dictionary conflicts and will join both versions of a coordinate and adds a marker to each conflicted coordinate - - if mode == MAP_FIX_FULL and not marker: - print("ERROR: Full fix mode selected but a marker wasn't provided.") - return False - - key_length = 1 - maxx = 1 - maxy = 1 - - if ours_map["key_length"] != theirs_map["key_length"] or ours_map["key_length"] != base_map["key_length"]: - print("ERROR: Key length is different, I am not smart enough for this yet.") - return False - else: - key_length = ours_map["key_length"] - - if ours_map["maxx"] != theirs_map["maxx"] or ours_map["maxy"] != theirs_map["maxy"] or ours_map["maxx"] != base_map["maxx"] or ours_map["maxy"] != base_map["maxy"]: - print("ERROR: Map size is different, I am not smart enough for this yet.") - return False - else: - maxx = ours_map["maxx"] - maxy = ours_map["maxy"] - - base_dict = base_map["dictionary"] - base_grid = base_map["grid"] - ours_dict = ours_map["dictionary"] - ours_grid = ours_map["grid"] - theirs_dict = theirs_map["dictionary"] - theirs_grid = theirs_map["grid"] - - merged_dict = collections.OrderedDict() - merged_grid = dict() - - new_key = generate_new_key(base_dict) - - grid_conflict_counter = 0 - - for y in range(1, maxy+1): - for x in range(1, maxx+1): - base_key = base_grid[x,y] - ours_key = ours_grid[x,y] - theirs_key = theirs_grid[x,y] - - #case 1: everything is the same - if base_dict[base_key] == ours_dict[ours_key] and base_dict[base_key] == theirs_dict[theirs_key]: - merged_dict[base_key] = base_dict[base_key] - merged_grid[x,y] = base_key - continue - - #case 2: ours is unchanged, theirs is different - if base_dict[base_key] == ours_dict[ours_key]: - some_key = search_key(base_dict, theirs_dict[theirs_key]) - if some_key != None: - merged_dict[some_key] = theirs_dict[theirs_key] - merged_grid[x,y] = some_key - else: - merged_dict[new_key] = theirs_dict[theirs_key] - merged_grid[x,y] = new_key - new_key = get_next_key(new_key, key_length) - - #case 3: ours is different, theirs is unchanged - elif base_dict[base_key] == theirs_dict[theirs_key]: - some_key = search_key(base_dict, ours_dict[ours_key]) - if some_key != None: - merged_dict[some_key] = ours_dict[ours_key] - merged_grid[x,y] = some_key - else: - merged_dict[new_key] = ours_dict[ours_key] - merged_grid[x,y] = new_key - new_key = get_next_key(new_key, key_length) - - #case 4: everything is different, grid conflict - else: - if mode != MAP_FIX_FULL: - print("FAILED: Map fixing failed due to grid conflicts. Try fixing in full fix mode.") - return False - else: - combined_tile = combine_tiles(ours_dict[ours_key], theirs_dict[theirs_key], priority, marker) - merged_dict[new_key] = combined_tile - merged_grid[x,y] = new_key - new_key = get_next_key(new_key, key_length) - grid_conflict_counter += 1 - - merged_dict = sort_dictionary(merged_dict) - if tgm: - write_dictionary_tgm(path+".fixed.dmm", merged_dict) - write_grid_coord_small(path+".fixed.dmm", merged_grid, maxx, maxy) - else: - write_dictionary(path+".fixed.dmm", merged_dict) - write_grid(path+".fixed.dmm", merged_grid, maxx, maxy) - if grid_conflict_counter > 0: - print("Counted {} conflicts.".format(grid_conflict_counter)) - return True - -def combine_tiles(tile_A, tile_B, priority, marker): - new_tile = list() - turf_atom = None - area_atom = None - - low_tile = None - high_tile = None - if priority == MAP_FIX_PRIORITY_OURS: - high_tile = tile_A - low_tile = tile_B - else: - high_tile = tile_B - low_tile = tile_A - - new_tile.append(marker) - for atom in high_tile: - if atom[0:5] == "/turf": - turf_atom = atom - elif atom[0:5] == "/area": - area_atom = atom - else: - new_tile.append(atom) - - for atom in low_tile: - if atom[0:5] == "/turf" or atom[0:5] == "/area": - continue - else: - new_tile.append(atom) - - new_tile.append(turf_atom) - new_tile.append(area_atom) - return tuple(new_tile) - - -def run_shell_command(command): - return subprocess.run(command, shell=True, stdout=subprocess.PIPE, universal_newlines=True).stdout diff --git a/tools/mapmerge2-old/Prepare Maps.bat b/tools/mapmerge2-old/Prepare Maps.bat deleted file mode 100644 index 6955e9c877c..00000000000 --- a/tools/mapmerge2-old/Prepare Maps.bat +++ /dev/null @@ -1,12 +0,0 @@ -@echo off -cd ../../_maps/ - -for /R %%f in (*.dmm) do copy "%%f" "%%f.backup" - -cls -echo All dmm files in _maps directories have been backed up -echo Now you can make your changes... -echo --- -echo Remember to run mapmerge.bat just before you commit your changes! -echo --- -pause diff --git a/tools/mapmerge2-old/README.md b/tools/mapmerge2-old/README.md deleted file mode 100644 index 0ff4d21ac2e..00000000000 --- a/tools/mapmerge2-old/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Map Merge 2 - -**Map Merge 2** is an improvement over previous map merging scripts, with -better merge-conflict prevention, multi-Z support, and automatic handling of -key overflow. For up-to-date tips and tricks, also visit the [Map Merger] wiki article. - -## What Map Merging Is - -The "map merge" operation describes the process of rewriting a map file written -by the DreamMaker map editor to A) use a format more amenable to Git's conflict -resolution and B) differ in the least amount textually from the previous -version of the map while maintaining all the actual changes. It requires an old -version of the map to use as a reference and a new version of the map which -contains the desired changes. - -## Installation - -To install Python dependencies, run `requirements-install.bat`, or run -`python -m pip install -r requirements.txt` directly. See the [Git hooks] -documentation to install the Git pre-commit hook which runs the map merger -automatically, or use `tools/mapmerge/Prepare Maps.bat` to save backups before -running `mapmerge.bat`. - -For up-to-date installation and detailed troubleshooting instructions, visit -the [Map Merger] wiki article. - -## Code Structure - -Frontend scripts are meant to be run directly. They obey the environment -variables `TGM` to set whether files are saved in TGM (1) or DMM (0) format, -and `MAPROOT` to determine where maps are kept. By default, TGM is used and -the map root is autodetected. Each script may either prompt for the desired map -or be run with command-line parameters indicating which maps to act on. The -scripts include: - -* `convert.py` for converting maps to and from the TGM format. Used by - `tgm2dmm.bat` and `dmm2tgm.bat`. -* `mapmerge.py` for running the map merge on map backups saved by - `Prepare Maps.bat`. Used by `mapmerge.bat` - -Implementation modules: - -* `dmm.py` includes the map reader and writer. -* `mapmerge.py` includes the implementation of the map merge operation. -* `frontend.py` includes the common code for the frontend scripts. - -`precommit.py` is run by the [Git hooks] if installed, and merges the new -version of any map saved in the index (`git add`ed) with the old version stored -in Git when run. - -[Map Merger]: https://tgstation13.org/wiki/Map_Merger -[Git hooks]: ../hooks/README.md diff --git a/tools/mapmerge2-old/convert.py b/tools/mapmerge2-old/convert.py deleted file mode 100644 index 35e5dda4433..00000000000 --- a/tools/mapmerge2-old/convert.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env python3 -import frontend -import dmm - -if __name__ == '__main__': - settings = frontend.read_settings() - for fname in frontend.process(settings, "convert"): - dmm.DMM.from_file(fname).to_file(fname, settings.tgm) diff --git a/tools/mapmerge2-old/dmi.py b/tools/mapmerge2-old/dmi.py deleted file mode 100644 index f0a8182c9f0..00000000000 --- a/tools/mapmerge2-old/dmi.py +++ /dev/null @@ -1,253 +0,0 @@ -# Tools for working with modern DreamMaker icon files (PNGs + metadata) - -import math -from PIL import Image -from PIL.PngImagePlugin import PngInfo - -DEFAULT_SIZE = 32, 32 -LOOP_UNLIMITED = 0 -LOOP_ONCE = 1 - -NORTH = 1 -SOUTH = 2 -EAST = 4 -WEST = 8 -SOUTHEAST = SOUTH|EAST -SOUTHWEST = SOUTH|WEST -NORTHEAST = NORTH|EAST -NORTHWEST = NORTH|WEST - -CARDINALS = [NORTH, SOUTH, EAST, WEST] -DIR_ORDER = [SOUTH, NORTH, EAST, WEST, SOUTHEAST, SOUTHWEST, NORTHEAST, NORTHWEST] -DIR_NAMES = { - 'SOUTH': SOUTH, - 'NORTH': NORTH, - 'EAST': EAST, - 'WEST': WEST, - 'SOUTHEAST': SOUTHEAST, - 'SOUTHWEST': SOUTHWEST, - 'NORTHEAST': NORTHEAST, - 'NORTHWEST': NORTHWEST, - **{str(x): x for x in DIR_ORDER}, - **{x: x for x in DIR_ORDER}, - '0': SOUTH, - None: SOUTH, -} - -class Dmi: - version = "4.0" - - def __init__(self, width, height): - self.width = width - self.height = height - self.states = [] - - @classmethod - def from_file(cls, fname): - image = Image.open(fname) - - # no metadata = regular image file - if 'Description' not in image.info: - dmi = Dmi(*image.size) - state = dmi.state("") - state.frame(image) - return dmi - - # read metadata - metadata = image.info['Description'] - line_iter = iter(metadata.splitlines()) - assert next(line_iter) == "# BEGIN DMI" - assert next(line_iter) == f"version = {cls.version}" - - dmi = Dmi(*DEFAULT_SIZE) - state = None - - for line in line_iter: - if line == "# END DMI": - break - key, value = line.lstrip().split(" = ") - if key == 'width': - dmi.width = int(value) - elif key == 'height': - dmi.height = int(value) - elif key == 'state': - state = dmi.state(unescape(value)) - elif key == 'dirs': - state.dirs = int(value) - elif key == 'frames': - state._nframes = int(value) - elif key == 'delay': - state.delays = [parse_num(x) for x in value.split(',')] - elif key == 'loop': - state.loop = int(value) - elif key == 'rewind': - state.rewind = parse_bool(value) - elif key == 'hotspot': - x, y, frm = [int(x) for x in value.split(',')] - state.hotspot(frm - 1, x, y) - elif key == 'movement': - state.movement = parse_bool(value) - else: - raise NotImplementedError(key) - - # cut image into frames - width, height = image.size - gridwidth = width // dmi.width - i = 0 - for state in dmi.states: - for frame in range(state._nframes): - for dir in range(state.dirs): - px = dmi.width * (i % gridwidth) - py = dmi.height * (i // gridwidth) - im = image.crop((px, py, px + dmi.width, py + dmi.height)) - assert im.size == (dmi.width, dmi.height) - state.frames.append(im) - i += 1 - state._nframes = None - - return dmi - - def state(self, *args, **kwargs): - s = State(self, *args, **kwargs) - self.states.append(s) - return s - - @property - def default_state(self): - return self.states[0] - - def get_state(self, name): - for state in self.states: - if state.name == name: - return state - raise KeyError(name) - return self.default_state - - def _assemble_comment(self): - comment = "# BEGIN DMI\n" - comment += f"version = {self.version}\n" - comment += f"\twidth = {self.width}\n" - comment += f"\theight = {self.height}\n" - for state in self.states: - comment += f"state = {escape(state.name)}\n" - comment += f"\tdirs = {state.dirs}\n" - comment += f"\tframes = {state.framecount}\n" - if state.framecount > 1 and len(state.delays): #any(x != 1 for x in state.delays): - comment += "\tdelay = " + ",".join(map(str, state.delays)) + "\n" - if state.loop != 0: - comment += f"\tloop = {state.loop}\n" - if state.rewind: - comment += "\trewind = 1\n" - if state.movement: - comment += "\tmovement = 1\n" - if state.hotspots and any(state.hotspots): - current = None - for i, value in enumerate(state.hotspots): - if value != current: - x, y = value - comment += f"\thotspot = {x},{y},{i + 1}\n" - current = value - comment += "# END DMI" - return comment - - def to_file(self, filename, *, palette=False): - # assemble comment - comment = self._assemble_comment() - - # assemble spritesheet - W, H = self.width, self.height - num_frames = sum(len(state.frames) for state in self.states) - sqrt = math.ceil(math.sqrt(num_frames)) - output = Image.new('RGBA', (sqrt * W, math.ceil(num_frames / sqrt) * H)) - - i = 0 - for state in self.states: - for frame in state.frames: - output.paste(frame, ((i % sqrt) * W, (i // sqrt) * H)) - i += 1 - - # save - pnginfo = PngInfo() - pnginfo.add_text('Description', comment, zip=True) - if palette: - output = output.convert('P') - output.save(filename, 'png', optimize=True, pnginfo=pnginfo) - -class State: - def __init__(self, dmi, name, *, loop=LOOP_UNLIMITED, rewind=False, movement=False, dirs=1): - self.dmi = dmi - self.name = name - self.loop = loop - self.rewind = rewind - self.movement = movement - self.dirs = dirs - - self._nframes = None # used during loading only - self.frames = [] - self.delays = [] - self.hotspots = None - - @property - def framecount(self): - if self._nframes is not None: - return self._nframes - else: - return len(self.frames) // self.dirs - - def frame(self, image, *, delay=1): - assert image.size == (self.dmi.width, self.dmi.height) - self.delays.append(delay) - self.frames.append(image) - - def hotspot(self, first_frame, x, y): - if self.hotspots is None: - self.hotspots = [None] * self.framecount - for i in range(first_frame, self.framecount): - self.hotspots[i] = x, y - - def _frame_index(self, frame=0, dir=None): - ofs = DIR_ORDER.index(DIR_NAMES[dir]) - if ofs >= self.dirs: - ofs = 0 - return frame * self.dirs + ofs - - def get_frame(self, *args, **kwargs): - return self.frames[self._frame_index(*args, **kwargs)] - -def escape(text): - assert '\\' not in text and '"' not in text - return f'"{text}"' - -def unescape(text, quote='"'): - if text == 'null': - return None - if not (text.startswith(quote) and text.endswith(quote)): - raise ValueError(text) - text = text[1:-1] - assert '\\' not in text and quote not in text - return text - -def parse_num(value): - if '.' in value: - return float(value) - return int(value) - -def parse_bool(value): - if value not in ('0', '1'): - raise ValueError(value) - return value == '1' - -if __name__ == '__main__': - # test: can we load every DMI in the tree - import os - - count = 0 - for dirpath, dirnames, filenames in os.walk('.'): - if '.git' in dirnames: - dirnames.remove('.git') - for filename in filenames: - if filename.endswith('.dmi'): - Dmi.from_file(os.path.join(dirpath, filename)) - count += 1 - - print(f"Successfully parsed {count} dmi files") diff --git a/tools/mapmerge2-old/dmm.py b/tools/mapmerge2-old/dmm.py deleted file mode 100644 index 8bb1dca3537..00000000000 --- a/tools/mapmerge2-old/dmm.py +++ /dev/null @@ -1,554 +0,0 @@ -# Tools for working with DreamMaker maps - -import io -import bidict -import random -from collections import namedtuple - -TGM_HEADER = "//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE" -ENCODING = 'utf-8' - -Coordinate = namedtuple('Coordinate', ['x', 'y', 'z']) - -class DMM: - __slots__ = ['key_length', 'size', 'dictionary', 'grid', 'header'] - - def __init__(self, key_length, size): - self.key_length = key_length - self.size = size - self.dictionary = bidict.bidict() - self.grid = {} - self.header = None - - @staticmethod - def from_file(fname): - # stream the file rather than forcing all its contents to memory - with open(fname, 'r', encoding=ENCODING) as f: - return _parse(iter(lambda: f.read(1), '')) - - @staticmethod - def from_bytes(bytes): - return _parse(bytes.decode(ENCODING)) - - def to_file(self, fname, tgm = True): - self._presave_checks() - with open(fname, 'w', newline='\n', encoding=ENCODING) as f: - (save_tgm if tgm else save_dmm)(self, f) - - def to_bytes(self, tgm = True): - self._presave_checks() - bio = io.BytesIO() - with io.TextIOWrapper(bio, newline='\n', encoding=ENCODING) as f: - (save_tgm if tgm else save_dmm)(self, f) - f.flush() - return bio.getvalue() - - def generate_new_key(self): - free_keys = self._ensure_free_keys(1) - # choose one of the free keys at random - key = 0 - while free_keys: - if key not in self.dictionary: - # this construction is used to avoid needing to construct the - # full set in order to random.choice() from it - if random.random() < 1 / free_keys: - return key - free_keys -= 1 - key += 1 - - raise RuntimeError("ran out of keys, this shouldn't happen") - - def overwrite_key(self, key, fixed, bad_keys): - try: - self.dictionary[key] = fixed - return None - except bidict.DuplicationError: - old_key = self.dictionary.inv[fixed] - bad_keys[key] = old_key - print(f"Merging '{num_to_key(key, self.key_length)}' into '{num_to_key(old_key, self.key_length)}'") - return old_key - - def reassign_bad_keys(self, bad_keys): - if not bad_keys: - return - for k, v in self.grid.items(): - # reassign the grid entries which used the old key - self.grid[k] = bad_keys.get(v, v) - - def _presave_checks(self): - # last-second handling of bogus keys to help prevent and fix broken maps - self._ensure_free_keys(0) - max_key = max_key_for(self.key_length) - bad_keys = {key: 0 for key in self.dictionary.keys() if key > max_key} - if bad_keys: - print(f"Warning: fixing {len(bad_keys)} overflowing keys") - for k in bad_keys: - # create a new non-bogus key and transfer that value to it - new_key = bad_keys[k] = self.generate_new_key() - self.dictionary.forceput(new_key, self.dictionary[k]) - print(f" {num_to_key(k, self.key_length, True)} -> {num_to_key(new_key, self.key_length)}") - - # handle entries in the dictionary which have atoms in the wrong order - keys = list(self.dictionary.keys()) - for key in keys: - value = self.dictionary[key] - if is_bad_atom_ordering(num_to_key(key, self.key_length, True), value): - fixed = tuple(fix_atom_ordering(value)) - self.overwrite_key(key, fixed, bad_keys) - - self.reassign_bad_keys(bad_keys) - - def _ensure_free_keys(self, desired): - # ensure that free keys exist by increasing the key length if necessary - free_keys = max_key_for(self.key_length) - len(self.dictionary) - while free_keys < desired: - if self.key_length >= MAX_KEY_LENGTH: - raise KeyTooLarge(f"can't expand beyond key length {MAX_KEY_LENGTH} ({len(self.dictionary)} keys)") - self.key_length += 1 - free_keys = max_key_for(self.key_length) - len(self.dictionary) - return free_keys - - @property - def coords_zyx(self): - for z in range(1, self.size.z + 1): - for y in range(1, self.size.y + 1): - for x in range(1, self.size.x + 1): - yield (z, y, x) - - @property - def coords_z(self): - return range(1, self.size.z + 1) - - @property - def coords_yx(self): - for y in range(1, self.size.y + 1): - for x in range(1, self.size.x + 1): - yield (y, x) - -# ---------- -# key handling - -# Base 52 a-z A-Z dictionary for fast conversion -MAX_KEY_LENGTH = 3 # things will get ugly fast if you exceed this -BASE = 52 -base52 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' -base52_r = {x: i for i, x in enumerate(base52)} -assert len(base52) == BASE and len(base52_r) == BASE - -def key_to_num(key): - num = 0 - for ch in key: - num = BASE * num + base52_r[ch] - return num - -def num_to_key(num, key_length, allow_overflow=False): - if num >= (BASE ** key_length if allow_overflow else max_key_for(key_length)): - raise KeyTooLarge(f"num={num} does not fit in key_length={key_length}") - - result = '' - while num: - result = base52[num % BASE] + result - num //= BASE - - assert len(result) <= key_length - return base52[0] * (key_length - len(result)) + result - -def max_key_for(key_length): - # keys only go up to "ymo" = 65534, under-estimated just in case - # https://secure.byond.com/forum/?post=2340796#comment23770802 - return min(65530, BASE ** key_length) - -class KeyTooLarge(Exception): - pass - -# ---------- -# An actual atom parser - -def parse_map_atom(atom): - try: - i = atom.index('{') - except ValueError: - return atom, {} - - path, rest = atom[:i], atom[i+1:] - vars = {} - - in_string = False - in_name = False - escaping = False - current_name = '' - current = '' - for ch in rest: - if escaping: - escaping = False - current += ch - elif ch == '\\': - escaping = True - elif ch == '"': - in_string = not in_string - current += ch - elif in_string: - current += ch - elif ch == ';': - vars[current_name.strip()] = current.strip() - current_name = current = '' - elif ch == '=': - current_name = current - current = '' - elif ch == '}': - vars[current_name.strip()] = current.strip() - break - elif ch not in ' ': - current += ch - - return path, vars - -def is_bad_atom_ordering(key, atoms): - seen_turfs = 0 - seen_areas = 0 - can_fix = False - for each in atoms: - if each.startswith('/turf'): - if seen_turfs == 1: - print(f"Warning: key '{key}' has multiple turfs!") - if seen_areas: - print(f"Warning: key '{key}' has area before turf (autofixing...)") - can_fix = True - seen_turfs += 1 - elif each.startswith('/area'): - if seen_areas == 1: - print(f"Warning: key '{key}' has multiple areas!!!") - seen_areas += 1 - else: - if (seen_turfs or seen_areas) and not can_fix: - print(f"Warning: key '{key}' has movable after turf or area (autofixing...)") - can_fix = True - if not seen_areas or not seen_turfs: - print(f"Warning: key '{key}' is missing either a turf or area") - return can_fix - -def fix_atom_ordering(atoms): - movables = [] - turfs = [] - areas = [] - for each in atoms: - if each.startswith('/turf'): - turfs.append(each) - elif each.startswith('/area'): - areas.append(each) - else: - movables.append(each) - movables.extend(turfs) - movables.extend(areas) - return movables - -# ---------- -# TGM writer - -def save_tgm(dmm, output): - output.write(f"{TGM_HEADER}\n") - if dmm.header: - output.write(f"{dmm.header}\n") - - # write dictionary in tgm format - for key, value in sorted(dmm.dictionary.items()): - output.write(f'"{num_to_key(key, dmm.key_length)}" = (\n') - for idx, thing in enumerate(value): - in_quote_block = False - in_varedit_block = False - for char in thing: - if in_quote_block: - if char == '"': - in_quote_block = False - output.write(char) - elif char == '"': - in_quote_block = True - output.write(char) - elif not in_varedit_block: - if char == "{": - in_varedit_block = True - output.write("{\n\t") - else: - output.write(char) - elif char == ";": - output.write(";\n\t") - elif char == "}": - output.write("\n\t}") - in_varedit_block = False - else: - output.write(char) - if idx < len(value) - 1: - output.write(",\n") - output.write(")\n") - - # thanks to YotaXP for finding out about this one - max_x, max_y, max_z = dmm.size - for z in range(1, max_z + 1): - output.write("\n") - for x in range(1, max_x + 1): - output.write(f"({x},{1},{z}) = {{\"\n") - for y in range(1, max_y + 1): - output.write(f"{num_to_key(dmm.grid[x, y, z], dmm.key_length)}\n") - output.write("\"}\n") - -# ---------- -# DMM writer - -def save_dmm(dmm, output): - if dmm.header: - output.write(f"{dmm.header}\n") - - # writes a tile dictionary the same way Dreammaker does - for key, value in sorted(dmm.dictionary.items()): - output.write(f'"{num_to_key(key, dmm.key_length)}" = ({",".join(value)})\n') - - output.write("\n") - - # writes a map grid the same way Dreammaker does - max_x, max_y, max_z = dmm.size - for z in range(1, max_z + 1): - output.write(f"(1,1,{z}) = {{\"\n") - - for y in range(1, max_y + 1): - for x in range(1, max_x + 1): - try: - output.write(num_to_key(dmm.grid[x, y, z], dmm.key_length)) - except KeyError: - print(f"Key error: ({x}, {y}, {z})") - output.write("\n") - output.write("\"}\n") - -# ---------- -# Parser - -def _parse(map_raw_text): - in_comment_line = False - comment_trigger = False - - in_quote_block = False - in_key_block = False - in_data_block = False - in_varedit_block = False - after_data_block = False - escaping = False - skip_whitespace = False - - dictionary = bidict.bidict() - duplicate_keys = {} - curr_key_len = 0 - curr_key = 0 - curr_datum = "" - curr_data = list() - - in_map_block = False - in_coord_block = False - in_map_string = False - iter_x = 0 - adjust_y = True - - curr_num = "" - reading_coord = "x" - - key_length = 0 - - maxx = 0 - maxy = 0 - maxz = 0 - - curr_x = 0 - curr_y = 0 - curr_z = 0 - grid = dict() - - it = iter(map_raw_text) - - # map block - for char in it: - if char == "\n": - in_comment_line = False - comment_trigger = False - continue - elif in_comment_line: - continue - elif char in "\r\t": - continue - - if char == "/" and not in_quote_block: - if comment_trigger: - in_comment_line = True - continue - else: - comment_trigger = True - else: - comment_trigger = False - - if in_data_block: - - if in_varedit_block: - - if in_quote_block: - if char == "\\": - curr_datum = curr_datum + char - escaping = True - - elif escaping: - curr_datum = curr_datum + char - escaping = False - - elif char == "\"": - curr_datum = curr_datum + char - in_quote_block = False - - else: - curr_datum = curr_datum + char - - else: - if skip_whitespace and char == " ": - skip_whitespace = False - continue - skip_whitespace = False - - if char == "\"": - curr_datum = curr_datum + char - in_quote_block = True - - elif char == ";": - skip_whitespace = True - curr_datum = curr_datum + char - - elif char == "}": - curr_datum = curr_datum + char - in_varedit_block = False - - else: - curr_datum = curr_datum + char - - elif char == "{": - curr_datum = curr_datum + char - in_varedit_block = True - - elif char == ",": - curr_data.append(curr_datum) - curr_datum = "" - - elif char == ")": - curr_data.append(curr_datum) - curr_data = tuple(curr_data) - try: - dictionary[curr_key] = curr_data - except bidict.ValueDuplicationError: - # if the map has duplicate values, eliminate them now - duplicate_keys[curr_key] = dictionary.inv[curr_data] - curr_data = list() - curr_datum = "" - curr_key = 0 - curr_key_len = 0 - in_data_block = False - after_data_block = True - - else: - curr_datum = curr_datum + char - - elif in_key_block: - if char == "\"": - in_key_block = False - if key_length == 0: - key_length = curr_key_len - else: - assert key_length == curr_key_len - else: - curr_key = BASE * curr_key + base52_r[char] - curr_key_len += 1 - - # else we're looking for a key block, a data block or the map block - elif char == "\"": - in_key_block = True - after_data_block = False - - elif char == "(": - if after_data_block: - in_coord_block = True - after_data_block = False - curr_key = 0 - curr_key_len = 0 - break - else: - in_data_block = True - after_data_block = False - - # grid block - for char in it: - if char == "\r": - continue - - if in_coord_block: - if char == ",": - if reading_coord == "x": - curr_x = int(curr_num) - if curr_x > maxx: - maxx = curr_x - iter_x = 0 - curr_num = "" - reading_coord = "y" - elif reading_coord == "y": - curr_y = int(curr_num) - if curr_y > maxy: - maxy = curr_y - curr_num = "" - reading_coord = "z" - else: - raise ValueError("too many dimensions") - - elif char == ")": - curr_z = int(curr_num) - if curr_z > maxz: - maxz = curr_z - in_coord_block = False - reading_coord = "x" - curr_num = "" - - else: - curr_num = curr_num + char - - elif in_map_string: - if char == "\"": - in_map_string = False - adjust_y = True - curr_y -= 1 - - elif char == "\n": - if adjust_y: - adjust_y = False - else: - curr_y += 1 - if curr_x > maxx: - maxx = curr_x - if iter_x > 1: - curr_x = 1 - iter_x = 0 - - else: - curr_key = BASE * curr_key + base52_r[char] - curr_key_len += 1 - if curr_key_len == key_length: - iter_x += 1 - if iter_x > 1: - curr_x += 1 - - grid[curr_x, curr_y, curr_z] = duplicate_keys.get(curr_key, curr_key) - curr_key = 0 - curr_key_len = 0 - - # else look for coordinate block or a map string - elif char == "(": - in_coord_block = True - elif char == "\"": - in_map_string = True - - if curr_y > maxy: - maxy = curr_y - - data = DMM(key_length, Coordinate(maxx, maxy, maxz)) - data.dictionary = dictionary - data.grid = grid - return data diff --git a/tools/mapmerge2-old/dmm2tgm.bat b/tools/mapmerge2-old/dmm2tgm.bat deleted file mode 100644 index bcf6150c2ea..00000000000 --- a/tools/mapmerge2-old/dmm2tgm.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -set MAPROOT=../../_maps/ -set TGM=1 -python convert.py -pause diff --git a/tools/mapmerge2-old/frontend.py b/tools/mapmerge2-old/frontend.py deleted file mode 100644 index 4d44eab951e..00000000000 --- a/tools/mapmerge2-old/frontend.py +++ /dev/null @@ -1,127 +0,0 @@ -# Common code for the frontend interface of map tools -import sys -import os -import pathlib -import shutil -from collections import namedtuple - -Settings = namedtuple('Settings', ['map_folder', 'tgm']) -MapsToRun = namedtuple('MapsToRun', ['files', 'indices']) - -def string_to_num(s): - try: - return int(s) - except ValueError: - return -1 - -def read_settings(): - # discover map folder if needed - try: - map_folder = os.environ['MAPROOT'] - except KeyError: - map_folder = '_maps/' - for _ in range(8): - if os.path.exists(map_folder): - break - map_folder = os.path.join('..', map_folder) - else: - map_folder = None - - # assume TGM is True by default - tgm = os.environ.get('TGM', "1") == "1" - - return Settings(map_folder, tgm) - -def pretty_path(settings, path_str): - if settings.map_folder: - return path_str[len(os.path.commonpath([settings.map_folder, path_str]))+1:] - else: - return path_str - -def prompt_maps(settings, verb): - if not settings.map_folder: - print("Could not autodetect the _maps folder, set MAPROOT") - exit(1) - - list_of_files = list() - for root, directories, filenames in os.walk(settings.map_folder): - for filename in [f for f in filenames if f.endswith(".dmm")]: - list_of_files.append(pathlib.Path(root, filename)) - - last_dir = "" - for i, this_file in enumerate(list_of_files): - this_dir = this_file.parent - if last_dir != this_dir: - print("--------------------------------") - last_dir = this_dir - print("[{}]: {}".format(i, pretty_path(settings, str(this_file)))) - - print("--------------------------------") - in_list = input("List the maps you want to " + verb + " (example: 1,3-5,12):\n") - in_list = in_list.replace(" ", "") - in_list = in_list.split(",") - - valid_indices = list() - for m in in_list: - index_range = m.split("-") - if len(index_range) == 1: - index = string_to_num(index_range[0]) - if index >= 0 and index < len(list_of_files): - valid_indices.append(index) - elif len(index_range) == 2: - index0 = string_to_num(index_range[0]) - index1 = string_to_num(index_range[1]) - if index0 >= 0 and index0 <= index1 and index1 < len(list_of_files): - valid_indices.extend(range(index0, index1 + 1)) - - return MapsToRun(list_of_files, valid_indices) - -def process(settings, verb, *, modify=True, backup=None): - if backup is None: - backup = modify # by default, backup when we modify - assert modify or not backup # doesn't make sense to backup when not modifying - - if len(sys.argv) > 1: - maps = sys.argv[1:] - else: - maps = prompt_maps(settings, verb) - maps = [str(maps.files[i]) for i in maps.indices] - print() - - if not maps: - print("No maps selected.") - return - - if modify: - print(f"Maps WILL{'' if settings.tgm else ' NOT'} be converted to tgm.") - if backup: - print("Backups will be created with a \".before\" extension.") - else: - print("Warning: backups are NOT being taken.") - - print(f"\nWill {verb} these maps:") - for path_str in maps: - print(pretty_path(settings, path_str)) - - try: - confirm = input(f"\nPress Enter to {verb}...\n") - except KeyboardInterrupt: - confirm = "^C" - if confirm != "": - print(f"\nAborted.") - return - - for path_str in maps: - print(f' - {pretty_path(settings, path_str)}') - - if backup: - shutil.copyfile(path_str, path_str + ".before") - - try: - yield path_str - except Exception as e: - print(f"Error: {e}") - else: - print("Succeeded.") - - print("\nFinished.") diff --git a/tools/mapmerge2-old/map_scripts/cornersfix.txt b/tools/mapmerge2-old/map_scripts/cornersfix.txt deleted file mode 100644 index d9ff8a20232..00000000000 --- a/tools/mapmerge2-old/map_scripts/cornersfix.txt +++ /dev/null @@ -1,30 +0,0 @@ -/obj/effect/turf_decal/stripes/corner {dir=1} : /obj/item/bear_armor {@OLD;dir=8} -/obj/effect/turf_decal/stripes/corner {dir=2} : /obj/effect/turf_decal/stripes/corner {@OLD;dir=@SKIP} -/obj/effect/turf_decal/stripes/corner {dir=4} : /obj/effect/turf_decal/stripes/corner {@OLD;dir=1} -/obj/effect/turf_decal/stripes/corner {dir=8} : /obj/effect/turf_decal/stripes/corner {@OLD;dir=4} -/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/stripes/corner {@OLD} -/obj/effect/turf_decal/stripes/red/corner {dir=1} : /obj/item/bear_armor {@OLD;dir=8} -/obj/effect/turf_decal/stripes/red/corner {dir=2} : /obj/effect/turf_decal/stripes/red/corner {@OLD;dir=@SKIP} -/obj/effect/turf_decal/stripes/red/corner {dir=4} : /obj/effect/turf_decal/stripes/red/corner {@OLD;dir=1} -/obj/effect/turf_decal/stripes/red/corner {dir=8} : /obj/effect/turf_decal/stripes/red/corner {@OLD;dir=4} -/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/stripes/red/corner {@OLD} -/obj/effect/turf_decal/stripes/white/corner {dir=1} : /obj/item/bear_armor {@OLD;dir=8} -/obj/effect/turf_decal/stripes/white/corner {dir=2} : /obj/effect/turf_decal/stripes/white/corner {@OLD;dir=@SKIP} -/obj/effect/turf_decal/stripes/white/corner {dir=4} : /obj/effect/turf_decal/stripes/white/corner {@OLD;dir=1} -/obj/effect/turf_decal/stripes/white/corner {dir=8} : /obj/effect/turf_decal/stripes/white/corner {@OLD;dir=4} -/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/stripes/white/corner {@OLD} -/obj/effect/turf_decal/box/corners {dir=1} : /obj/item/bear_armor {@OLD;dir=8} -/obj/effect/turf_decal/box/corners {dir=2} : /obj/effect/turf_decal/box/corners {@OLD;dir=@SKIP} -/obj/effect/turf_decal/box/corners {dir=4} : /obj/effect/turf_decal/box/corners {@OLD;dir=1} -/obj/effect/turf_decal/box/corners {dir=8} : /obj/effect/turf_decal/box/corners {@OLD;dir=4} -/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/box/corners {@OLD} -/obj/effect/turf_decal/box/red/corners {dir=1} : /obj/item/bear_armor {@OLD;dir=8} -/obj/effect/turf_decal/box/red/corners {dir=2} : /obj/effect/turf_decal/box/red/corners {@OLD;dir=@SKIP} -/obj/effect/turf_decal/box/red/corners {dir=4} : /obj/effect/turf_decal/box/red/corners {@OLD;dir=1} -/obj/effect/turf_decal/box/red/corners {dir=8} : /obj/effect/turf_decal/box/red/corners {@OLD;dir=4} -/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/box/red/corners {@OLD} -/obj/effect/turf_decal/box/white/corners {dir=1} : /obj/item/bear_armor {@OLD;dir=8} -/obj/effect/turf_decal/box/white/corners {dir=2} : /obj/effect/turf_decal/box/white/corners {@OLD;dir=@SKIP} -/obj/effect/turf_decal/box/white/corners {dir=4} : /obj/effect/turf_decal/box/white/corners {@OLD;dir=1} -/obj/effect/turf_decal/box/white/corners {dir=8} : /obj/effect/turf_decal/box/white/corners {@OLD;dir=4} -/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/box/white/corners {@OLD} \ No newline at end of file diff --git a/tools/mapmerge2-old/map_scripts/turfs2decals.txt b/tools/mapmerge2-old/map_scripts/turfs2decals.txt deleted file mode 100644 index 13ae02baf73..00000000000 --- a/tools/mapmerge2-old/map_scripts/turfs2decals.txt +++ /dev/null @@ -1,465 +0,0 @@ -/turf/open/floor/circuit/killroom : /turf/open/floor/circuit/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/airless/asteroid : /obj/effect/turf_decal/sand , /turf/open/floor/plasteel/airless {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/airless/bar : /obj/effect/turf_decal/tile/bar , /obj/effect/turf_decal/tile/bar {dir=1} , /turf/open/floor/plasteel/airless {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival {dir=1} : /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1} -/turf/open/floor/plasteel/arrival {dir=@UNSET} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival {dir=2} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival {dir=4} : /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival {dir=5} : /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival {dir=6} : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival {dir=8} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1} -/turf/open/floor/plasteel/arrival {dir=9} : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1} -/turf/open/floor/plasteel/arrival {dir=10} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival/corner {dir=1} : /turf/open/floor/plasteel/white/corner {@OLD} -/turf/open/floor/plasteel/arrival/corner {dir=@UNSET} : /turf/open/floor/plasteel/white/corner {@OLD} -/turf/open/floor/plasteel/arrival/corner {dir=2} : /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival/corner {dir=4} : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival/corner {dir=8} : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/asteroid : /obj/effect/turf_decal/sand , /turf/open/floor/plasteel -/turf/open/floor/plasteel/bar : /obj/effect/turf_decal/tile/bar , /obj/effect/turf_decal/tile/bar {dir=1} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/barber : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/corner : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/corner : /obj/effect/turf_decal/tile/brown {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold/corner : /obj/effect/turf_decal/tile/brown {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=1} -/turf/open/floor/plasteel/caution {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution {dir=2} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution {dir=4} : /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/checker {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution {dir=6} : /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=1} -/turf/open/floor/plasteel/caution {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=1} -/turf/open/floor/plasteel/caution {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/checker {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution/corner {dir=1} : /turf/open/floor/plasteel/dark/corner {@OLD} -/turf/open/floor/plasteel/caution/corner {dir=@UNSET} : /turf/open/floor/plasteel/dark/corner {@OLD} -/turf/open/floor/plasteel/caution/corner {dir=2} : /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution/corner {dir=4} : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution/corner {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/cmo : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/dark/telecomms/mainframe : /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/dark/telecomms/server : /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/dark/telecomms/server/walkway : /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/corner : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/corner : /obj/effect/turf_decal/tile/brown {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/corner : /obj/effect/turf_decal/tile/green {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/corner : /obj/effect/turf_decal/tile/purple {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/corner : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape {dir=1} : /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1} -/turf/open/floor/plasteel/escape {dir=@UNSET} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape {dir=2} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape {dir=4} : /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape {dir=5} : /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape {dir=6} : /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape {dir=8} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1} -/turf/open/floor/plasteel/escape {dir=9} : /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1} -/turf/open/floor/plasteel/escape {dir=10} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape/corner {dir=1} : /turf/open/floor/plasteel/white/corner {@OLD} -/turf/open/floor/plasteel/escape/corner {dir=@UNSET} : /turf/open/floor/plasteel/white/corner {@OLD} -/turf/open/floor/plasteel/escape/corner {dir=2} : /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape/corner {dir=4} : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape/corner {dir=8} : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/corner : /obj/effect/turf_decal/tile/green {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/hydrofloor : /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=1} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=@UNSET} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=2} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=4} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=5} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=6} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=8} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=9} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=10} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/corner : /obj/effect/turf_decal/tile/neutral {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/corner : /obj/effect/turf_decal/tile/purple {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/corner : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/airless : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/airless {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/snowdin : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/snowdin {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/telecomms : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/telecomms/mainframe : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/killroom : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=1} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=@UNSET} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=2} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=4} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=5} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=6} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=8} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=9} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=10} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/corner : /obj/effect/turf_decal/tile/neutral {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/corner : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/corner : /obj/effect/turf_decal/tile/green {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/corner : /obj/effect/turf_decal/tile/purple {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/corner : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} \ No newline at end of file diff --git a/tools/mapmerge2-old/mapmerge.bat b/tools/mapmerge2-old/mapmerge.bat deleted file mode 100644 index 5a066226b3c..00000000000 --- a/tools/mapmerge2-old/mapmerge.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -set MAPROOT=../../_maps/ -set TGM=1 -python mapmerge.py -pause diff --git a/tools/mapmerge2-old/mapmerge.py b/tools/mapmerge2-old/mapmerge.py deleted file mode 100644 index f449bd948f0..00000000000 --- a/tools/mapmerge2-old/mapmerge.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python3 -import frontend -import shutil -from dmm import * -from collections import defaultdict - -def merge_map(new_map, old_map, delete_unused=False): - if new_map.key_length != old_map.key_length: - print("Warning: Key lengths differ, taking new map") - print(f" Old: {old_map.key_length}") - print(f" New: {new_map.key_length}") - return new_map - - if new_map.size != old_map.size: - print("Warning: Map dimensions differ, taking new map") - print(f" Old: {old_map.size}") - print(f" New: {new_map.size}") - return new_map - - key_length, size = old_map.key_length, old_map.size - merged = DMM(key_length, size) - merged.dictionary = old_map.dictionary.copy() - - known_keys = dict() # mapping fron 'new' key to 'merged' key - unused_keys = set(old_map.dictionary.keys()) # keys going unused - - # step one: parse the new version, compare it to the old version, merge both - for z, y, x in new_map.coords_zyx: - new_key = new_map.grid[x, y, z] - # if this key has been processed before, it can immediately be merged - try: - merged.grid[x, y, z] = known_keys[new_key] - continue - except KeyError: - pass - - def select_key(assigned): - merged.grid[x, y, z] = known_keys[new_key] = assigned - - old_key = old_map.grid[x, y, z] - old_tile = old_map.dictionary[old_key] - new_tile = new_map.dictionary[new_key] - - # this tile is the exact same as before, so the old key is used - if new_tile == old_tile: - select_key(old_key) - unused_keys.remove(old_key) - - # the tile is different here, but if it exists in the merged dictionary, that key can be used - elif new_tile in merged.dictionary.inv: - newold_key = merged.dictionary.inv[new_tile] - select_key(newold_key) - unused_keys.remove(newold_key) - - # the tile is brand new and it needs a new key, but if the old key isn't being used any longer it can be used instead - elif old_tile not in new_map.dictionary.inv and old_key in unused_keys: - merged.dictionary[old_key] = new_tile - select_key(old_key) - unused_keys.remove(old_key) - - # all other options ruled out, a brand new key is generated for the brand new tile - else: - fresh_key = merged.generate_new_key() - merged.dictionary[fresh_key] = new_tile - select_key(fresh_key) - - # step two: delete unused keys - if unused_keys: - print(f"Notice: Trimming {len(unused_keys)} unused dictionary keys.") - for key in unused_keys: - del merged.dictionary[key] - - # sanity check: that the merged map equals the new map - for z, y, x in new_map.coords_zyx: - new_tile = new_map.dictionary[new_map.grid[x, y, z]] - merged_tile = merged.dictionary[merged.grid[x, y, z]] - if new_tile != merged_tile: - print(f"Error: the map has been mangled! This is a mapmerge bug!") - print(f"At {x},{y},{z}.") - print(f"Should be {new_tile}") - print(f"Instead is {merged_tile}") - raise RuntimeError() - - return merged - -def main(settings): - for fname in frontend.process(settings, "merge", backup=True): - shutil.copyfile(fname, fname + ".before") - old_map = DMM.from_file(fname + ".backup") - new_map = DMM.from_file(fname) - merge_map(new_map, old_map).to_file(fname, settings.tgm) - -if __name__ == '__main__': - main(frontend.read_settings()) diff --git a/tools/mapmerge2-old/merge_driver_dmi.py b/tools/mapmerge2-old/merge_driver_dmi.py deleted file mode 100644 index 37c0abd9543..00000000000 --- a/tools/mapmerge2-old/merge_driver_dmi.py +++ /dev/null @@ -1,177 +0,0 @@ -#!/usr/bin/env python3 -import sys -import dmi - -def images_equal(left, right): - if left.size != right.size: - return False - w, h = left.size - left_load, right_load = left.load(), right.load() - for y in range(0, h): - for x in range(0, w): - lpixel, rpixel = left_load[x, y], right_load[x, y] - # quietly ignore changes where both pixels are fully transparent - if lpixel != rpixel and (lpixel[3] != 0 or rpixel[3] != 0): - return False - return True - -def states_equal(left, right): - result = True - - # basic properties - for attr in ('loop', 'rewind', 'movement', 'dirs', 'delays', 'hotspots', 'framecount'): - lval, rval = getattr(left, attr), getattr(right, attr) - if lval != rval: - result = False - - # frames - for (left_frame, right_frame) in zip(left.frames, right.frames): - if not images_equal(left_frame, right_frame): - result = False - - return result - -def key_of(state): - return (state.name, state.movement) - -def dictify(sheet): - result = {} - for state in sheet.states: - k = key_of(state) - if k in result: - print(f" duplicate {k!r}") - result[k] = state - return result - -def three_way_merge(base, left, right): - base_dims = base.width, base.height - if base_dims != (left.width, left.height) or base_dims != (right.width, right.height): - print("Dimensions have changed:") - print(f" Base: {base.width} x {base.height}") - print(f" Ours: {left.width} x {left.height}") - print(f" Theirs: {right.width} x {right.height}") - return True, None - - base_states, left_states, right_states = dictify(base), dictify(left), dictify(right) - - new_left = {k: v for k, v in left_states.items() if k not in base_states} - new_right = {k: v for k, v in right_states.items() if k not in base_states} - new_both = {} - conflicts = [] - for key, state in list(new_left.items()): - in_right = new_right.get(key, None) - if in_right: - if states_equal(state, in_right): - # allow it - new_both[key] = state - else: - # generate conflict states - print(f" C: {state.name!r}: added differently in both!") - state.name = f"{state.name} !CONFLICT! left" - conflicts.append(state) - in_right.name = f"{state.name} !CONFLICT! right" - conflicts.append(in_right) - # don't add it a second time - del new_left[key] - del new_right[key] - - final_states = [] - # add states that are currently in the base - for state in base.states: - in_left = left_states.get(key_of(state), None) - in_right = right_states.get(key_of(state), None) - left_equals = in_left and states_equal(state, in_left) - right_equals = in_right and states_equal(state, in_right) - - if not in_left and not in_right: - # deleted in both left and right, it's just deleted - print(f" {state.name!r}: deleted in both") - elif not in_left: - # left deletes - print(f" {state.name!r}: deleted in left") - if not right_equals: - print(f" ... but modified in right") - final_states.append(in_right) - elif not in_right: - # right deletes - print(f" {state.name!r}: deleted in right") - if not left_equals: - print(f" ... but modified in left") - final_states.append(in_left) - elif left_equals and right_equals: - # changed in neither - #print(f"Same in both: {state.name!r}") - final_states.append(state) - elif left_equals: - # changed only in right - print(f" {state.name!r}: changed in left") - final_states.append(in_right) - elif right_equals: - # changed only in left - print(f" {state.name!r}: changed in right") - final_states.append(in_left) - elif states_equal(in_left, in_right): - # changed in both, to the same thing - print(f" {state.name!r}: changed same in both") - final_states.append(in_left) # either or - else: - # changed in both - name = state.name - print(f" C: {name!r}: changed differently in both!") - state.name = f"{name} !CONFLICT! base" - conflicts.append(state) - in_left.name = f"{name} !CONFLICT! left" - conflicts.append(in_left) - in_right.name = f"{name} !CONFLICT! right" - conflicts.append(in_right) - - # add states which both left and right added the same - for key, state in new_both.items(): - print(f" {state.name!r}: added same in both") - final_states.append(state) - - # add states that are brand-new in the left - for key, state in new_left.items(): - print(f" {state.name!r}: added in left") - final_states.append(state) - - # add states that are brand-new in the right - for key, state in new_right.items(): - print(f" {state.name!r}: added in right") - final_states.append(state) - - final_states.extend(conflicts) - merged = dmi.Dmi(base.width, base.height) - merged.states = final_states - return len(conflicts), merged - -def main(path, original, left, right): - print(f"Merging icon: {path}") - - icon_orig = dmi.Dmi.from_file(original) - icon_left = dmi.Dmi.from_file(left) - icon_right = dmi.Dmi.from_file(right) - - trouble, merged = three_way_merge(icon_orig, icon_left, icon_right) - if merged: - merged.to_file(left) - if trouble: - print("!!! Manual merge required!") - if merged: - print(" A best-effort merge was performed. You must edit the icon and remove all") - print(" icon states marked with !CONFLICT!, leaving only the desired icon.") - else: - print(" The icon was totally unable to be merged, you must start with one version") - print(" or the other and manually resolve the conflict.") - print(" Information about which states conflicted is listed above.") - return trouble - -if __name__ == '__main__': - if len(sys.argv) != 6: - print("DMI merge driver called with wrong number of arguments") - print(" usage: merge-driver-dmi %P %O %A %B %L") - exit(1) - - # "left" is also the file that ought to be overwritten - _, path, original, left, right, conflict_size_marker = sys.argv - exit(main(path, original, left, right)) diff --git a/tools/mapmerge2-old/precommit.py b/tools/mapmerge2-old/precommit.py deleted file mode 100644 index f5ea49a50ea..00000000000 --- a/tools/mapmerge2-old/precommit.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 -import os -import pygit2 -import dmm -from mapmerge import merge_map - -def main(repo): - if repo.index.conflicts: - print("You need to resolve merge conflicts first.") - return 1 - - try: - repo.lookup_reference('MERGE_HEAD') - print("Not running mapmerge for merge commit.") - return 0 - except KeyError: - pass - - changed = 0 - for path, status in repo.status().items(): - if path.endswith(".dmm") and (status & (pygit2.GIT_STATUS_INDEX_MODIFIED | pygit2.GIT_STATUS_INDEX_NEW)): - # read the index - index_entry = repo.index[path] - index_map = dmm.DMM.from_bytes(repo[index_entry.id].read_raw()) - - try: - head_blob = repo[repo[repo.head.target].tree[path].id] - except KeyError: - # New map, no entry in HEAD - print(f"Converting new map: {path}", flush=True) - assert (status & pygit2.GIT_STATUS_INDEX_NEW) - merged_map = index_map - else: - # Entry in HEAD, merge the index over it - print(f"Merging map: {path}", flush=True) - assert not (status & pygit2.GIT_STATUS_INDEX_NEW) - head_map = dmm.DMM.from_bytes(head_blob.read_raw()) - merged_map = merge_map(index_map, head_map) - - # write to the index - blob_id = repo.create_blob(merged_map.to_bytes()) - repo.index.add(pygit2.IndexEntry(path, blob_id, index_entry.mode)) - changed += 1 - - # write to the working directory if that's clean - if status & (pygit2.GIT_STATUS_WT_DELETED | pygit2.GIT_STATUS_WT_MODIFIED): - print(f"Warning: {path} has unindexed changes, not overwriting them") - else: - merged_map.to_file(os.path.join(repo.workdir, path)) - - if changed: - repo.index.write() - print(f"Merged {changed} maps.") - return 0 - -if __name__ == '__main__': - exit(main(pygit2.Repository(pygit2.discover_repository(os.getcwd())))) diff --git a/tools/mapmerge2-old/requirements-install.bat b/tools/mapmerge2-old/requirements-install.bat deleted file mode 100644 index 71341af8792..00000000000 --- a/tools/mapmerge2-old/requirements-install.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -python -m pip install -r requirements.txt -pause diff --git a/tools/mapmerge2-old/requirements.txt b/tools/mapmerge2-old/requirements.txt deleted file mode 100644 index 65d1a5e0b17..00000000000 --- a/tools/mapmerge2-old/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -pygit2==1.0.1 -bidict==0.13.1 -Pillow==7.1.1 diff --git a/tools/mapmerge2-old/tgm2dmm.bat b/tools/mapmerge2-old/tgm2dmm.bat deleted file mode 100644 index 2748533febf..00000000000 --- a/tools/mapmerge2-old/tgm2dmm.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -set MAPROOT=../../_maps/ -set TGM=0 -python convert.py -pause diff --git a/tools/mapmerge2-old/update_paths.py b/tools/mapmerge2-old/update_paths.py deleted file mode 100644 index 6359b6bb303..00000000000 --- a/tools/mapmerge2-old/update_paths.py +++ /dev/null @@ -1,163 +0,0 @@ -# A script and syntax for applying path updates to maps. -import re -import os -import argparse -import frontend -from dmm import * - -desc = """ -Update dmm files given update file/string. -Replacement syntax example: - /turf/open/floor/plasteel/warningline : /obj/effect/turf_decal {dir = @OLD ;tag = @SKIP;icon_state = @SKIP} - /turf/open/floor/plasteel/warningline : /obj/effect/turf_decal {@OLD} , /obj/thing {icon_state = @OLD:name; name = "meme"} - /turf/open/floor/plasteel/warningline{dir=2} : /obj/thing -New paths properties: - @OLD - if used as property name copies all modified properties from original path to this one - property = @SKIP - will not copy this property through when global @OLD is used. - property = @OLD - will copy this modified property from original object even if global @OLD is not used - property = @OLD:name - will copy [name] property from original object even if global @OLD is not used - Anything else is copied as written. -Old paths properties: - Will be used as a filter. - property = @UNSET - will apply the rule only if the property is not mapedited -""" - -default_map_directory = "../../_maps" -replacement_re = re.compile('\s*([^{]*)\s*(\{(.*)\})?') - -#urgent todo: replace with actual parser, this is slow as janitor in crit -split_re = re.compile('((?:[A-Za-z0-9_\-$]+)\s*=\s*(?:"(?:.+?)"|[^";]*)|@OLD)') - - -def props_to_string(props): - return "{{{0}}}".format(";".join([k+" = "+props[k] for k in props])) - - -def string_to_props(propstring, verbose = False): - props = dict() - for raw_prop in re.split(split_re, propstring): - if not raw_prop or raw_prop.strip() == ';': - continue - prop = raw_prop.split('=', maxsplit=1) - props[prop[0].strip()] = prop[1].strip() if len(prop) > 1 else None - if verbose: - print("{0} to {1}".format(propstring, props)) - return props - - -def parse_rep_string(replacement_string, verbose = False): - # translates /blah/blah {meme = "test",} into path,prop dictionary tuple - match = re.match(replacement_re, replacement_string) - path = match.group(1) - props = match.group(3) - if props: - prop_dict = string_to_props(props, verbose) - else: - prop_dict = dict() - return path.strip(), prop_dict - - -def update_path(dmm_data, replacement_string, verbose=False): - old_path_part, new_path_part = replacement_string.split(':', maxsplit=1) - old_path, old_path_props = parse_rep_string(old_path_part, verbose) - new_paths = list() - for replacement_def in new_path_part.split(','): - new_path, new_path_props = parse_rep_string(replacement_def, verbose) - new_paths.append((new_path, new_path_props)) - - def replace_def(match): - if match.group(2): - old_props = string_to_props(match.group(2), verbose) - else: - old_props = dict() - for filter_prop in old_path_props: - if filter_prop not in old_props: - if old_path_props[filter_prop] == "@UNSET": - continue - else: - return [match.group(0)] - else: - if old_props[filter_prop] != old_path_props[filter_prop] or old_path_props[filter_prop] == "@UNSET": - return [match.group(0)] #does not match current filter, skip the change. - if verbose: - print("Found match : {0}".format(match.group(0))) - out_paths = [] - for new_path, new_props in new_paths: - out = new_path - out_props = dict() - for prop_name, prop_value in new_props.items(): - if prop_name == "@OLD": - out_props = dict(old_props) - continue - if prop_value == "@SKIP": - out_props.pop(prop_name, None) - continue - if prop_value.startswith("@OLD"): - params = prop_value.split(":") - if prop_name in old_props: - out_props[prop_name] = old_props[params[1]] if len(params) > 1 else old_props[prop_name] - continue - out_props[prop_name] = prop_value - if out_props: - out += props_to_string(out_props) - out_paths.append(out) - if verbose: - print("Replacing with: {0}".format(out_paths)) - return out_paths - - def get_result(element): - p = re.compile("{0}\s*({{(.*)}})?$".format(re.escape(old_path))) - match = p.match(element) - if match: - return replace_def(match) # = re.sub(p,replace_def,element) - else: - return [element] - - bad_keys = {} - keys = list(dmm_data.dictionary.keys()) - for definition_key in keys: - def_value = dmm_data.dictionary[definition_key] - new_value = tuple(y for x in def_value for y in get_result(x)) - if new_value != def_value: - dmm_data.overwrite_key(definition_key, new_value, bad_keys) - dmm_data.reassign_bad_keys(bad_keys) - - -def update_map(map_filepath, updates, verbose=False): - print("Updating: {0}".format(map_filepath)) - dmm_data = DMM.from_file(map_filepath) - for update_string in updates: - update_path(dmm_data, update_string, verbose) - dmm_data.to_file(map_filepath, True) - - -def update_all_maps(map_directory, updates, verbose=False): - for root, _, files in os.walk(map_directory): - for filepath in files: - if filepath.endswith(".dmm"): - path = os.path.join(root, filepath) - update_map(path, updates, verbose) - - -def main(args): - if args.inline: - updates = [args.update_source] - else: - with open(args.update_source) as f: - updates = [line for line in f if line and not line.startswith("#") and not line.isspace()] - - if args.map: - update_map(args.map, updates, verbose=args.verbose) - else: - map_directory = args.directory or frontend.read_settings().map_folder - update_all_maps(map_directory, updates, verbose=args.verbose) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description=desc, formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument("update_source", help="update file path / line of update notation") - parser.add_argument("--map", "-m", help="path to update, defaults to all maps in maps directory") - parser.add_argument("--directory", "-d", help="path to maps directory, defaults to _maps/") - parser.add_argument("--inline", "-i", help="treat update source as update string instead of path", action="store_true") - parser.add_argument("--verbose", "-v", help="toggle detailed update information", action="store_true") - main(parser.parse_args()) diff --git a/tools/mapmerge2/I Forgot To Map Merge.bat b/tools/mapmerge2/I_Forgot_To_Map_Merge.bat similarity index 100% rename from tools/mapmerge2/I Forgot To Map Merge.bat rename to tools/mapmerge2/I_Forgot_To_Map_Merge.bat diff --git a/tools/mapmerge2/Prepare Maps.bat b/tools/mapmerge2/Prepare Maps.bat deleted file mode 100644 index 6955e9c877c..00000000000 --- a/tools/mapmerge2/Prepare Maps.bat +++ /dev/null @@ -1,12 +0,0 @@ -@echo off -cd ../../_maps/ - -for /R %%f in (*.dmm) do copy "%%f" "%%f.backup" - -cls -echo All dmm files in _maps directories have been backed up -echo Now you can make your changes... -echo --- -echo Remember to run mapmerge.bat just before you commit your changes! -echo --- -pause diff --git a/tools/mapmerge2/README.md b/tools/mapmerge2/README.md index 0ff4d21ac2e..58fe668a1fe 100644 --- a/tools/mapmerge2/README.md +++ b/tools/mapmerge2/README.md @@ -1,8 +1,27 @@ -# Map Merge 2 +# Map Merger -**Map Merge 2** is an improvement over previous map merging scripts, with -better merge-conflict prevention, multi-Z support, and automatic handling of -key overflow. For up-to-date tips and tricks, also visit the [Map Merger] wiki article. +The **Map Merger** is a collection of scripts that keep this repository's maps +in a format which is easier to track in Git and less likely to cause merge +conflicts. When merge conflicts do occur, it can sometimes resolve them. + +For detailed troubleshooting instructions and other tips, visit the +[Map Merger] wiki article. + +## Installation + +To install the [Git hooks], open the `tools/hooks/` folder and double-click +`Install.bat`. Linux users run `tools/hooks/install.sh`. + +## Manual Use + +If using a Git GUI which is not compatible with the hooks: + +* Before committing, double-click `Run_Before_Committing.bat` +* When a merge has map conflicts, double-click `Resolve_Map_Conflicts.bat` + +The console will show whether the operation succeeded. + +For more details, see the [Map Merger] wiki article. ## What Map Merging Is @@ -13,16 +32,8 @@ version of the map while maintaining all the actual changes. It requires an old version of the map to use as a reference and a new version of the map which contains the desired changes. -## Installation - -To install Python dependencies, run `requirements-install.bat`, or run -`python -m pip install -r requirements.txt` directly. See the [Git hooks] -documentation to install the Git pre-commit hook which runs the map merger -automatically, or use `tools/mapmerge/Prepare Maps.bat` to save backups before -running `mapmerge.bat`. - -For up-to-date installation and detailed troubleshooting instructions, visit -the [Map Merger] wiki article. +Map Merge 2 adds multi-Z support, automatic handling of key overflow, better +merge conflict prevention, and a real merge conflict resolver. ## Code Structure diff --git a/tools/mapmerge2/Resolve Map Conflicts.bat b/tools/mapmerge2/Resolve_Map_Conflicts.bat similarity index 100% rename from tools/mapmerge2/Resolve Map Conflicts.bat rename to tools/mapmerge2/Resolve_Map_Conflicts.bat diff --git a/tools/mapmerge2/Run Before Committing.bat b/tools/mapmerge2/Run_Before_Committing.bat similarity index 100% rename from tools/mapmerge2/Run Before Committing.bat rename to tools/mapmerge2/Run_Before_Committing.bat diff --git a/tools/mapmerge2/convert.py b/tools/mapmerge2/convert.py index 35e5dda4433..63fe8cbb9a0 100755 --- a/tools/mapmerge2/convert.py +++ b/tools/mapmerge2/convert.py @@ -1,8 +1,7 @@ #!/usr/bin/env python3 -import frontend -import dmm +from . import frontend, dmm if __name__ == '__main__': settings = frontend.read_settings() for fname in frontend.process(settings, "convert"): - dmm.DMM.from_file(fname).to_file(fname, settings.tgm) + dmm.DMM.from_file(fname).to_file(fname, tgm = settings.tgm) diff --git a/tools/mapmerge2/dmi.py b/tools/mapmerge2/dmi.py deleted file mode 100755 index f0a8182c9f0..00000000000 --- a/tools/mapmerge2/dmi.py +++ /dev/null @@ -1,253 +0,0 @@ -# Tools for working with modern DreamMaker icon files (PNGs + metadata) - -import math -from PIL import Image -from PIL.PngImagePlugin import PngInfo - -DEFAULT_SIZE = 32, 32 -LOOP_UNLIMITED = 0 -LOOP_ONCE = 1 - -NORTH = 1 -SOUTH = 2 -EAST = 4 -WEST = 8 -SOUTHEAST = SOUTH|EAST -SOUTHWEST = SOUTH|WEST -NORTHEAST = NORTH|EAST -NORTHWEST = NORTH|WEST - -CARDINALS = [NORTH, SOUTH, EAST, WEST] -DIR_ORDER = [SOUTH, NORTH, EAST, WEST, SOUTHEAST, SOUTHWEST, NORTHEAST, NORTHWEST] -DIR_NAMES = { - 'SOUTH': SOUTH, - 'NORTH': NORTH, - 'EAST': EAST, - 'WEST': WEST, - 'SOUTHEAST': SOUTHEAST, - 'SOUTHWEST': SOUTHWEST, - 'NORTHEAST': NORTHEAST, - 'NORTHWEST': NORTHWEST, - **{str(x): x for x in DIR_ORDER}, - **{x: x for x in DIR_ORDER}, - '0': SOUTH, - None: SOUTH, -} - -class Dmi: - version = "4.0" - - def __init__(self, width, height): - self.width = width - self.height = height - self.states = [] - - @classmethod - def from_file(cls, fname): - image = Image.open(fname) - - # no metadata = regular image file - if 'Description' not in image.info: - dmi = Dmi(*image.size) - state = dmi.state("") - state.frame(image) - return dmi - - # read metadata - metadata = image.info['Description'] - line_iter = iter(metadata.splitlines()) - assert next(line_iter) == "# BEGIN DMI" - assert next(line_iter) == f"version = {cls.version}" - - dmi = Dmi(*DEFAULT_SIZE) - state = None - - for line in line_iter: - if line == "# END DMI": - break - key, value = line.lstrip().split(" = ") - if key == 'width': - dmi.width = int(value) - elif key == 'height': - dmi.height = int(value) - elif key == 'state': - state = dmi.state(unescape(value)) - elif key == 'dirs': - state.dirs = int(value) - elif key == 'frames': - state._nframes = int(value) - elif key == 'delay': - state.delays = [parse_num(x) for x in value.split(',')] - elif key == 'loop': - state.loop = int(value) - elif key == 'rewind': - state.rewind = parse_bool(value) - elif key == 'hotspot': - x, y, frm = [int(x) for x in value.split(',')] - state.hotspot(frm - 1, x, y) - elif key == 'movement': - state.movement = parse_bool(value) - else: - raise NotImplementedError(key) - - # cut image into frames - width, height = image.size - gridwidth = width // dmi.width - i = 0 - for state in dmi.states: - for frame in range(state._nframes): - for dir in range(state.dirs): - px = dmi.width * (i % gridwidth) - py = dmi.height * (i // gridwidth) - im = image.crop((px, py, px + dmi.width, py + dmi.height)) - assert im.size == (dmi.width, dmi.height) - state.frames.append(im) - i += 1 - state._nframes = None - - return dmi - - def state(self, *args, **kwargs): - s = State(self, *args, **kwargs) - self.states.append(s) - return s - - @property - def default_state(self): - return self.states[0] - - def get_state(self, name): - for state in self.states: - if state.name == name: - return state - raise KeyError(name) - return self.default_state - - def _assemble_comment(self): - comment = "# BEGIN DMI\n" - comment += f"version = {self.version}\n" - comment += f"\twidth = {self.width}\n" - comment += f"\theight = {self.height}\n" - for state in self.states: - comment += f"state = {escape(state.name)}\n" - comment += f"\tdirs = {state.dirs}\n" - comment += f"\tframes = {state.framecount}\n" - if state.framecount > 1 and len(state.delays): #any(x != 1 for x in state.delays): - comment += "\tdelay = " + ",".join(map(str, state.delays)) + "\n" - if state.loop != 0: - comment += f"\tloop = {state.loop}\n" - if state.rewind: - comment += "\trewind = 1\n" - if state.movement: - comment += "\tmovement = 1\n" - if state.hotspots and any(state.hotspots): - current = None - for i, value in enumerate(state.hotspots): - if value != current: - x, y = value - comment += f"\thotspot = {x},{y},{i + 1}\n" - current = value - comment += "# END DMI" - return comment - - def to_file(self, filename, *, palette=False): - # assemble comment - comment = self._assemble_comment() - - # assemble spritesheet - W, H = self.width, self.height - num_frames = sum(len(state.frames) for state in self.states) - sqrt = math.ceil(math.sqrt(num_frames)) - output = Image.new('RGBA', (sqrt * W, math.ceil(num_frames / sqrt) * H)) - - i = 0 - for state in self.states: - for frame in state.frames: - output.paste(frame, ((i % sqrt) * W, (i // sqrt) * H)) - i += 1 - - # save - pnginfo = PngInfo() - pnginfo.add_text('Description', comment, zip=True) - if palette: - output = output.convert('P') - output.save(filename, 'png', optimize=True, pnginfo=pnginfo) - -class State: - def __init__(self, dmi, name, *, loop=LOOP_UNLIMITED, rewind=False, movement=False, dirs=1): - self.dmi = dmi - self.name = name - self.loop = loop - self.rewind = rewind - self.movement = movement - self.dirs = dirs - - self._nframes = None # used during loading only - self.frames = [] - self.delays = [] - self.hotspots = None - - @property - def framecount(self): - if self._nframes is not None: - return self._nframes - else: - return len(self.frames) // self.dirs - - def frame(self, image, *, delay=1): - assert image.size == (self.dmi.width, self.dmi.height) - self.delays.append(delay) - self.frames.append(image) - - def hotspot(self, first_frame, x, y): - if self.hotspots is None: - self.hotspots = [None] * self.framecount - for i in range(first_frame, self.framecount): - self.hotspots[i] = x, y - - def _frame_index(self, frame=0, dir=None): - ofs = DIR_ORDER.index(DIR_NAMES[dir]) - if ofs >= self.dirs: - ofs = 0 - return frame * self.dirs + ofs - - def get_frame(self, *args, **kwargs): - return self.frames[self._frame_index(*args, **kwargs)] - -def escape(text): - assert '\\' not in text and '"' not in text - return f'"{text}"' - -def unescape(text, quote='"'): - if text == 'null': - return None - if not (text.startswith(quote) and text.endswith(quote)): - raise ValueError(text) - text = text[1:-1] - assert '\\' not in text and quote not in text - return text - -def parse_num(value): - if '.' in value: - return float(value) - return int(value) - -def parse_bool(value): - if value not in ('0', '1'): - raise ValueError(value) - return value == '1' - -if __name__ == '__main__': - # test: can we load every DMI in the tree - import os - - count = 0 - for dirpath, dirnames, filenames in os.walk('.'): - if '.git' in dirnames: - dirnames.remove('.git') - for filename in filenames: - if filename.endswith('.dmi'): - Dmi.from_file(os.path.join(dirpath, filename)) - count += 1 - - print(f"Successfully parsed {count} dmi files") diff --git a/tools/mapmerge2/dmm.py b/tools/mapmerge2/dmm.py index 8bb1dca3537..5702ed21edc 100755 --- a/tools/mapmerge2/dmm.py +++ b/tools/mapmerge2/dmm.py @@ -22,20 +22,19 @@ def __init__(self, key_length, size): @staticmethod def from_file(fname): - # stream the file rather than forcing all its contents to memory with open(fname, 'r', encoding=ENCODING) as f: - return _parse(iter(lambda: f.read(1), '')) + return _parse(f.read()) @staticmethod def from_bytes(bytes): return _parse(bytes.decode(ENCODING)) - def to_file(self, fname, tgm = True): + def to_file(self, fname, *, tgm = True): self._presave_checks() with open(fname, 'w', newline='\n', encoding=ENCODING) as f: (save_tgm if tgm else save_dmm)(self, f) - def to_bytes(self, tgm = True): + def to_bytes(self, *, tgm = True): self._presave_checks() bio = io.BytesIO() with io.TextIOWrapper(bio, newline='\n', encoding=ENCODING) as f: @@ -43,20 +42,29 @@ def to_bytes(self, tgm = True): f.flush() return bio.getvalue() + def get_or_generate_key(self, tile): + try: + return self.dictionary.inv[tile] + except KeyError: + key = self.generate_new_key() + self.dictionary[key] = tile + return key + + def get_tile(self, coord): + return self.dictionary[self.grid[coord]] + + def set_tile(self, coord, tile): + tile = tuple(tile) + self.grid[coord] = self.get_or_generate_key(tile) + def generate_new_key(self): - free_keys = self._ensure_free_keys(1) + self._ensure_free_keys(1) + max_key = max_key_for(self.key_length) # choose one of the free keys at random - key = 0 - while free_keys: - if key not in self.dictionary: - # this construction is used to avoid needing to construct the - # full set in order to random.choice() from it - if random.random() < 1 / free_keys: - return key - free_keys -= 1 - key += 1 - - raise RuntimeError("ran out of keys, this shouldn't happen") + key = random.randint(0, max_key - 1) + while key in self.dictionary: + key = random.randint(0, max_key - 1) + return key def overwrite_key(self, key, fixed, bad_keys): try: @@ -75,6 +83,14 @@ def reassign_bad_keys(self, bad_keys): # reassign the grid entries which used the old key self.grid[k] = bad_keys.get(v, v) + def remove_unused_keys(self, modified_keys = None): + unused_keys = list(set(modified_keys)) if modified_keys is not None else self.dictionary.keys() + for key in self.grid.values(): + if key in unused_keys: + unused_keys.remove(key) + for key in unused_keys: + del self.dictionary[key] + def _presave_checks(self): # last-second handling of bogus keys to help prevent and fix broken maps self._ensure_free_keys(0) @@ -125,6 +141,9 @@ def coords_yx(self): for x in range(1, self.size.x + 1): yield (y, x) + def __repr__(self): + return f"DMM(size={self.size}, key_length={self.key_length}, dictionary_size={len(self.dictionary)})" + # ---------- # key handling @@ -227,10 +246,8 @@ def is_bad_atom_ordering(key, atoms): print(f"Warning: key '{key}' is missing either a turf or area") return can_fix -def fix_atom_ordering(atoms): - movables = [] - turfs = [] - areas = [] +def split_atom_groups(atoms): + movables, turfs, areas = [], [], [] for each in atoms: if each.startswith('/turf'): turfs.append(each) @@ -238,6 +255,10 @@ def fix_atom_ordering(atoms): areas.append(each) else: movables.append(each) + return movables, turfs, areas + +def fix_atom_ordering(atoms): + movables, turfs, areas = split_atom_groups(atoms) movables.extend(turfs) movables.extend(areas) return movables @@ -287,7 +308,7 @@ def save_tgm(dmm, output): output.write("\n") for x in range(1, max_x + 1): output.write(f"({x},{1},{z}) = {{\"\n") - for y in range(1, max_y + 1): + for y in range(max_y, 0, -1): output.write(f"{num_to_key(dmm.grid[x, y, z], dmm.key_length)}\n") output.write("\"}\n") @@ -309,7 +330,7 @@ def save_dmm(dmm, output): for z in range(1, max_z + 1): output.write(f"(1,1,{z}) = {{\"\n") - for y in range(1, max_y + 1): + for y in range(max_y, 0, -1): for x in range(1, max_x + 1): try: output.write(num_to_key(dmm.grid[x, y, z], dmm.key_length)) @@ -343,7 +364,7 @@ def _parse(map_raw_text): in_map_block = False in_coord_block = False in_map_string = False - iter_x = 0 + base_x = 0 adjust_y = True curr_num = "" @@ -487,7 +508,7 @@ def _parse(map_raw_text): curr_x = int(curr_num) if curr_x > maxx: maxx = curr_x - iter_x = 0 + base_x = curr_x curr_num = "" reading_coord = "y" elif reading_coord == "y": @@ -521,21 +542,15 @@ def _parse(map_raw_text): adjust_y = False else: curr_y += 1 - if curr_x > maxx: - maxx = curr_x - if iter_x > 1: - curr_x = 1 - iter_x = 0 - + curr_x = base_x else: curr_key = BASE * curr_key + base52_r[char] curr_key_len += 1 if curr_key_len == key_length: - iter_x += 1 - if iter_x > 1: - curr_x += 1 - grid[curr_x, curr_y, curr_z] = duplicate_keys.get(curr_key, curr_key) + if curr_x > maxx: + maxx = curr_x + curr_x += 1 curr_key = 0 curr_key_len = 0 @@ -548,7 +563,17 @@ def _parse(map_raw_text): if curr_y > maxy: maxy = curr_y + if not grid: + # Usually caused by unbalanced quotes. + max_key = num_to_key(max(dictionary.keys()), key_length, True) + raise ValueError(f"dmm failed to parse, check for a syntax error near or after key {max_key!r}") + + # Convert from raw .dmm coordinates to DM/BYOND coordinates by flipping Y + grid2 = dict() + for (x, y, z), tile in grid.items(): + grid2[x, maxy + 1 - y, z] = tile + data = DMM(key_length, Coordinate(maxx, maxy, maxz)) data.dictionary = dictionary - data.grid = grid + data.grid = grid2 return data diff --git a/tools/mapmerge2/dmm2tgm.bat b/tools/mapmerge2/dmm2tgm.bat deleted file mode 100644 index bcf6150c2ea..00000000000 --- a/tools/mapmerge2/dmm2tgm.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -set MAPROOT=../../_maps/ -set TGM=1 -python convert.py -pause diff --git a/tools/mapmerge2/dmm_test.py b/tools/mapmerge2/dmm_test.py index 02f5383f2ab..581a48e88a5 100755 --- a/tools/mapmerge2/dmm_test.py +++ b/tools/mapmerge2/dmm_test.py @@ -1,5 +1,4 @@ -import os -import sys +import os, sys from .dmm import * diff --git a/tools/mapmerge2/fixup.py b/tools/mapmerge2/fixup.py index 6953e7ab778..89346949065 100755 --- a/tools/mapmerge2/fixup.py +++ b/tools/mapmerge2/fixup.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -import os -import pygit2 +import os, pygit2 from . import dmm from .mapmerge import merge_map diff --git a/tools/mapmerge2/map_scripts/cornersfix.txt b/tools/mapmerge2/map_scripts/cornersfix.txt deleted file mode 100644 index d9ff8a20232..00000000000 --- a/tools/mapmerge2/map_scripts/cornersfix.txt +++ /dev/null @@ -1,30 +0,0 @@ -/obj/effect/turf_decal/stripes/corner {dir=1} : /obj/item/bear_armor {@OLD;dir=8} -/obj/effect/turf_decal/stripes/corner {dir=2} : /obj/effect/turf_decal/stripes/corner {@OLD;dir=@SKIP} -/obj/effect/turf_decal/stripes/corner {dir=4} : /obj/effect/turf_decal/stripes/corner {@OLD;dir=1} -/obj/effect/turf_decal/stripes/corner {dir=8} : /obj/effect/turf_decal/stripes/corner {@OLD;dir=4} -/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/stripes/corner {@OLD} -/obj/effect/turf_decal/stripes/red/corner {dir=1} : /obj/item/bear_armor {@OLD;dir=8} -/obj/effect/turf_decal/stripes/red/corner {dir=2} : /obj/effect/turf_decal/stripes/red/corner {@OLD;dir=@SKIP} -/obj/effect/turf_decal/stripes/red/corner {dir=4} : /obj/effect/turf_decal/stripes/red/corner {@OLD;dir=1} -/obj/effect/turf_decal/stripes/red/corner {dir=8} : /obj/effect/turf_decal/stripes/red/corner {@OLD;dir=4} -/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/stripes/red/corner {@OLD} -/obj/effect/turf_decal/stripes/white/corner {dir=1} : /obj/item/bear_armor {@OLD;dir=8} -/obj/effect/turf_decal/stripes/white/corner {dir=2} : /obj/effect/turf_decal/stripes/white/corner {@OLD;dir=@SKIP} -/obj/effect/turf_decal/stripes/white/corner {dir=4} : /obj/effect/turf_decal/stripes/white/corner {@OLD;dir=1} -/obj/effect/turf_decal/stripes/white/corner {dir=8} : /obj/effect/turf_decal/stripes/white/corner {@OLD;dir=4} -/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/stripes/white/corner {@OLD} -/obj/effect/turf_decal/box/corners {dir=1} : /obj/item/bear_armor {@OLD;dir=8} -/obj/effect/turf_decal/box/corners {dir=2} : /obj/effect/turf_decal/box/corners {@OLD;dir=@SKIP} -/obj/effect/turf_decal/box/corners {dir=4} : /obj/effect/turf_decal/box/corners {@OLD;dir=1} -/obj/effect/turf_decal/box/corners {dir=8} : /obj/effect/turf_decal/box/corners {@OLD;dir=4} -/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/box/corners {@OLD} -/obj/effect/turf_decal/box/red/corners {dir=1} : /obj/item/bear_armor {@OLD;dir=8} -/obj/effect/turf_decal/box/red/corners {dir=2} : /obj/effect/turf_decal/box/red/corners {@OLD;dir=@SKIP} -/obj/effect/turf_decal/box/red/corners {dir=4} : /obj/effect/turf_decal/box/red/corners {@OLD;dir=1} -/obj/effect/turf_decal/box/red/corners {dir=8} : /obj/effect/turf_decal/box/red/corners {@OLD;dir=4} -/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/box/red/corners {@OLD} -/obj/effect/turf_decal/box/white/corners {dir=1} : /obj/item/bear_armor {@OLD;dir=8} -/obj/effect/turf_decal/box/white/corners {dir=2} : /obj/effect/turf_decal/box/white/corners {@OLD;dir=@SKIP} -/obj/effect/turf_decal/box/white/corners {dir=4} : /obj/effect/turf_decal/box/white/corners {@OLD;dir=1} -/obj/effect/turf_decal/box/white/corners {dir=8} : /obj/effect/turf_decal/box/white/corners {@OLD;dir=4} -/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/box/white/corners {@OLD} \ No newline at end of file diff --git a/tools/mapmerge2/map_scripts/turfs2decals.txt b/tools/mapmerge2/map_scripts/turfs2decals.txt deleted file mode 100644 index 13ae02baf73..00000000000 --- a/tools/mapmerge2/map_scripts/turfs2decals.txt +++ /dev/null @@ -1,465 +0,0 @@ -/turf/open/floor/circuit/killroom : /turf/open/floor/circuit/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/airless/asteroid : /obj/effect/turf_decal/sand , /turf/open/floor/plasteel/airless {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/airless/bar : /obj/effect/turf_decal/tile/bar , /obj/effect/turf_decal/tile/bar {dir=1} , /turf/open/floor/plasteel/airless {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival {dir=1} : /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1} -/turf/open/floor/plasteel/arrival {dir=@UNSET} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival {dir=2} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival {dir=4} : /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival {dir=5} : /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival {dir=6} : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival {dir=8} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1} -/turf/open/floor/plasteel/arrival {dir=9} : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1} -/turf/open/floor/plasteel/arrival {dir=10} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival/corner {dir=1} : /turf/open/floor/plasteel/white/corner {@OLD} -/turf/open/floor/plasteel/arrival/corner {dir=@UNSET} : /turf/open/floor/plasteel/white/corner {@OLD} -/turf/open/floor/plasteel/arrival/corner {dir=2} : /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival/corner {dir=4} : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/arrival/corner {dir=8} : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/asteroid : /obj/effect/turf_decal/sand , /turf/open/floor/plasteel -/turf/open/floor/plasteel/bar : /obj/effect/turf_decal/tile/bar , /obj/effect/turf_decal/tile/bar {dir=1} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/barber : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blue/corner : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/blueyellow/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/corner : /obj/effect/turf_decal/tile/brown {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/brownold/corner : /obj/effect/turf_decal/tile/brown {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=1} -/turf/open/floor/plasteel/caution {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution {dir=2} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution {dir=4} : /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/checker {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution {dir=6} : /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=1} -/turf/open/floor/plasteel/caution {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=1} -/turf/open/floor/plasteel/caution {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/checker {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution/corner {dir=1} : /turf/open/floor/plasteel/dark/corner {@OLD} -/turf/open/floor/plasteel/caution/corner {dir=@UNSET} : /turf/open/floor/plasteel/dark/corner {@OLD} -/turf/open/floor/plasteel/caution/corner {dir=2} : /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution/corner {dir=4} : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/caution/corner {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/cmo : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/dark/telecomms/mainframe : /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/dark/telecomms/server : /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/dark/telecomms/server/walkway : /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/corner : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkblue/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/side {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkbrown/corner : /obj/effect/turf_decal/tile/brown {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/corner : /obj/effect/turf_decal/tile/green {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/corner : /obj/effect/turf_decal/tile/purple {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/corner : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkred/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape {dir=1} : /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1} -/turf/open/floor/plasteel/escape {dir=@UNSET} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape {dir=2} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape {dir=4} : /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape {dir=5} : /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape {dir=6} : /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape {dir=8} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1} -/turf/open/floor/plasteel/escape {dir=9} : /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1} -/turf/open/floor/plasteel/escape {dir=10} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape/corner {dir=1} : /turf/open/floor/plasteel/white/corner {@OLD} -/turf/open/floor/plasteel/escape/corner {dir=@UNSET} : /turf/open/floor/plasteel/white/corner {@OLD} -/turf/open/floor/plasteel/escape/corner {dir=2} : /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape/corner {dir=4} : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/escape/corner {dir=8} : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/corner : /obj/effect/turf_decal/tile/green {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/green/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenblue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/greenyellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/hydrofloor : /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=1} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=@UNSET} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=2} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=4} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=5} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=6} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=8} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=9} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side {dir=10} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/corner : /obj/effect/turf_decal/tile/neutral {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/neutral/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/orange/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/side {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/purple/corner : /obj/effect/turf_decal/tile/purple {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/red/corner : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/redside {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redblue/blueside {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redgreen/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/redyellow/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/airless : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/airless {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/snowdin : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/snowdin {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/telecomms : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/telecomms/mainframe : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/killroom : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=1} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=@UNSET} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=2} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=4} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=5} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=6} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=8} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=9} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/side {dir=10} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/vault/corner : /obj/effect/turf_decal/tile/neutral {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/corner : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/side {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitegreen/corner : /obj/effect/turf_decal/tile/green {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/corner : /obj/effect/turf_decal/tile/purple {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whitered/corner : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/whiteyellow/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} -/turf/open/floor/plasteel/yellow/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP} \ No newline at end of file diff --git a/tools/mapmerge2/mapmerge.bat b/tools/mapmerge2/mapmerge.bat deleted file mode 100644 index 5a066226b3c..00000000000 --- a/tools/mapmerge2/mapmerge.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -set MAPROOT=../../_maps/ -set TGM=1 -python mapmerge.py -pause diff --git a/tools/mapmerge2/mapmerge.py b/tools/mapmerge2/mapmerge.py index f449bd948f0..d9cdea24cfb 100755 --- a/tools/mapmerge2/mapmerge.py +++ b/tools/mapmerge2/mapmerge.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 -import frontend import shutil -from dmm import * from collections import defaultdict +from . import frontend +from .dmm import * def merge_map(new_map, old_map, delete_unused=False): if new_map.key_length != old_map.key_length: @@ -66,7 +66,7 @@ def select_key(assigned): # step two: delete unused keys if unused_keys: - print(f"Notice: Trimming {len(unused_keys)} unused dictionary keys.") + #print(f"Notice: Trimming {len(unused_keys)} unused dictionary keys.") for key in unused_keys: del merged.dictionary[key] diff --git a/tools/mapmerge2/merge_driver.py b/tools/mapmerge2/merge_driver.py index 39bc1f723e3..8daead9c165 100755 --- a/tools/mapmerge2/merge_driver.py +++ b/tools/mapmerge2/merge_driver.py @@ -75,9 +75,13 @@ def three_way_merge(base, left, right): print(f" C: Both sides touch the tile at {coord}") if merged_movables is None: - obj_name = "---Merge conflict marker---" - merged_movables = left_movables + [f'/obj{{name = "{obj_name}"}}'] + right_movables - print(f" Left and right movable groups are split by an `/obj` named \"{obj_name}\"") + # Note that if you do not have an object that matches this path in your DME, the invalid path may be discarded when the map is loaded into a map editor. + # To rectify this, either add an object with this same path, or create a new object/denote an existing object in the obj_path define. + obj_path = "/obj/merge_conflict_marker" + obj_name = "---Merge Conflict Marker---" + obj_desc = "A best-effort merge was performed. You must resolve this conflict yourself (manually) and remove this object once complete." + merged_movables = left_movables + [f'{obj_path}{{name = "{obj_name}";\n\tdesc = "{obj_desc}"}}'] + right_movables + print(f" Left and right movable groups are split by an `{obj_path}` named \"{obj_name}\"") if merged_turfs is None: merged_turfs = left_turfs print(f" Saving turf: {', '.join(left_turfs)}") diff --git a/tools/mapmerge2/merge_driver_dmi.py b/tools/mapmerge2/merge_driver_dmi.py deleted file mode 100755 index 37c0abd9543..00000000000 --- a/tools/mapmerge2/merge_driver_dmi.py +++ /dev/null @@ -1,177 +0,0 @@ -#!/usr/bin/env python3 -import sys -import dmi - -def images_equal(left, right): - if left.size != right.size: - return False - w, h = left.size - left_load, right_load = left.load(), right.load() - for y in range(0, h): - for x in range(0, w): - lpixel, rpixel = left_load[x, y], right_load[x, y] - # quietly ignore changes where both pixels are fully transparent - if lpixel != rpixel and (lpixel[3] != 0 or rpixel[3] != 0): - return False - return True - -def states_equal(left, right): - result = True - - # basic properties - for attr in ('loop', 'rewind', 'movement', 'dirs', 'delays', 'hotspots', 'framecount'): - lval, rval = getattr(left, attr), getattr(right, attr) - if lval != rval: - result = False - - # frames - for (left_frame, right_frame) in zip(left.frames, right.frames): - if not images_equal(left_frame, right_frame): - result = False - - return result - -def key_of(state): - return (state.name, state.movement) - -def dictify(sheet): - result = {} - for state in sheet.states: - k = key_of(state) - if k in result: - print(f" duplicate {k!r}") - result[k] = state - return result - -def three_way_merge(base, left, right): - base_dims = base.width, base.height - if base_dims != (left.width, left.height) or base_dims != (right.width, right.height): - print("Dimensions have changed:") - print(f" Base: {base.width} x {base.height}") - print(f" Ours: {left.width} x {left.height}") - print(f" Theirs: {right.width} x {right.height}") - return True, None - - base_states, left_states, right_states = dictify(base), dictify(left), dictify(right) - - new_left = {k: v for k, v in left_states.items() if k not in base_states} - new_right = {k: v for k, v in right_states.items() if k not in base_states} - new_both = {} - conflicts = [] - for key, state in list(new_left.items()): - in_right = new_right.get(key, None) - if in_right: - if states_equal(state, in_right): - # allow it - new_both[key] = state - else: - # generate conflict states - print(f" C: {state.name!r}: added differently in both!") - state.name = f"{state.name} !CONFLICT! left" - conflicts.append(state) - in_right.name = f"{state.name} !CONFLICT! right" - conflicts.append(in_right) - # don't add it a second time - del new_left[key] - del new_right[key] - - final_states = [] - # add states that are currently in the base - for state in base.states: - in_left = left_states.get(key_of(state), None) - in_right = right_states.get(key_of(state), None) - left_equals = in_left and states_equal(state, in_left) - right_equals = in_right and states_equal(state, in_right) - - if not in_left and not in_right: - # deleted in both left and right, it's just deleted - print(f" {state.name!r}: deleted in both") - elif not in_left: - # left deletes - print(f" {state.name!r}: deleted in left") - if not right_equals: - print(f" ... but modified in right") - final_states.append(in_right) - elif not in_right: - # right deletes - print(f" {state.name!r}: deleted in right") - if not left_equals: - print(f" ... but modified in left") - final_states.append(in_left) - elif left_equals and right_equals: - # changed in neither - #print(f"Same in both: {state.name!r}") - final_states.append(state) - elif left_equals: - # changed only in right - print(f" {state.name!r}: changed in left") - final_states.append(in_right) - elif right_equals: - # changed only in left - print(f" {state.name!r}: changed in right") - final_states.append(in_left) - elif states_equal(in_left, in_right): - # changed in both, to the same thing - print(f" {state.name!r}: changed same in both") - final_states.append(in_left) # either or - else: - # changed in both - name = state.name - print(f" C: {name!r}: changed differently in both!") - state.name = f"{name} !CONFLICT! base" - conflicts.append(state) - in_left.name = f"{name} !CONFLICT! left" - conflicts.append(in_left) - in_right.name = f"{name} !CONFLICT! right" - conflicts.append(in_right) - - # add states which both left and right added the same - for key, state in new_both.items(): - print(f" {state.name!r}: added same in both") - final_states.append(state) - - # add states that are brand-new in the left - for key, state in new_left.items(): - print(f" {state.name!r}: added in left") - final_states.append(state) - - # add states that are brand-new in the right - for key, state in new_right.items(): - print(f" {state.name!r}: added in right") - final_states.append(state) - - final_states.extend(conflicts) - merged = dmi.Dmi(base.width, base.height) - merged.states = final_states - return len(conflicts), merged - -def main(path, original, left, right): - print(f"Merging icon: {path}") - - icon_orig = dmi.Dmi.from_file(original) - icon_left = dmi.Dmi.from_file(left) - icon_right = dmi.Dmi.from_file(right) - - trouble, merged = three_way_merge(icon_orig, icon_left, icon_right) - if merged: - merged.to_file(left) - if trouble: - print("!!! Manual merge required!") - if merged: - print(" A best-effort merge was performed. You must edit the icon and remove all") - print(" icon states marked with !CONFLICT!, leaving only the desired icon.") - else: - print(" The icon was totally unable to be merged, you must start with one version") - print(" or the other and manually resolve the conflict.") - print(" Information about which states conflicted is listed above.") - return trouble - -if __name__ == '__main__': - if len(sys.argv) != 6: - print("DMI merge driver called with wrong number of arguments") - print(" usage: merge-driver-dmi %P %O %A %B %L") - exit(1) - - # "left" is also the file that ought to be overwritten - _, path, original, left, right, conflict_size_marker = sys.argv - exit(main(path, original, left, right)) diff --git a/tools/mapmerge2/precommit.py b/tools/mapmerge2/precommit.py index f5ea49a50ea..54f252a3dcf 100755 --- a/tools/mapmerge2/precommit.py +++ b/tools/mapmerge2/precommit.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 -import os -import pygit2 -import dmm -from mapmerge import merge_map +import os, sys, pygit2 +from . import dmm +from .mapmerge import merge_map -def main(repo): + +def main(repo, *, use_workdir=False): if repo.index.conflicts: print("You need to resolve merge conflicts first.") return 1 @@ -16,12 +16,21 @@ def main(repo): except KeyError: pass + target_statuses = pygit2.GIT_STATUS_INDEX_MODIFIED | pygit2.GIT_STATUS_INDEX_NEW + skip_to_file_statuses = pygit2.GIT_STATUS_WT_DELETED | pygit2.GIT_STATUS_WT_MODIFIED + if use_workdir: + target_statuses |= pygit2.GIT_STATUS_WT_MODIFIED | pygit2.GIT_STATUS_WT_NEW + skip_to_file_statuses &= ~pygit2.GIT_STATUS_WT_MODIFIED + changed = 0 for path, status in repo.status().items(): - if path.endswith(".dmm") and (status & (pygit2.GIT_STATUS_INDEX_MODIFIED | pygit2.GIT_STATUS_INDEX_NEW)): + if path.endswith(".dmm") and (status & target_statuses): # read the index index_entry = repo.index[path] - index_map = dmm.DMM.from_bytes(repo[index_entry.id].read_raw()) + if use_workdir: + index_map = dmm.DMM.from_file(os.path.join(repo.workdir, path)) + else: + index_map = dmm.DMM.from_bytes(repo[index_entry.id].read_raw()) try: head_blob = repo[repo[repo.head.target].tree[path].id] @@ -32,7 +41,7 @@ def main(repo): merged_map = index_map else: # Entry in HEAD, merge the index over it - print(f"Merging map: {path}", flush=True) + print(f"Converting map: {path}", flush=True) assert not (status & pygit2.GIT_STATUS_INDEX_NEW) head_map = dmm.DMM.from_bytes(head_blob.read_raw()) merged_map = merge_map(index_map, head_map) @@ -43,15 +52,16 @@ def main(repo): changed += 1 # write to the working directory if that's clean - if status & (pygit2.GIT_STATUS_WT_DELETED | pygit2.GIT_STATUS_WT_MODIFIED): + if status & skip_to_file_statuses: print(f"Warning: {path} has unindexed changes, not overwriting them") else: merged_map.to_file(os.path.join(repo.workdir, path)) if changed: repo.index.write() - print(f"Merged {changed} maps.") return 0 + if __name__ == '__main__': - exit(main(pygit2.Repository(pygit2.discover_repository(os.getcwd())))) + repo = pygit2.Repository(pygit2.discover_repository(os.getcwd())) + exit(main(repo, use_workdir='--use-workdir' in sys.argv)) diff --git a/tools/mapmerge2/requirements-install.bat b/tools/mapmerge2/requirements-install.bat deleted file mode 100644 index 71341af8792..00000000000 --- a/tools/mapmerge2/requirements-install.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -python -m pip install -r requirements.txt -pause diff --git a/tools/mapmerge2/requirements.txt b/tools/mapmerge2/requirements.txt deleted file mode 100644 index 65d1a5e0b17..00000000000 --- a/tools/mapmerge2/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -pygit2==1.0.1 -bidict==0.13.1 -Pillow==7.1.1 diff --git a/tools/mapmerge2/tgm2dmm.bat b/tools/mapmerge2/tgm2dmm.bat deleted file mode 100644 index 2748533febf..00000000000 --- a/tools/mapmerge2/tgm2dmm.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -set MAPROOT=../../_maps/ -set TGM=0 -python convert.py -pause diff --git a/tools/oldChangelog/README.MD b/tools/oldChangelog/README.MD deleted file mode 100644 index 2786ec3138d..00000000000 --- a/tools/oldChangelog/README.MD +++ /dev/null @@ -1,3 +0,0 @@ -# Old Changelog System - -This directory contains all the data for the old changelog system \ No newline at end of file diff --git a/tools/oldChangelog/github_webhook_processor.php b/tools/oldChangelog/github_webhook_processor.php deleted file mode 100644 index c27a7eb4c5b..00000000000 --- a/tools/oldChangelog/github_webhook_processor.php +++ /dev/null @@ -1,355 +0,0 @@ -getLine()}: " . htmlSpecialChars($e->getMessage()); - die(); -}); -$rawPost = NULL; -if (!$hookSecret || $hookSecret == '08ajh0qj93209qj90jfq932j32r') - throw new \Exception("Hook secret is required and can not be default"); -if (!isset($_SERVER['HTTP_X_HUB_SIGNATURE'])) { - throw new \Exception("HTTP header 'X-Hub-Signature' is missing."); -} elseif (!extension_loaded('hash')) { - throw new \Exception("Missing 'hash' extension to check the secret code validity."); -} -list($algo, $hash) = explode('=', $_SERVER['HTTP_X_HUB_SIGNATURE'], 2) + array('', ''); -if (!in_array($algo, hash_algos(), TRUE)) { - throw new \Exception("Hash algorithm '$algo' is not supported."); -} -$rawPost = file_get_contents('php://input'); -if ($hash !== hash_hmac($algo, $rawPost, $hookSecret)) { - throw new \Exception('Hook secret does not match.'); -} - -$contenttype = null; -//apache and nginx/fastcgi/phpfpm call this two different things. -if (!isset($_SERVER['HTTP_CONTENT_TYPE'])) { - if (!isset($_SERVER['CONTENT_TYPE'])) - throw new \Exception("Missing HTTP 'Content-Type' header."); - else - $contenttype = $_SERVER['CONTENT_TYPE']; -} else { - $contenttype = $_SERVER['HTTP_CONTENT_TYPE']; -} -if (!isset($_SERVER['HTTP_X_GITHUB_EVENT'])) { - throw new \Exception("Missing HTTP 'X-Github-Event' header."); -} -switch ($contenttype) { - case 'application/json': - $json = $rawPost ?: file_get_contents('php://input'); - break; - case 'application/x-www-form-urlencoded': - $json = $_POST['payload']; - break; - default: - throw new \Exception("Unsupported content type: $contenttype"); -} -# Payload structure depends on triggered event -# https://developer.github.com/v3/activity/events/types/ -$payload = json_decode($json, true); - -switch (strtolower($_SERVER['HTTP_X_GITHUB_EVENT'])) { - case 'ping': - echo 'pong'; - break; - case 'pull_request': - handle_pr($payload); - break; - default: - header('HTTP/1.0 404 Not Found'); - echo "Event:$_SERVER[HTTP_X_GITHUB_EVENT] Payload:\n"; - print_r($payload); # For debug only. Can be found in GitHub hook log. - die(); -} -function handle_pr($payload) { - $action = 'opened'; - switch ($payload["action"]) { - case 'opened': - case 'reopened': - $action = $payload['action']; - break; - case 'closed': - if (!$payload['pull_request']['merged']) { - $action = 'closed'; - } - else { - $action = 'merged'; - checkchangelog($payload, true); - } - break; - default: - return; - } - - if (strtolower(substr($payload['pull_request']['title'], 0, 3)) == '[s]') { - echo "PR Announcement Halted; Secret tag detected.\n"; - return; - } - - $msg = 'Pull Request '.$action.' by '.htmlSpecialChars($payload['sender']['login']).': '.htmlSpecialChars('#'.$payload['pull_request']['number'].' '.$payload['pull_request']['user']['login'].' - '.$payload['pull_request']['title']).''; - sendtoallservers('?announce='.urlencode($msg)); - -} - -function checkchangelog($payload, $merge = false) { - global $apiKey; - if (!$merge) - return; - if (!isset($payload['pull_request']) || !isset($payload['pull_request']['body'])) { - return; - } - if (!isset($payload['pull_request']['user']) || !isset($payload['pull_request']['user']['login'])) { - return; - } - $body = $payload['pull_request']['body']; - $body = str_replace("\r\n", "\n", $body); - $body = explode("\n", $body); - $username = $payload['pull_request']['user']['login']; - $incltag = false; - $changelogbody = array(); - $currentchangelogblock = array(); - $foundcltag = false; - foreach ($body as $line) { - $line = trim($line); - if (substr($line,0,4) == ':cl:' || substr($line,0,4) == '🆑') { - $incltag = true; - $foundcltag = true; - $pos = strpos($line, " "); - if ($pos) - $username = substr($line, $pos+1); - continue; - } else if (substr($line,0,5) == '/:cl:' || substr($line,0,6) == '/ :cl:' || substr($line,0,5) == ':/cl:' || substr($line,0,5) == '/🆑' || substr($line,0,6) == '/ 🆑' ) { - $incltag = false; - $changelogbody = array_merge($changelogbody, $currentchangelogblock); - continue; - } - if (!$incltag) - continue; - - $firstword = explode(' ', $line)[0]; - $pos = strpos($line, " "); - $item = ''; - if ($pos) { - $firstword = trim(substr($line, 0, $pos)); - $item = trim(substr($line, $pos+1)); - } else { - $firstword = $line; - } - - if (!strlen($firstword)) { - $currentchangelogblock[count($currentchangelogblock)-1]['body'] .= "\n"; - continue; - } - //not a prefix line. - //so we add it to the last changelog entry as a separate line - if (!strlen($firstword) || $firstword[strlen($firstword)-1] != ':') { - if (count($currentchangelogblock) <= 0) - continue; - $currentchangelogblock[count($currentchangelogblock)-1]['body'] .= "\n".$line; - continue; - } - $cltype = strtolower(substr($firstword, 0, -1)); - switch ($cltype) { - case 'fix': - case 'fixes': - case 'bugfix': - $currentchangelogblock[] = array('type' => 'bugfix', 'body' => $item); - break; - case 'wip': - $currentchangelogblock[] = array('type' => 'wip', 'body' => $item); - break; - case 'rsctweak': - case 'tweaks': - case 'tweak': - $currentchangelogblock[] = array('type' => 'tweak', 'body' => $item); - break; - case 'soundadd': - $currentchangelogblock[] = array('type' => 'soundadd', 'body' => $item); - break; - case 'sounddel': - $currentchangelogblock[] = array('type' => 'sounddel', 'body' => $item); - break; - case 'add': - case 'adds': - case 'rscadd': - $currentchangelogblock[] = array('type' => 'rscadd', 'body' => $item); - break; - case 'del': - case 'dels': - case 'rscdel': - $currentchangelogblock[] = array('type' => 'rscdel', 'body' => $item); - break; - case 'imageadd': - $currentchangelogblock[] = array('type' => 'imageadd', 'body' => $item); - break; - case 'imagedel': - $currentchangelogblock[] = array('type' => 'imagedel', 'body' => $item); - break; - case 'typo': - case 'spellcheck': - $currentchangelogblock[] = array('type' => 'spellcheck', 'body' => $item); - break; - case 'experimental': - case 'experiment': - $currentchangelogblock[] = array('type' => 'experiment', 'body' => $item); - break; - case 'tgs': - $currentchangelogblock[] = array('type' => 'tgs', 'body' => $item); - break; - default: - //we add it to the last changelog entry as a separate line - if (count($currentchangelogblock) > 0) - $currentchangelogblock[count($currentchangelogblock)-1]['body'] .= "\n".$line; - break; - } - } - - if (!count($changelogbody)) - return; - - $file = 'author: "'.trim(str_replace(array("\\", '"'), array("\\\\", "\\\""), $username)).'"'."\n"; - $file .= "delete-after: True\n"; - $file .= "changes: \n"; - foreach ($changelogbody as $changelogitem) { - $type = $changelogitem['type']; - $body = trim(str_replace(array("\\", '"'), array("\\\\", "\\\""), $changelogitem['body'])); - $file .= ' - '.$type.': "'.$body.'"'; - $file .= "\n"; - } - $content = array ( - 'branch' => $payload['pull_request']['base']['ref'], - 'message' => 'Automatic changelog generation for PR #'.$payload['pull_request']['number'].' [ci skip]', - 'content' => base64_encode($file) - ); - $scontext = array('http' => array( - 'method' => 'PUT', - 'header' => - "Content-type: application/json\r\n". - 'Authorization: token ' . $apiKey, - 'content' => json_encode($content), - 'ignore_errors' => true, - 'user_agent' => 'tgstation13.org-Github-Automation-Tools' - )); - $filename = '/html/changelogs/AutoChangeLog-pr-'.$payload['pull_request']['number'].'.yml'; - echo file_get_contents($payload['pull_request']['base']['repo']['url'].'/contents'.$filename, false, stream_context_create($scontext)); -} - -function sendtoallservers($str) { - global $servers; - foreach ($servers as $serverid => $server) { - if (isset($server['comskey'])) - $rtn = export($server['address'], $server['port'], $str.'&key='.$server['comskey']); - else - $rtn = export($server['address'], $server['port'], $str); - - echo "Server Number $serverid replied: $rtn\n"; - } -} - - - -function export($addr, $port, $str) { - global $error; - // All queries must begin with a question mark (ie "?players") - if($str{0} != '?') $str = ('?' . $str); - - /* --- Prepare a packet to send to the server (based on a reverse-engineered packet structure) --- */ - $query = "\x00\x83" . pack('n', strlen($str) + 6) . "\x00\x00\x00\x00\x00" . $str . "\x00"; - - /* --- Create a socket and connect it to the server --- */ - $server = socket_create(AF_INET,SOCK_STREAM,SOL_TCP) or exit("ERROR"); - socket_set_option($server, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 2, 'usec' => 0)); //sets connect and send timeout to 2 seconds - if(!socket_connect($server,$addr,$port)) { - $error = true; - return "ERROR"; - } - - - /* --- Send bytes to the server. Loop until all bytes have been sent --- */ - $bytestosend = strlen($query); - $bytessent = 0; - while ($bytessent < $bytestosend) { - //echo $bytessent.'
'; - $result = socket_write($server,substr($query,$bytessent),$bytestosend-$bytessent); - //echo 'Sent '.$result.' bytes
'; - if ($result===FALSE) die(socket_strerror(socket_last_error())); - $bytessent += $result; - } - - /* --- Idle for a while until recieved bytes from game server --- */ - $result = socket_read($server, 10000, PHP_BINARY_READ); - socket_close($server); // we don't need this anymore - - if($result != "") { - if($result{0} == "\x00" || $result{1} == "\x83") { // make sure it's the right packet format - - // Actually begin reading the output: - $sizebytes = unpack('n', $result{2} . $result{3}); // array size of the type identifier and content - $size = $sizebytes[1] - 1; // size of the string/floating-point (minus the size of the identifier byte) - - if($result{4} == "\x2a") { // 4-byte big-endian floating-point - $unpackint = unpack('f', $result{5} . $result{6} . $result{7} . $result{8}); // 4 possible bytes: add them up together, unpack them as a floating-point - return $unpackint[1]; - } - else if($result{4} == "\x06") { // ASCII string - $unpackstr = ""; // result string - $index = 5; // string index - - while($size > 0) { // loop through the entire ASCII string - $size--; - $unpackstr .= $result{$index}; // add the string position to return string - $index++; - } - return $unpackstr; - } - } - } - //if we get to this point, something went wrong; - $error = true; - return "ERROR"; -} -?> \ No newline at end of file diff --git a/tools/oldChangelog/makeChangelog.bat b/tools/oldChangelog/makeChangelog.bat deleted file mode 100644 index 7a16ff6b870..00000000000 --- a/tools/oldChangelog/makeChangelog.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -rem Cheridan asked for this. - N3X -rem This has been updated to use the old changelog directories as of PR #13051 -AA -call python ss13_genchangelog.py ../../html/archived_changelog/changelog.html ../../html/archived_changelog/changelogs -pause diff --git a/tools/oldChangelog/ss13_genchangelog.py b/tools/oldChangelog/ss13_genchangelog.py deleted file mode 100644 index 18634d34832..00000000000 --- a/tools/oldChangelog/ss13_genchangelog.py +++ /dev/null @@ -1,217 +0,0 @@ -''' -ss13_genchangelog.py - Generate changelog from YAML. - -Usage: - $ python ss13_genchangelog.py [--dry-run] html/changelog.html html/changelogs/ - - Example (first use): - - Install python 2.7 - - run cmd.exe - - pip install pyyaml - - cd paradise github directory - - python tools/ss13_genchangelog.py html/changelog.html html/changelogs/ - -Copyright 2013 Rob "N3X15" Nelson - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -''' - -from __future__ import print_function -import yaml, os, glob, sys, re, time, argparse -from datetime import datetime, date -from time import time - -today = date.today() - -dateformat = "%d %B %Y" - -opt = argparse.ArgumentParser() -opt.add_argument('-d', '--dry-run', dest='dryRun', default=False, action='store_true', help='Only parse changelogs and, if needed, the targetFile. (A .dry_changelog.yml will be output for debugging purposes.)') -opt.add_argument('targetFile', help='The HTML changelog we wish to update.') -opt.add_argument('ymlDir', help='The directory of YAML changelogs we will use.') - -args = opt.parse_args() - -all_changelog_entries = {} - -validPrefixes = [ - 'bugfix', - 'wip', - 'tweak', - 'soundadd', - 'sounddel', - 'rscdel', - 'rscadd', - 'imageadd', - 'imagedel', - 'spellcheck', - 'experiment', - 'tgs' -] - -def dictToTuples(inp): - return [(k, v) for k, v in inp.items()] - -changelog_cache = os.path.join(args.ymlDir, '.all_changelog.yml') - -failed_cache_read = True -if os.path.isfile(changelog_cache): - try: - with open(changelog_cache) as f: - (_, all_changelog_entries) = yaml.load_all(f) - failed_cache_read = False - - # Convert old timestamps to newer format. - new_entries = {} - for _date in all_changelog_entries.keys(): - ty = type(_date).__name__ - # print(ty) - if ty in ['str', 'unicode']: - temp_data = all_changelog_entries[_date] - _date = datetime.strptime(_date, dateformat).date() - new_entries[_date] = temp_data - else: - new_entries[_date] = all_changelog_entries[_date] - all_changelog_entries = new_entries - except Exception as e: - print("Failed to read cache:") - print(e, file=sys.stderr) - -if args.dryRun: - changelog_cache = os.path.join(args.ymlDir, '.dry_changelog.yml') - -if failed_cache_read and os.path.isfile(args.targetFile): - from bs4 import BeautifulSoup - from bs4.element import NavigableString - print(' Generating cache...') - with open(args.targetFile, 'r') as f: - soup = BeautifulSoup(f) - for e in soup.find_all('div', {'class':'commit'}): - entry = {} - date = datetime.strptime(e.h2.string.strip(), dateformat).date() # key - for authorT in e.find_all('h3', {'class':'author'}): - author = authorT.string - # Strip suffix - if author.endswith('updated:'): - author = author[:-8] - author = author.strip() - - # Find