feat(stdlib): Tiled P0 — XML reader + base64 decode + gzip framing (#67)
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 20s
ci / build-and-test (push) Successful in 1m43s
commit-lint / conventional-commits (push) Successful in 2s
docs / build-and-deploy (push) Successful in 27s

The three parsing primitives the TMX path needs that were not already in
the tree (zlib inflate + the JSON reader already shipped):

- Xml.* — a minimal, deterministic pure-Ludic XML reader for the
  element/attribute/CDATA subset TMX/TSX/TX use, spliced on demand. Handles
  nested elements, single/double-quoted attributes, text + <![CDATA[…]]>,
  comments, the <?xml?> prolog and <!DOCTYPE>, the five predefined entities
  and numeric character references.
- Base64.* — standard base64 (RFC 4648) decode + a matching pure-Ludic
  encoder; the decoder ignores the whitespace Tiled wraps into <data>.
  Splicing Base64.* also pulls in inflate.ludic so a plain tool can run the
  full base64 -> zlib/gzip decode chain.
- z_gunzip — gzip framing (RFC 1952) over the existing DEFLATE inflater:
  skip the 10-byte header + optional fields, inflate the body, ignore the
  CRC32/ISIZE trailer.

Golden corpus vendored under assets/tiled-fixtures/ (mapeditor/tiled
examples, attributed, + hand-authored multi-encoding fixtures). New
example library/tiled_p0.ludic proves all three (21 assertions); docs
pages + inventory added so check-impl stays green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-01 14:04:49 +03:00
parent 0b149a6876
commit 79776d1f6a
35 changed files with 20549 additions and 18415 deletions

View file

@ -0,0 +1,29 @@
# Tiled golden fixtures
The curated, version-pinned corpus for the Ludic Tiled reader (design record:
[Design: Tiled maps](https://git.workshopsoft.io/workshopsoft/ludic/wiki/Design%2FTiled),
issues #67–#74). No single Tiled file covers the format surface, so this is a
subset of the official [`mapeditor/tiled`](https://github.com/mapeditor/tiled)
`examples/` tree plus a few hand-authored files for the gaps the official
examples miss.
## Vendored from mapeditor/tiled (`examples/`)
Fetched from `https://raw.githubusercontent.com/mapeditor/tiled/master/examples/`.
Tiled's example assets carry their own licenses (see the upstream repo's
per-folder `*.license`/README); vendored here with attribution for testing only.
| File | Exercises |
|---|---|
| `desert.tmx` + `desert.tsx` | orthogonal, external `.tsx`, base64+zlib (P0/P1) |
| `sewers.tmx` | orthogonal, base64+zlib, embedded tileset, opacity (P0) |
| `orthogonal-outside.tmx` | object layers, shapes, custom properties (P4) |
| `perspective_walls.tsx` | per-tile bool properties, `<tileoffset>` (P4) |
| `isometric_grass_and_water.tmx` | isometric orientation, Wang set (P5) |
| `hexagonal-mini.tmx` | hexagonal orientation (P5) |
## Hand-authored (CC0 / public domain)
| File | Exercises |
|---|---|
| `handmade.tmx` + `handmade.tsx` | a 4×4 orthogonal map whose four layers carry the **same** GID array in CSV, base64-uncompressed, base64+gzip and base64+zlib — so every encoding path must decode identically. The last tile is GID 1 with the horizontal-flip flag (`0x80000001`), forcing real GID decode. `handmade.tsx` also carries a `solid` bool property and a per-tile `<objectgroup>` collision shape for P2. |

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.0" tiledversion="1.1.5" orientation="orthogonal" renderorder="right-down" width="40" height="40" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
<tileset firstgid="1" source="desert.tsx"/>
<layer id="1" name="Ground" width="40" height="40">
<data encoding="base64" compression="zlib">
eJztmNkKwjAQRaN9cAPrAq5Yq3Xf6v9/nSM2VIbQJjEZR+nDwQZScrwztoORECLySBcIgZ7nc2y4KfyWDLx+Jb9nViNgDEwY+KioAXUgQN4+zpoCMwPmQAtoAx2CLFbA2oDEo9+hwG8DnIDtF/2K8ks086Tw2zH0uyMv7HcRr/6/EvvhnsPrsrxwX7rwU/0ODig/eV3mh3N1ld8eraWPaX6+64s9McesfrqcHfg1MpoifxcVEWjukyw+9AtFPl/I71pER3Of6j4bv7HI54s+MChhqLlPdZ/P3qMmFuo5h5NnTOhjM5tReN2yT51n5/v7J3F0vi46fk+ne7aX0i9l6If7mpufTX3f5wsqv9TAD2fJLT9VrTn7UeZnM5tR+v0LMQOHXwFnxe2/warGFRWf8QDjOLfP
</data>
</layer>
</map>

View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.4" tiledversion="1.4.3" name="Desert" tilewidth="32" tileheight="32" spacing="1" margin="1" tilecount="48" columns="8">
<image source="tmw_desert_spacing.png" width="265" height="199"/>
<tile id="30" probability="0.01"/>
<tile id="31" probability="0.01"/>
<tile id="37" probability="0.01"/>
<tile id="38" probability="0.01"/>
<tile id="39" probability="0.01"/>
<tile id="45" probability="0"/>
<tile id="46" probability="0.01"/>
<tile id="47" probability="0.01"/>
<wangsets>
<wangset name="Desert" type="corner" tile="5">
<wangcolor name="Desert" color="#ff0000" tile="29" probability="1"/>
<wangcolor name="Brick" color="#00ff00" tile="9" probability="1"/>
<wangcolor name="Cobblestone" color="#0000ff" tile="33" probability="1"/>
<wangcolor name="Dirt" color="#ff7700" tile="14" probability="1"/>
<wangtile tileid="0" wangid="0,1,0,2,0,1,0,1"/>
<wangtile tileid="1" wangid="0,1,0,2,0,2,0,1"/>
<wangtile tileid="2" wangid="0,1,0,1,0,2,0,1"/>
<wangtile tileid="3" wangid="0,4,0,1,0,4,0,4"/>
<wangtile tileid="4" wangid="0,4,0,4,0,1,0,4"/>
<wangtile tileid="5" wangid="0,1,0,4,0,1,0,1"/>
<wangtile tileid="6" wangid="0,1,0,4,0,4,0,1"/>
<wangtile tileid="7" wangid="0,1,0,1,0,4,0,1"/>
<wangtile tileid="8" wangid="0,2,0,2,0,1,0,1"/>
<wangtile tileid="9" wangid="0,2,0,2,0,2,0,2"/>
<wangtile tileid="10" wangid="0,1,0,1,0,2,0,2"/>
<wangtile tileid="11" wangid="0,1,0,4,0,4,0,4"/>
<wangtile tileid="12" wangid="0,4,0,4,0,4,0,1"/>
<wangtile tileid="13" wangid="0,4,0,4,0,1,0,1"/>
<wangtile tileid="14" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="15" wangid="0,1,0,1,0,4,0,4"/>
<wangtile tileid="16" wangid="0,2,0,1,0,1,0,1"/>
<wangtile tileid="17" wangid="0,2,0,1,0,1,0,2"/>
<wangtile tileid="18" wangid="0,1,0,1,0,1,0,2"/>
<wangtile tileid="19" wangid="0,2,0,1,0,2,0,2"/>
<wangtile tileid="20" wangid="0,2,0,2,0,1,0,2"/>
<wangtile tileid="21" wangid="0,4,0,1,0,1,0,1"/>
<wangtile tileid="22" wangid="0,4,0,1,0,1,0,4"/>
<wangtile tileid="23" wangid="0,1,0,1,0,1,0,4"/>
<wangtile tileid="24" wangid="0,1,0,3,0,1,0,1"/>
<wangtile tileid="25" wangid="0,1,0,3,0,3,0,1"/>
<wangtile tileid="26" wangid="0,1,0,1,0,3,0,1"/>
<wangtile tileid="27" wangid="0,1,0,2,0,2,0,2"/>
<wangtile tileid="28" wangid="0,2,0,2,0,2,0,1"/>
<wangtile tileid="29" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="30" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="31" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="32" wangid="0,3,0,3,0,1,0,1"/>
<wangtile tileid="33" wangid="0,3,0,3,0,3,0,3"/>
<wangtile tileid="34" wangid="0,1,0,1,0,3,0,3"/>
<wangtile tileid="35" wangid="0,3,0,1,0,3,0,3"/>
<wangtile tileid="36" wangid="0,3,0,3,0,1,0,3"/>
<wangtile tileid="37" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="38" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="39" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="40" wangid="0,3,0,1,0,1,0,1"/>
<wangtile tileid="41" wangid="0,3,0,1,0,1,0,3"/>
<wangtile tileid="42" wangid="0,1,0,1,0,1,0,3"/>
<wangtile tileid="43" wangid="0,1,0,3,0,3,0,3"/>
<wangtile tileid="44" wangid="0,3,0,3,0,3,0,1"/>
<wangtile tileid="45" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="46" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="47" wangid="0,1,0,1,0,1,0,1"/>
</wangset>
</wangsets>
</tileset>

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Hand-authored fixture for the Ludic Tiled reader (issue #67). Public domain (CC0). -->
<map version="1.10" tiledversion="1.10.2" orientation="orthogonal" renderorder="right-down" width="4" height="4" tilewidth="16" tileheight="16" infinite="0" nextlayerid="4" nextobjectid="1">
<tileset firstgid="1" source="handmade.tsx"/>
<layer id="1" name="csv" width="4" height="4">
<data encoding="csv">
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,2147483649
</data>
</layer>
<layer id="2" name="base64" width="4" height="4">
<data encoding="base64">
AQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAAQAAgA==
</data>
</layer>
<layer id="3" name="gzip" width="4" height="4">
<data encoding="base64" compression="gzip">
H4sIAAAAAAAC/w3Dhw0AIAwEsQ+9hpUZPWfJJikxs7CysXNwcnHz8NL5aNIPlvf4ekAAAAA=
</data>
</layer>
<layer id="4" name="zlib" width="4" height="4">
<data encoding="base64" compression="zlib">
eJwNw4cNACAMBLEPvYaVGT1nySYpMbOwsrFzcHJx8/DS+WjSDw1EAPo=
</data>
</layer>
</map>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Hand-authored fixture for the Ludic Tiled reader (issue #67). Public domain (CC0). -->
<tileset version="1.10" tiledversion="1.10.2" name="handmade" tilewidth="16" tileheight="16" spacing="0" margin="0" tilecount="16" columns="4">
<image source="handmade.png" width="64" height="64"/>
<tile id="4">
<properties>
<property name="solid" type="bool" value="true"/>
</properties>
</tile>
<tile id="6">
<objectgroup draworder="index">
<object id="1" x="0" y="8" width="16" height="8"/>
</objectgroup>
</tile>
</tileset>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.0" orientation="hexagonal" renderorder="right-down" width="20" height="20" tilewidth="14" tileheight="12" hexsidelength="6" staggeraxis="y" staggerindex="odd" nextobjectid="2">
<tileset firstgid="1" name="hex mini" tilewidth="18" tileheight="18">
<tileoffset x="0" y="1"/>
<image source="hexmini.png" width="106" height="72"/>
</tileset>
<layer name="Ground" width="20" height="20">
<data encoding="base64" compression="zlib">
eJyl1FEKhDAMBNBSt6jVaL3/Za2QwDAkVdiPQda2zyTonimlU1N6Ws+lkZ6l56AUXcPY2qlniv5uL5Z5BdyDvFXXMoX3Rp44axl6nqFejj3LLK6xgmf3Zg06Qs+O+qiaDOZOVgXPs7jfCme8Hkce1+fNlGdlM3myDTzc580fz1htW2Baj15/R/J72wLvcVZN5HnzGnmVPJ5hNH+0dt33j4ex91TARUs+WjNZz/fewKvJfy+/1naR+dX7OfdEnUYefyOeZZ7Vht/b5HjefxJbO1iTE7YWuEpg5hfPzi8D782x3Mg7DV4=
</data>
</layer>
</map>

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.4" tiledversion="1.4.3" orientation="isometric" renderorder="right-down" width="25" height="25" tilewidth="64" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
<tileset firstgid="1" name="isometric_grass_and_water" tilewidth="64" tileheight="64" tilecount="24" columns="4">
<tileoffset x="0" y="16"/>
<grid orientation="isometric" width="64" height="32"/>
<image source="isometric_grass_and_water.png" width="256" height="384"/>
<wangsets>
<wangset name="Grass and Water" type="corner" tile="15">
<wangcolor name="Grass" color="#8ab022" tile="0" probability="1"/>
<wangcolor name="Water" color="#378dc2" tile="23" probability="1"/>
<wangtile tileid="0" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="1" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="2" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="3" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="4" wangid="0,1,0,2,0,1,0,1"/>
<wangtile tileid="5" wangid="0,1,0,1,0,2,0,1"/>
<wangtile tileid="6" wangid="0,1,0,1,0,1,0,2"/>
<wangtile tileid="7" wangid="0,2,0,1,0,1,0,1"/>
<wangtile tileid="8" wangid="0,2,0,2,0,2,0,1"/>
<wangtile tileid="9" wangid="0,1,0,2,0,2,0,2"/>
<wangtile tileid="10" wangid="0,2,0,1,0,2,0,2"/>
<wangtile tileid="11" wangid="0,2,0,2,0,1,0,2"/>
<wangtile tileid="12" wangid="0,1,0,2,0,2,0,1"/>
<wangtile tileid="13" wangid="0,1,0,1,0,2,0,2"/>
<wangtile tileid="14" wangid="0,2,0,1,0,1,0,2"/>
<wangtile tileid="15" wangid="0,2,0,2,0,1,0,1"/>
<wangtile tileid="16" wangid="0,1,0,2,0,2,0,1"/>
<wangtile tileid="17" wangid="0,1,0,1,0,2,0,2"/>
<wangtile tileid="18" wangid="0,2,0,1,0,1,0,2"/>
<wangtile tileid="19" wangid="0,2,0,2,0,1,0,1"/>
<wangtile tileid="20" wangid="0,2,0,1,0,2,0,1"/>
<wangtile tileid="21" wangid="0,1,0,2,0,1,0,2"/>
<wangtile tileid="22" wangid="0,2,0,2,0,2,0,2"/>
<wangtile tileid="23" wangid="0,2,0,2,0,2,0,2"/>
</wangset>
</wangsets>
</tileset>
<layer id="1" name="Tile Layer 1" width="25" height="25">
<data encoding="base64" compression="zlib">
eJx1lttywjAMROVgyqVtAoFC/v9L68xoh5PFPGhIYktrrVYyS0QszZ7Nvpvd0n7y24L1Q7MhrTSreN/le821HZ7lv9qYa6sdE0cYs/kX7PXYwtfaevYp7WDrd+SnHByjYr/npP1zZ4/elcuM71rjeckdc5KNHX75fMwc9s2uzb6AsYstJzwrv5/Tz89SLIZy8v203llV8xl7yMU+462/v81OqA114/UhrzUxRqwprnh6ZGzp2PNQfPqRu/X9hnMV8F/xLg1L42erDf2oaa2RI2qPtbgbhmw2H69nMUxx/gVccXdC3AW/o/HV60vW59Lhu8arDxmfGIPFUV1qbLVQEIs4PlOeHQxqVjmzr5mLYsmf+5Qj5yM1r3Ne4p1D5VcMh3qWZibLx2fYkBhPYOv81I9wbrGd45zFU7zrndpwDjkHXXfej9zHc3EG+D3AWcCZMJif7hTnVxr6i9edtoBDz8N7kxqbY6sN9gJnsnqIOqCme7Un76579sIV8dccHvHqZefH76BP9wjzkVapM2rL+5/8cR6QS9eh8p2AT12y5oO9+7yh5hzLZypnHX29/pzB9PE7bOg8Mza5KvGu4R7mp/89zqvr7x+TnxEn
</data>
</layer>
</map>

View file

@ -0,0 +1,285 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.8" tiledversion="1.8.5" orientation="orthogonal" renderorder="right-down" width="45" height="31" tilewidth="16" tileheight="16" infinite="0" nextlayerid="4" nextobjectid="38">
<properties>
<property name="enemyTint" type="color" value="#ffa33636"/>
</properties>
<tileset firstgid="1" name="outdoor" tilewidth="16" tileheight="16" tilecount="288" columns="24">
<image source="buch-outdoor.png" width="384" height="192"/>
<tile id="6" probability="0.1"/>
<tile id="27" probability="0.05"/>
<tile id="28" probability="0.05"/>
<tile id="30" probability="0.1"/>
<tile id="51" probability="0.05"/>
<tile id="52" probability="0.05"/>
<tile id="54" probability="0.1"/>
<tile id="75" probability="0.05"/>
<tile id="76" probability="0.05"/>
<tile id="78" probability="0.1"/>
<tile id="82" probability="0.1"/>
<tile id="83" probability="0.1"/>
<tile id="99" probability="0.05"/>
<tile id="102" probability="0.1"/>
<tile id="106" probability="0.1"/>
<tile id="107" probability="0.1"/>
<tile id="126" probability="0.1"/>
<wangsets>
<wangset name="Terrains" type="corner" tile="25">
<wangcolor name="Grass" color="#fce94f" tile="150" probability="1"/>
<wangcolor name="Dirt" color="#ef2929" tile="100" probability="1"/>
<wangcolor name="Dark Dirt" color="#f57900" tile="34" probability="1"/>
<wangcolor name="Water" color="#729fcf" tile="171" probability="1"/>
<wangtile tileid="0" wangid="0,1,0,2,0,1,0,1"/>
<wangtile tileid="1" wangid="0,1,0,2,0,2,0,1"/>
<wangtile tileid="2" wangid="0,1,0,2,0,2,0,1"/>
<wangtile tileid="3" wangid="0,1,0,2,0,2,0,1"/>
<wangtile tileid="4" wangid="0,1,0,2,0,2,0,1"/>
<wangtile tileid="5" wangid="0,1,0,1,0,2,0,1"/>
<wangtile tileid="6" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="7" wangid="0,2,0,3,0,2,0,2"/>
<wangtile tileid="8" wangid="0,2,0,3,0,3,0,2"/>
<wangtile tileid="9" wangid="0,2,0,3,0,3,0,2"/>
<wangtile tileid="10" wangid="0,2,0,3,0,3,0,2"/>
<wangtile tileid="11" wangid="0,2,0,3,0,3,0,2"/>
<wangtile tileid="12" wangid="0,2,0,2,0,3,0,2"/>
<wangtile tileid="13" wangid="0,1,0,3,0,1,0,1"/>
<wangtile tileid="14" wangid="0,1,0,3,0,3,0,1"/>
<wangtile tileid="15" wangid="0,1,0,3,0,3,0,1"/>
<wangtile tileid="16" wangid="0,1,0,3,0,3,0,1"/>
<wangtile tileid="17" wangid="0,1,0,3,0,3,0,1"/>
<wangtile tileid="18" wangid="0,1,0,1,0,3,0,1"/>
<wangtile tileid="24" wangid="0,2,0,2,0,1,0,1"/>
<wangtile tileid="25" wangid="0,2,0,1,0,2,0,2"/>
<wangtile tileid="26" wangid="0,2,0,2,0,1,0,2"/>
<wangtile tileid="27" wangid="0,2,0,2,0,2,0,2"/>
<wangtile tileid="28" wangid="0,2,0,2,0,2,0,2"/>
<wangtile tileid="29" wangid="0,1,0,1,0,2,0,2"/>
<wangtile tileid="30" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="31" wangid="0,3,0,3,0,2,0,2"/>
<wangtile tileid="32" wangid="0,3,0,2,0,3,0,3"/>
<wangtile tileid="33" wangid="0,3,0,3,0,2,0,3"/>
<wangtile tileid="34" wangid="0,3,0,3,0,3,0,3"/>
<wangtile tileid="35" wangid="0,3,0,3,0,3,0,3"/>
<wangtile tileid="36" wangid="0,2,0,2,0,3,0,3"/>
<wangtile tileid="37" wangid="0,3,0,3,0,1,0,1"/>
<wangtile tileid="38" wangid="0,3,0,1,0,3,0,3"/>
<wangtile tileid="39" wangid="0,3,0,3,0,1,0,3"/>
<wangtile tileid="40" wangid="0,3,0,3,0,3,0,3"/>
<wangtile tileid="42" wangid="0,1,0,1,0,3,0,3"/>
<wangtile tileid="48" wangid="0,2,0,2,0,1,0,1"/>
<wangtile tileid="49" wangid="0,1,0,2,0,2,0,2"/>
<wangtile tileid="50" wangid="0,2,0,2,0,2,0,1"/>
<wangtile tileid="51" wangid="0,2,0,2,0,2,0,2"/>
<wangtile tileid="52" wangid="0,2,0,2,0,2,0,2"/>
<wangtile tileid="53" wangid="0,1,0,1,0,2,0,2"/>
<wangtile tileid="54" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="55" wangid="0,3,0,3,0,2,0,2"/>
<wangtile tileid="56" wangid="0,2,0,3,0,3,0,3"/>
<wangtile tileid="57" wangid="0,3,0,3,0,3,0,2"/>
<wangtile tileid="58" wangid="0,3,0,3,0,3,0,3"/>
<wangtile tileid="59" wangid="0,3,0,3,0,3,0,3"/>
<wangtile tileid="60" wangid="0,2,0,2,0,3,0,3"/>
<wangtile tileid="61" wangid="0,3,0,3,0,1,0,1"/>
<wangtile tileid="62" wangid="0,1,0,3,0,3,0,3"/>
<wangtile tileid="63" wangid="0,3,0,3,0,3,0,1"/>
<wangtile tileid="66" wangid="0,1,0,1,0,3,0,3"/>
<wangtile tileid="72" wangid="0,2,0,2,0,1,0,1"/>
<wangtile tileid="73" wangid="0,2,0,1,0,2,0,1"/>
<wangtile tileid="74" wangid="0,1,0,2,0,1,0,2"/>
<wangtile tileid="75" wangid="0,2,0,2,0,2,0,2"/>
<wangtile tileid="76" wangid="0,2,0,2,0,2,0,2"/>
<wangtile tileid="77" wangid="0,1,0,1,0,2,0,2"/>
<wangtile tileid="78" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="79" wangid="0,3,0,3,0,2,0,2"/>
<wangtile tileid="80" wangid="0,3,0,2,0,3,0,2"/>
<wangtile tileid="81" wangid="0,2,0,3,0,2,0,3"/>
<wangtile tileid="82" wangid="0,3,0,3,0,3,0,3"/>
<wangtile tileid="83" wangid="0,3,0,3,0,3,0,3"/>
<wangtile tileid="84" wangid="0,2,0,2,0,3,0,3"/>
<wangtile tileid="85" wangid="0,3,0,3,0,1,0,1"/>
<wangtile tileid="86" wangid="0,3,0,1,0,3,0,1"/>
<wangtile tileid="87" wangid="0,1,0,3,0,1,0,3"/>
<wangtile tileid="90" wangid="0,1,0,1,0,3,0,3"/>
<wangtile tileid="96" wangid="0,2,0,2,0,1,0,1"/>
<wangtile tileid="97" wangid="0,1,0,2,0,1,0,2"/>
<wangtile tileid="98" wangid="0,2,0,1,0,2,0,1"/>
<wangtile tileid="99" wangid="0,2,0,2,0,2,0,2"/>
<wangtile tileid="100" wangid="0,2,0,2,0,2,0,2"/>
<wangtile tileid="101" wangid="0,1,0,1,0,2,0,2"/>
<wangtile tileid="102" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="103" wangid="0,3,0,3,0,2,0,2"/>
<wangtile tileid="104" wangid="0,2,0,3,0,2,0,3"/>
<wangtile tileid="105" wangid="0,3,0,2,0,3,0,2"/>
<wangtile tileid="106" wangid="0,3,0,3,0,3,0,3"/>
<wangtile tileid="107" wangid="0,3,0,3,0,3,0,3"/>
<wangtile tileid="108" wangid="0,2,0,2,0,3,0,3"/>
<wangtile tileid="109" wangid="0,3,0,3,0,1,0,1"/>
<wangtile tileid="110" wangid="0,1,0,3,0,1,0,3"/>
<wangtile tileid="111" wangid="0,3,0,1,0,3,0,1"/>
<wangtile tileid="114" wangid="0,1,0,1,0,3,0,3"/>
<wangtile tileid="120" wangid="0,2,0,1,0,1,0,1"/>
<wangtile tileid="121" wangid="0,2,0,1,0,1,0,2"/>
<wangtile tileid="122" wangid="0,2,0,1,0,1,0,2"/>
<wangtile tileid="123" wangid="0,2,0,1,0,1,0,2"/>
<wangtile tileid="124" wangid="0,2,0,1,0,1,0,2"/>
<wangtile tileid="125" wangid="0,1,0,1,0,1,0,2"/>
<wangtile tileid="126" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="127" wangid="0,3,0,2,0,2,0,2"/>
<wangtile tileid="128" wangid="0,3,0,2,0,2,0,3"/>
<wangtile tileid="129" wangid="0,3,0,2,0,2,0,3"/>
<wangtile tileid="130" wangid="0,3,0,2,0,2,0,3"/>
<wangtile tileid="131" wangid="0,3,0,2,0,2,0,3"/>
<wangtile tileid="132" wangid="0,2,0,2,0,2,0,3"/>
<wangtile tileid="133" wangid="0,3,0,1,0,1,0,1"/>
<wangtile tileid="134" wangid="0,3,0,1,0,1,0,3"/>
<wangtile tileid="135" wangid="0,3,0,1,0,1,0,3"/>
<wangtile tileid="136" wangid="0,3,0,1,0,1,0,3"/>
<wangtile tileid="137" wangid="0,3,0,1,0,1,0,3"/>
<wangtile tileid="138" wangid="0,1,0,1,0,1,0,3"/>
<wangtile tileid="144" wangid="0,1,0,4,0,1,0,1"/>
<wangtile tileid="145" wangid="0,1,0,4,0,4,0,1"/>
<wangtile tileid="146" wangid="0,1,0,4,0,4,0,1"/>
<wangtile tileid="147" wangid="0,1,0,4,0,4,0,1"/>
<wangtile tileid="148" wangid="0,1,0,4,0,4,0,1"/>
<wangtile tileid="149" wangid="0,1,0,1,0,4,0,1"/>
<wangtile tileid="150" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="151" wangid="0,2,0,4,0,2,0,2"/>
<wangtile tileid="152" wangid="0,2,0,4,0,4,0,2"/>
<wangtile tileid="153" wangid="0,2,0,4,0,4,0,2"/>
<wangtile tileid="154" wangid="0,2,0,4,0,4,0,2"/>
<wangtile tileid="155" wangid="0,2,0,4,0,4,0,2"/>
<wangtile tileid="156" wangid="0,2,0,2,0,4,0,2"/>
<wangtile tileid="168" wangid="0,4,0,4,0,1,0,1"/>
<wangtile tileid="169" wangid="0,4,0,1,0,4,0,4"/>
<wangtile tileid="170" wangid="0,4,0,4,0,1,0,4"/>
<wangtile tileid="171" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="172" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="173" wangid="0,1,0,1,0,4,0,4"/>
<wangtile tileid="174" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="175" wangid="0,4,0,4,0,2,0,2"/>
<wangtile tileid="176" wangid="0,4,0,2,0,4,0,4"/>
<wangtile tileid="177" wangid="0,4,0,4,0,2,0,4"/>
<wangtile tileid="178" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="179" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="180" wangid="0,2,0,2,0,4,0,4"/>
<wangtile tileid="192" wangid="0,4,0,4,0,1,0,1"/>
<wangtile tileid="193" wangid="0,1,0,4,0,4,0,4"/>
<wangtile tileid="194" wangid="0,4,0,4,0,4,0,1"/>
<wangtile tileid="195" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="196" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="197" wangid="0,1,0,1,0,4,0,4"/>
<wangtile tileid="198" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="199" wangid="0,4,0,4,0,2,0,2"/>
<wangtile tileid="200" wangid="0,2,0,4,0,4,0,4"/>
<wangtile tileid="201" wangid="0,4,0,4,0,4,0,2"/>
<wangtile tileid="202" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="203" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="204" wangid="0,2,0,2,0,4,0,4"/>
<wangtile tileid="216" wangid="0,4,0,4,0,1,0,1"/>
<wangtile tileid="217" wangid="0,4,0,1,0,4,0,1"/>
<wangtile tileid="218" wangid="0,1,0,4,0,1,0,4"/>
<wangtile tileid="219" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="220" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="221" wangid="0,1,0,1,0,4,0,4"/>
<wangtile tileid="222" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="223" wangid="0,4,0,4,0,2,0,2"/>
<wangtile tileid="224" wangid="0,4,0,2,0,4,0,2"/>
<wangtile tileid="225" wangid="0,2,0,4,0,2,0,4"/>
<wangtile tileid="226" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="227" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="228" wangid="0,2,0,2,0,4,0,4"/>
<wangtile tileid="240" wangid="0,4,0,4,0,1,0,1"/>
<wangtile tileid="241" wangid="0,1,0,4,0,1,0,4"/>
<wangtile tileid="242" wangid="0,4,0,1,0,4,0,1"/>
<wangtile tileid="243" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="244" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="245" wangid="0,1,0,1,0,4,0,4"/>
<wangtile tileid="246" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="247" wangid="0,4,0,4,0,2,0,2"/>
<wangtile tileid="248" wangid="0,2,0,4,0,2,0,4"/>
<wangtile tileid="249" wangid="0,4,0,2,0,4,0,2"/>
<wangtile tileid="250" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="251" wangid="0,4,0,4,0,4,0,4"/>
<wangtile tileid="252" wangid="0,2,0,2,0,4,0,4"/>
<wangtile tileid="264" wangid="0,4,0,1,0,1,0,1"/>
<wangtile tileid="265" wangid="0,4,0,1,0,1,0,4"/>
<wangtile tileid="266" wangid="0,4,0,1,0,1,0,4"/>
<wangtile tileid="267" wangid="0,4,0,1,0,1,0,4"/>
<wangtile tileid="268" wangid="0,4,0,1,0,1,0,4"/>
<wangtile tileid="269" wangid="0,1,0,1,0,1,0,4"/>
<wangtile tileid="270" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="271" wangid="0,4,0,2,0,2,0,2"/>
<wangtile tileid="272" wangid="0,4,0,2,0,2,0,4"/>
<wangtile tileid="273" wangid="0,4,0,2,0,2,0,4"/>
<wangtile tileid="274" wangid="0,4,0,2,0,2,0,4"/>
<wangtile tileid="275" wangid="0,4,0,2,0,2,0,4"/>
<wangtile tileid="276" wangid="0,2,0,2,0,2,0,4"/>
</wangset>
</wangsets>
</tileset>
<layer id="1" name="Ground" width="45" height="31">
<data encoding="base64" compression="zlib">
eJyNWE1vVVUU3Y0KQeXL4kBL7QAiEkcopQOIkjgysXagYeLIpE0HGucEtY5U6giw1Bj8AdiWxhZ+ANLS4nv+AJKW1+TVH9DklWfSR+LeeWt51j3eWxmsnPvuPR9rr7P3Pvu8hpkd7DFb8dYb24Pf89bFtOOio8/xquNreZ/jdccxx0nH53j+SN7F81nHOfz+BGs1vP0C706i/1kZ+6asMWRdrvMY+4q3bzmedTwj/FfAO/i2HVcc10s4f+t4QzidcEw6vnd8lz0HfrAu3wOO8xj3seO44AT6cY0GONPWTx1jjp8cvzjO4Fsbfan/luP3XXgrJ+4XtWnjeQX9VzBmErgsdud8lXdwCb94G5w3HE+g+R5ZcwDPDx114U3dY569wkW5UZ8J8I6+AfalPbT7MvhS03nMMV3CNzT+A5zHMt70obvezjrWwfue47HwynUhH3JivwG01E1Be0cs8eW3mOd9x2lwXHVsOx7AP8bgI/PCZ5+PmwHvHceSaK76UZO2cGyg1X2mT/eKrtOwUX2Le/RcicbB4zfHyz6239sPs3VijtB6E33XRPPr0CbXmpwaAvrEPPyBvsDvOn4IbQ+4jkHnDaxfE52POl6zFIe0n1oH12Vw37Hq2HzH8W5o6DgE9FrRn+l7uk8rVvSZi6LvDdF4GaBPU2edS32kDjub1vWrMt6Mq8gJkc/OwQbypq9T54jrKcfVkrl+Fq5ctwn9/hTOZefIgPC+7VhEW9tFb+bwyL2Rw3le5DHGeVuY6xrma0DPJtpYL+Ip/JT+TM7uT9/k649jji3MEWMO+5gF2Py4hLOel8y/A1bMKdRbeW8K99BkzlIOmMVe37GuL2u+y/PYCNbbAkfGwCo0vyX9cq0nwbcsXnP/e97xAjADzutoQ6def3+kJ2lMnCmZL/wl/C7y87bsTXDuOB5Bt//jpbgiflBlQwe6am4bE40Dw6J1PscW9inmiJhlvvzVcaAn7fnT8JyC/ZG77u/SX3Nx8CPnQNRxl6xY05XZPYN5HoBv+F+VL49kccF9on9GG757q2J84KXMD0bBrw/+EHt7yro5umqOh7IW1330FHtNvkvQdg72co8GKtajnn2ib+QJ1p7T2XMgzlDPI//mv+C8Db5NWVO/MeangB/Bt4Y9CnuXs7FVIEfWofy9d5cxPF8mRKtNaDQLvxiy5O/xvgMteQ5si7Y1PLdkf8owjvW+hIan7L85gnXJRLd/wQ+ZD+jPjOU1K9ao1JLfeWatgfdtvGcNsBtnzjcu+/+VdWMubNA6i3lNx9MWahl7qvUHa1RqS79pWjord9C/hedFjLsKaByQ72KJLax1437GmqZX+OV2Mz+FP9y0dI52wKuFd3y/CH3Zh1qz1f7x7n62X/USHm3ggqU7pdYyeZ57EedTxI3W1XXw25T1a+DFs4vn/Bz4d7BHm5bOOe4XvzdLeBBRO0YdwzszeYevjFvymYg1xiv1qFvKtx1o17QUi1EXMHYOgfsR8G9Z8hXWiZyrjvFVnFl/kfOxjDdrmeAZeeuapTOce8x6gHquAVEv6jnL51VozH6shdbAn3VnrBvxdtCS7/LdeUv/NUQNxntlG7ypK/dxHWuw/tbzlTVIrMlaKu4Zeu4egm30I+a/WbTL+KaaHoeWh8GX+sZ/I1HnDlixFr9nqY5dtFQztjK+vMurbsH7hqU7J/X+GxyXMGcNWJI9oy9csOJ/PKEr/0cJe96Dvjdl/3g/2ZZ1uH9/Wbe2GnR8AC7Rb8dSPOV2jaIfc7ae6ew7akX/nQRP+kC8j/OO98vgvA95Yj/q2v2SK7Sm5fx5rC2gT/R/YsXacRT7EeMXLMVdcNa4rYrByMd6B676j44+3QFn1U7jTLkzz6nGw/I93m9Yyot5HcdzhPkrELkrYjD8mnGZc2a9pnUO+Q5mPEO/fivG21Grtktty+8eqjM58b873tk+s25c6t0+cNdS/cAYv1Oxfhn6pR20oh+dzvoOZ/b+A6OnAUo=
</data>
</layer>
<layer id="2" name="Fringe" width="45" height="31">
<data encoding="base64" compression="zlib">
eJzVl9lNw0AURZ8ltgr4YquAjliaYPl8DdAChCVABRB2KkBhpwK2sKQC4FgiShQ8tseMx/aVjmRLY+fO3JnnFxGRGZiVamkBFos2EaOBQGQw6N6PFmcltcbwOx50vU+neKYztsb1OmzAZq4uo9XxbjO2wfUBHMJRjt5c6RyacAlXcF2oGzu9wCu0YCohpwcPftJqFdZ+r9uGMf1nvWjtwX7P/UiEN5vzUiZRW5Qao9QarUHRftKI2qLUGKXWaCOjZ9/zprYoNUapNdrM+Hsu5m0jaotSY5Rao62M73Ax70d4gme4yOgjSb01tH/eu/947xd8izvfS7Ds6F2+VZP8e5oVx+8rY0/D90dN385QPnuapN7DZnxvT1O2HiCNqtYD2GaXt3aot9tQh62K9CJn+DyFEziuiOd7fN7BLdyUxDN5C7kL+Yf74I8+8fkB7/AGQ+zdYU/7t21YI/IWchfyD/dBoibwO1nwmSNvIXch/3AfxCopE18ibyF3If9wH8TKNhOfMq2nTSZ5yXSeTOvZn0nU83Mw78Bb1P/tUKbzlHY9k87jD20Li3Y=
</data>
</layer>
<objectgroup id="3" name="Objects">
<object id="1" name="maggots" type="Location" x="435" y="74" width="155" height="99">
<properties>
<property name="spawncount" type="int" value="5"/>
<property name="spawntype" value="maggot"/>
</properties>
</object>
<object id="2" name="discover chest" type="Trigger" x="201" y="200" width="127" height="127">
<properties>
<property name="script" type="file" value="chest-discovered.lua"/>
</properties>
<ellipse/>
</object>
<object id="3" name="unreachable" type="Fixture" x="2" y="158">
<properties>
<property name="static" type="bool" value="true"/>
</properties>
<polygon points="0,0 55,-23 96,-117 110,-61 104,-42 119,-33 116,6 104,9 100,36 60,43 53,58 43,58 34,74 21,69 18,90 0,89"/>
</object>
<object id="5" name="guard" type="NPC" x="22" y="361">
<polyline points="-3,120 87,91 154,96 181,16 273,-1"/>
</object>
<object id="6" name="guard" type="NPC" x="277" y="18">
<polyline points="0,0 75,78 133,82 176,179 274,183"/>
</object>
<object id="10" gid="282" x="413.333" y="225.333" width="16" height="16"/>
<object id="11" gid="282" x="421.667" y="218" width="16" height="16"/>
<object id="12" gid="2147483930" x="423" y="235.333" width="16" height="16"/>
<object id="13" gid="282" x="5" y="70" width="16" height="16"/>
<object id="14" gid="282" x="-3.66667" y="80.3333" width="16" height="16"/>
<object id="16" gid="283" x="538" y="418.333" width="16" height="16"/>
<object id="17" gid="283" x="407.667" y="462" width="16" height="16"/>
<object id="18" gid="283" x="417" y="473.667" width="16" height="16"/>
<object id="19" gid="283" x="402.667" y="469" width="16" height="16"/>
<object id="21" gid="2147483930" x="683.333" y="260.5" width="16" height="16"/>
<object id="22" gid="282" x="692.167" y="269.167" width="16" height="16"/>
<object id="23" gid="282" x="701.667" y="247.833" width="16" height="16"/>
<object id="24" gid="282" x="688.5" y="242" width="16" height="16"/>
<object id="25" gid="282" x="670.5" y="263.5" width="16" height="16"/>
<object id="26" gid="282" x="680" y="284" width="16" height="16"/>
<object id="27" gid="282" x="643.833" y="283.667" width="16" height="16"/>
<object id="28" gid="282" x="63.4165" y="386" width="16" height="16"/>
<object id="29" gid="282" x="9.0835" y="356.167" width="16" height="16"/>
<object id="30" gid="282" x="11.9165" y="385" width="16" height="16"/>
<object id="31" gid="282" x="54.2495" y="378.5" width="16" height="16"/>
<object id="32" gid="2147483930" x="2.4165" y="364.5" width="16" height="16"/>
<object id="33" gid="2147483930" x="41.5835" y="382.833" width="16" height="16"/>
<object id="34" type="Sign" gid="257" x="670.667" y="87" width="16" height="16">
<properties>
<property name="text" value="East West"/>
</properties>
</object>
<object id="37" name="player-start" type="Location" x="192" y="160">
<point/>
</object>
</objectgroup>
</map>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset name="perspective_walls" tilewidth="64" tileheight="64">
<tileoffset x="-32" y="0"/>
<image source="perspective_walls.png"/>
<tile id="13">
<properties>
<property name="door" value="true"/>
</properties>
</tile>
<tile id="14">
<properties>
<property name="door" value="true"/>
</properties>
</tile>
<tile id="15">
<properties>
<property name="pickup" value="true"/>
</properties>
</tile>
</tileset>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.0" orientation="orthogonal" width="50" height="50" tilewidth="24" tileheight="24">
<tileset firstgid="1" name="sewer_tileset" tilewidth="24" tileheight="24">
<image source="sewer_tileset.png" trans="ff00ff" width="192" height="217"/>
</tileset>
<layer name="Bottom" width="50" height="50">
<data encoding="base64" compression="zlib">
eJzt19kKwjAQBdDim0sFqwguL3Vf/sP//ySnkIFhSGrSdEnxPhyQxqJ32kySPMuyJTkZC5KLa2dyNEo1Lsds3wkl/4f+7V/0/f+Y40Je5GpUn2+J5NiQCdmO/HlMyYzMI3JwLUJx7drIsSIFWUfk4FrY3GvGuHb8vr4jcmhNcnAtpIflmmar3VA5nqaWMUKeQ1d9dyht59iRPTmMPEdpua8Put/Frh88P5q84zFkv/NZP2TOlOaH7Hc+64fMmdL8cPVbV9+tcn5MzpTmR0gv12uDbQ4MNT8AIA73Uq3v3hqLe2ldTx4D21k1tf2ubw59Vk1tX+KbQ59VXfuSlMn9SJHV70tS5jqrYu8BAAAAAAAAAABd+wIHfQq1
</data>
</layer>
<layer name="Top" width="50" height="50" opacity="0.49">
<data encoding="base64" compression="zlib">
eJzt1jsKgDAQQEELtVKvYuGvEDvvfya3MBeQQAzMwCPdsum2af5lL71AJv7xL7X+Y46WtzXayq7z2RGd0f2+V6a5bdRFfaZ5pQzRGE2lFwEAoArpDk7Veg+nOzjlHgYAAAAAIIcHvboDlQ==
</data>
</layer>
</map>