dungeoncoder 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. dungeoncoder/__init__.py +4 -0
  2. dungeoncoder/__main__.py +254 -0
  3. dungeoncoder/_api_config.py +6 -0
  4. dungeoncoder/_generated/__init__.py +8 -0
  5. dungeoncoder/_generated/api/__init__.py +1 -0
  6. dungeoncoder/_generated/api/game/__init__.py +1 -0
  7. dungeoncoder/_generated/api/game/get_statistics.py +158 -0
  8. dungeoncoder/_generated/api/game/get_version.py +166 -0
  9. dungeoncoder/_generated/api/hero/__init__.py +1 -0
  10. dungeoncoder/_generated/api/hero/ask_oracle.py +192 -0
  11. dungeoncoder/_generated/api/hero/configure.py +207 -0
  12. dungeoncoder/_generated/api/hero/drop.py +207 -0
  13. dungeoncoder/_generated/api/hero/get_inventory.py +188 -0
  14. dungeoncoder/_generated/api/hero/get_items_at_position.py +188 -0
  15. dungeoncoder/_generated/api/hero/interact.py +188 -0
  16. dungeoncoder/_generated/api/hero/is_abyss_in_front.py +188 -0
  17. dungeoncoder/_generated/api/hero/is_at_goal.py +192 -0
  18. dungeoncoder/_generated/api/hero/is_collision_in_front.py +188 -0
  19. dungeoncoder/_generated/api/hero/is_enemy_in_front.py +188 -0
  20. dungeoncoder/_generated/api/hero/is_facing_north.py +188 -0
  21. dungeoncoder/_generated/api/hero/is_switch_in_front.py +188 -0
  22. dungeoncoder/_generated/api/hero/is_torch_in_front.py +188 -0
  23. dungeoncoder/_generated/api/hero/move.py +188 -0
  24. dungeoncoder/_generated/api/hero/peek_item_value.py +211 -0
  25. dungeoncoder/_generated/api/hero/pickup.py +207 -0
  26. dungeoncoder/_generated/api/hero/read_item_value.py +188 -0
  27. dungeoncoder/_generated/api/hero/sense_goal.py +192 -0
  28. dungeoncoder/_generated/api/hero/set_pace.py +207 -0
  29. dungeoncoder/_generated/api/hero/turn_left.py +188 -0
  30. dungeoncoder/_generated/api/level/__init__.py +1 -0
  31. dungeoncoder/_generated/api/level/load_level.py +190 -0
  32. dungeoncoder/_generated/api/level/reset_level.py +158 -0
  33. dungeoncoder/_generated/client.py +271 -0
  34. dungeoncoder/_generated/errors.py +14 -0
  35. dungeoncoder/_generated/models/__init__.py +47 -0
  36. dungeoncoder/_generated/models/api_error_response.py +98 -0
  37. dungeoncoder/_generated/models/api_error_response_status.py +7 -0
  38. dungeoncoder/_generated/models/boolean_result.py +96 -0
  39. dungeoncoder/_generated/models/boolean_result_status.py +7 -0
  40. dungeoncoder/_generated/models/configure_params.py +84 -0
  41. dungeoncoder/_generated/models/distance_param.py +76 -0
  42. dungeoncoder/_generated/models/name_param.py +76 -0
  43. dungeoncoder/_generated/models/nullable_integer_result.py +104 -0
  44. dungeoncoder/_generated/models/nullable_integer_result_status.py +7 -0
  45. dungeoncoder/_generated/models/nullable_string_result.py +104 -0
  46. dungeoncoder/_generated/models/nullable_string_result_status.py +7 -0
  47. dungeoncoder/_generated/models/pace_params.py +76 -0
  48. dungeoncoder/_generated/models/statistics.py +217 -0
  49. dungeoncoder/_generated/models/statistics_result.py +104 -0
  50. dungeoncoder/_generated/models/statistics_result_status.py +7 -0
  51. dungeoncoder/_generated/models/string_array_result.py +100 -0
  52. dungeoncoder/_generated/models/string_array_result_status.py +7 -0
  53. dungeoncoder/_generated/models/tiled_level.py +67 -0
  54. dungeoncoder/_generated/models/version_result.py +104 -0
  55. dungeoncoder/_generated/models/version_result_result.py +84 -0
  56. dungeoncoder/_generated/models/version_result_status.py +7 -0
  57. dungeoncoder/_generated/types.py +53 -0
  58. dungeoncoder/asciimap.py +824 -0
  59. dungeoncoder/dungeoncoder.py +482 -0
  60. dungeoncoder/generator.py +213 -0
  61. dungeoncoder/packs/gelaende.json +1 -0
  62. dungeoncoder/packs/items.json +67 -0
  63. dungeoncoder/packs/station.json +1 -0
  64. dungeoncoder/packs/studio.json +1 -0
  65. dungeoncoder/packs/tilesets.json +1 -0
  66. dungeoncoder/packs/werkstatt.json +1 -0
  67. dungeoncoder/replay.py +80 -0
  68. dungeoncoder/requirements.txt +2 -0
  69. dungeoncoder/sim.py +792 -0
  70. dungeoncoder/testing.py +63 -0
  71. dungeoncoder/trace.py +92 -0
  72. dungeoncoder/variants.py +112 -0
  73. dungeoncoder-0.2.0.dist-info/METADATA +37 -0
  74. dungeoncoder-0.2.0.dist-info/RECORD +77 -0
  75. dungeoncoder-0.2.0.dist-info/WHEEL +5 -0
  76. dungeoncoder-0.2.0.dist-info/licenses/LICENSE.txt +25 -0
  77. dungeoncoder-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,63 @@
1
+ """Helpers for testing Dungeon Coder programs with pytest, in the simulator.
2
+
3
+ from dungeoncoder.testing import spiel
4
+
5
+ def test_umdrehen_zweimal_ist_wie_vorher():
6
+ game, hero = spiel(\"\"\"
7
+ start: east
8
+ ---
9
+ #####
10
+ #H..#
11
+ #####
12
+ \"\"\")
13
+ umdrehen(hero)
14
+ umdrehen(hero)
15
+ assert not hero.is_facing_north() and hero.move()
16
+
17
+ spiel(...) switches to the simulator (no VS Code needed, steps take no time) and
18
+ loads a level: a map text (see asciimap.py), a .txt map file, or a .json level.
19
+ """
20
+ import os
21
+ import tempfile
22
+ import textwrap
23
+
24
+ from . import dungeoncoder as _core
25
+ from .asciimap import GRID_H, GRID_W, parse_text
26
+ from .dungeoncoder import Game, Hero
27
+
28
+ _versatz = (0, 0) # where the last map text was placed on the 30x20 field
29
+
30
+
31
+ def spiel(level: str) -> tuple[Game, Hero]:
32
+ """(game, hero) for a level in the simulator. `level` is a map text or a file path."""
33
+ if _core._simulator is None:
34
+ _core.use_simulator()
35
+ if "\n" in level:
36
+ path = os.path.join(tempfile.mkdtemp(prefix="dungeoncoder-test-"), "level.txt")
37
+ with open(path, "w", encoding="utf-8") as f:
38
+ f.write(textwrap.dedent(level).strip("\n") + "\n")
39
+ else:
40
+ path = level
41
+ global _versatz
42
+ if path.endswith(".txt"):
43
+ with open(path, encoding="utf-8") as f:
44
+ _, rows = parse_text(f.read())
45
+ _versatz = ((GRID_W - max((len(r) for r in rows), default=0)) // 2, (GRID_H - len(rows)) // 2)
46
+ else:
47
+ _versatz = (0, 0)
48
+ game = Game(path)
49
+ return game, game.get_hero()
50
+
51
+
52
+ def wachen() -> list[tuple[int, int]]:
53
+ """Nur für Tests im Simulator: wo die Wächter gerade stehen, (x, y) in den Koordinaten
54
+ der Karte, wie sie geschrieben ist. Im echten Spiel gibt es das nicht: dort sieht die
55
+ Heldin einen Wächter nur mit is_enemy_in_front()."""
56
+ if _core._simulator is None or _core._simulator.level is None:
57
+ raise RuntimeError("wachen() gibt es nur im Simulator, nach spiel(...)")
58
+ level = _core._simulator.level
59
+ ox, oy = _versatz
60
+ return [(c - ox, r - oy) for c, r in (level.cell_of(o) for o in level.objects if o.kind == "Guard")]
61
+
62
+
63
+ game_for = spiel # English name
dungeoncoder/trace.py ADDED
@@ -0,0 +1,92 @@
1
+ """Traces: every call a program made, with what came back, per loaded level.
2
+
3
+ game.save_trace("spur.json") # in a program: the current level so far
4
+ DUNGEONCODER_TRACE=spur.json python prog.py # every level the program loads, written at the end
5
+
6
+ A trace holds the level itself (also a generated level or a variant) and the calls in
7
+ order, so it can be replayed exactly: `python -m dungeoncoder replay spur.json` shows it
8
+ in the game, `python -m dungeoncoder trace spur.json` lists it with the hero's field after
9
+ every call (computed in the simulator). Positions are not recorded while the program runs:
10
+ the program itself never learns where the hero stands.
11
+
12
+ Format (JSON):
13
+ {"format": "dungeoncoder-trace", "version": 1,
14
+ "runs": [{"level_file": "levels/x.json", "level": {...Tiled JSON...},
15
+ "calls": [["move", null, true], ["is_switch_in_front", null, false], ...],
16
+ "statistics": {...}}]}
17
+ """
18
+ import atexit
19
+ import json
20
+ import os
21
+ import signal
22
+ import sys
23
+ import threading
24
+
25
+ FORMAT, VERSION = "dungeoncoder-trace", 1
26
+ # calls that only the host/tools make, or that don't belong in a replay
27
+ NOT_RECORDED = ("load_level", "get_version")
28
+ MAX_CALLS = 50_000 # per run: a program in an endless loop still gives a trace of its start
29
+
30
+ runs = [] # one entry per loaded level: {"level_file", "level", "calls", "statistics"}
31
+ _level_file = None # the path the next load_level comes from (set by Game)
32
+
33
+
34
+ def loading(path):
35
+ """Game is about to load the level from `path`."""
36
+ global _level_file
37
+ _level_file = path
38
+
39
+
40
+ def record(method, params, result):
41
+ """Called by dungeoncoder._call for every call (cheap: one list append)."""
42
+ if method == "load_level":
43
+ if result:
44
+ runs.append({"level_file": _level_file, "level": params, "calls": []})
45
+ return
46
+ if method in NOT_RECORDED or not runs:
47
+ return
48
+ if len(runs[-1]["calls"]) >= MAX_CALLS:
49
+ runs[-1]["truncated"] = True
50
+ return
51
+ shown = result.to_dict() if hasattr(result, "to_dict") else result
52
+ if method == "get_statistics":
53
+ runs[-1]["statistics"] = shown
54
+ runs[-1]["calls"].append([method, params, shown])
55
+
56
+
57
+ def document(which=None):
58
+ """The trace as a JSON-ready dict: all runs, or only the run objects in `which`."""
59
+ chosen = runs if which is None else which
60
+ return {"format": FORMAT, "version": VERSION, "runs": chosen}
61
+
62
+
63
+ def write(path, which=None):
64
+ with open(path, "w", encoding="utf-8") as f:
65
+ json.dump(document(which), f, ensure_ascii=False)
66
+
67
+
68
+ def read(path):
69
+ """The runs of a trace file; raises ValueError if it isn't one."""
70
+ with open(path, encoding="utf-8") as f:
71
+ data = json.load(f)
72
+ if not isinstance(data, dict) or data.get("format") != FORMAT:
73
+ raise ValueError(f"{path} is not a Dungeon Coder trace")
74
+ return data["runs"]
75
+
76
+
77
+ def _write_at_exit():
78
+ path = os.environ.get("DUNGEONCODER_TRACE", "").strip()
79
+ if path and runs:
80
+ write(path)
81
+
82
+
83
+ atexit.register(_write_at_exit)
84
+
85
+
86
+ def _stop(signum, frame):
87
+ sys.exit(128 + signum) # runs the atexit hooks, so the trace is written
88
+
89
+
90
+ # a stopped program (e.g. `variants` ends one in an endless loop) still writes its trace
91
+ if os.environ.get("DUNGEONCODER_TRACE", "").strip() and threading.current_thread() is threading.main_thread():
92
+ signal.signal(signal.SIGTERM, _stop)
@@ -0,0 +1,112 @@
1
+ """Level variants: one level file, many levels. `Game("schalter.json", seed=17)`.
2
+
3
+ A level marks what may move: a rectangle object of class `Region` (drawn in Tiled, or
4
+ `region:` in a text map) and objects whose property `region` names it. Loading the level
5
+ with a seed puts those objects on different free fields of their region; the same seed
6
+ always gives the same variant, and the map property `seed` carries it (the game shows it
7
+ on its end screen, so a failure can be reproduced).
8
+
9
+ region: s 2,2 17,13 # text map: every switch s lies somewhere in this rectangle
10
+
11
+ Without a seed the level is loaded as drawn, unless its map property `variants` is
12
+ `random`: then every load is a new variant, and the seed is printed. The environment
13
+ variable DUNGEONCODER_SEED fixes such a random seed from outside (grading, tutors).
14
+
15
+ The variant is made here, in Python, before the level goes to the game or the simulator,
16
+ so both get exactly the same level.
17
+ """
18
+ import copy
19
+ import os
20
+ import random
21
+
22
+ REGION = "Region"
23
+
24
+
25
+ def random_seed():
26
+ """A seed for "random": DUNGEONCODER_SEED if set (grading, reproducing), else a new one."""
27
+ fixed = os.environ.get("DUNGEONCODER_SEED", "").strip()
28
+ if fixed.lstrip("-").isdigit():
29
+ return int(fixed), False
30
+ return random.SystemRandom().randrange(1, 1_000_000), True
31
+
32
+
33
+ def _prop(props, name):
34
+ return next((p.get("value") for p in props or [] if p.get("name") == name), None)
35
+
36
+
37
+ def _set_prop(level, name, type_, value):
38
+ props = [p for p in level.get("properties", []) or [] if p.get("name") != name]
39
+ props.append({"name": name, "type": type_, "value": value})
40
+ level["properties"] = props
41
+
42
+
43
+ def has_regions(level):
44
+ return any(o.get("type") == REGION for layer in level.get("layers", []) for o in layer.get("objects", []) or [])
45
+
46
+
47
+ def strip_regions(level):
48
+ """The level without its Region rectangles (they only describe variants)."""
49
+ for layer in level.get("layers", []):
50
+ if "objects" in layer:
51
+ layer["objects"] = [o for o in layer["objects"] if o.get("type") != REGION]
52
+ return level
53
+
54
+
55
+ def _walkable(level):
56
+ """A function (col, row) -> walkable by the game's rules, or None if the tile rules aren't
57
+ available here (then the region is trusted as drawn)."""
58
+ try:
59
+ from . import sim
60
+ rules = sim.Level(strip_regions(copy.deepcopy(level)))
61
+ except Exception: # noqa: BLE001 - e.g. a missing asset pack: trust the region
62
+ return None
63
+ return rules.walkable
64
+
65
+
66
+ def apply(level, seed):
67
+ """A copy of the level with every object of a region on a field of that region chosen by
68
+ `seed` (no two on one field, never on a field another object occupies), map property
69
+ `seed` set. Raises ValueError if a region has fewer free fields than objects."""
70
+ level = copy.deepcopy(level)
71
+ tw, th = level.get("tilewidth", 16), level.get("tileheight", 16)
72
+ objects = [o for layer in level.get("layers", []) for o in layer.get("objects", []) or []]
73
+ regions = {o.get("name", ""): o for o in objects if o.get("type") == REGION}
74
+ walkable = _walkable(level)
75
+ rng = random.Random(seed)
76
+
77
+ def cell(o):
78
+ return int(o["x"] // tw), int((o["y"] - 1) // th)
79
+
80
+ movers = {name: [o for o in objects if o.get("type") != REGION and _prop(o.get("properties"), "region") == name]
81
+ for name in sorted(regions)}
82
+ moving = {id(o) for group in movers.values() for o in group}
83
+ taken = {cell(o) for o in objects if o.get("type") != REGION and id(o) not in moving and o.get("gid")}
84
+ for name, group in movers.items():
85
+ if not group:
86
+ continue
87
+ r = regions[name]
88
+ c0, r0 = int(r["x"] // tw), int(r["y"] // th)
89
+ c1, r1 = int((r["x"] + r["width"] - 1) // tw), int((r["y"] + r["height"] - 1) // th)
90
+ free = [(c, rr) for rr in range(r0, r1 + 1) for c in range(c0, c1 + 1)
91
+ if (c, rr) not in taken and (walkable is None or walkable(c, rr))]
92
+ if len(free) < len(group):
93
+ raise ValueError(f"region {name!r} has {len(free)} free field(s) for {len(group)} object(s)")
94
+ for o, (c, rr) in zip(group, rng.sample(free, len(group))):
95
+ o["x"], o["y"] = c * tw, (rr + 1) * th
96
+ taken.add((c, rr))
97
+ _set_prop(level, "seed", "int", seed)
98
+ return strip_regions(level)
99
+
100
+
101
+ def prepare(level, seed=None):
102
+ """(level to load, seed or None, chosen at random?) for Game(path, seed). Levels without
103
+ regions are returned unchanged (a seed given for them is ignored)."""
104
+ if not has_regions(level):
105
+ return level, None, False
106
+ chosen = False
107
+ if seed is None and str(_prop(level.get("properties"), "variants") or "").lower() == "random":
108
+ seed, _ = random_seed()
109
+ chosen = True
110
+ if seed is None:
111
+ return strip_regions(copy.deepcopy(level)), None, False
112
+ return apply(level, seed), seed, chosen
@@ -0,0 +1,37 @@
1
+ Metadata-Version: 2.4
2
+ Name: dungeoncoder
3
+ Version: 0.2.0
4
+ Summary: Python API for Dungeon Coder: steer the hero from a script, in VS Code or in the built-in simulator
5
+ License-Expression: MIT
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: Intended Audience :: Education
8
+ Classifier: Topic :: Education
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE.txt
12
+ Requires-Dist: httpx>=0.27
13
+ Requires-Dist: attrs>=23.1
14
+ Dynamic: license-file
15
+
16
+ # dungeoncoder
17
+
18
+ The Python API for Dungeon Coder, a VS Code extension in which a Python script steers a hero through a pixel-art dungeon.
19
+
20
+ ```python
21
+ from dungeoncoder import Game
22
+
23
+ game = Game("playground.json")
24
+ hero = game.get_hero()
25
+ while not hero.is_at_goal():
26
+ if hero.is_collision_in_front():
27
+ hero.turn_left()
28
+ else:
29
+ hero.move()
30
+ ```
31
+
32
+ - **With the extension:** start the game in VS Code (`Dungeon Coder: Enter the dungeon`); the script talks to it over a local REST API.
33
+ - **Without VS Code:** `dungeoncoder.use_simulator()` (or `DUNGEONCODER_SIM=1`) runs the same script in a pure-Python simulator of the game's rules: no picture, no waiting. `dungeoncoder.testing.spiel(map_text)` gives `(game, hero)` for pytest.
34
+ - **Levels from text maps:** `Game("karte.txt")`.
35
+ - **Setup check:** `python -m dungeoncoder` says which Python and which copy of the package run, whether the game answers and whether its version fits.
36
+
37
+ The package has the same version as the extension. Install it with `pip install dungeoncoder`.
@@ -0,0 +1,77 @@
1
+ dungeoncoder/__init__.py,sha256=XrFyz332acwER5Y781xhNsC4izHNQNGxbo0hCTv_mDI,158
2
+ dungeoncoder/__main__.py,sha256=HYiXQM02zWpM75K3wpK5gD3FL85oTV-tPISkT6c8M7E,11331
3
+ dungeoncoder/_api_config.py,sha256=wWI57wQZgDT9fsL5Ljasf9B46Ukr1zD5qsKzcLc1zYI,187
4
+ dungeoncoder/asciimap.py,sha256=IpBHmu9xeto4bhWZczCpcOqqZd0V4mkZ9OKCQ_T9lxo,44901
5
+ dungeoncoder/dungeoncoder.py,sha256=fZ32hKKGmH8DrsiNmrWR4WAd0YF-huu2PZr_fUFkI8E,23167
6
+ dungeoncoder/generator.py,sha256=dmkW2C7-fIe2LmnaZzuYwB6THS5HTqBluW5t1C4asnQ,9427
7
+ dungeoncoder/replay.py,sha256=3nQEtXG19x2ZIK1jWgEWbvguNcEXOMNStquXMeSzKlE,3304
8
+ dungeoncoder/requirements.txt,sha256=F-GNwkLSOnRQ1ebP-ZUs2th-4HRn-7j-N_xkDLCn2to,24
9
+ dungeoncoder/sim.py,sha256=OOgKDJh5ak9LzIqnXV_HYaMVHTuQPa89yIdFrCpLym4,35924
10
+ dungeoncoder/testing.py,sha256=CiYsJLKKoU3GBU0bbxolkQkqFe8QZ3lEoFgbwuEFlgo,2252
11
+ dungeoncoder/trace.py,sha256=xE-CewFpmSq2aDCHtT5Lh74AMjmUbGV4eCAC7C1HxnE,3426
12
+ dungeoncoder/variants.py,sha256=3dhyBgmuurwIFG1VAZkzRrxYdRldbiQ_8sjKb8K-iis,4896
13
+ dungeoncoder/_generated/__init__.py,sha256=HIZSbxk1_1Zg9M8NfwBlcYFM1vI7OQsIoQ3a_MLDE1c,162
14
+ dungeoncoder/_generated/client.py,sha256=GDzw6T2uRmPlUb1DImpBGxwy0dNbhmBknfvvIQW0GuU,12387
15
+ dungeoncoder/_generated/errors.py,sha256=trp-p5qn1_JLRxGZhdHtICaNPaCrcDCe4TgIihBravk,546
16
+ dungeoncoder/_generated/types.py,sha256=k9-ddYg6Tq-sd90hvGkH8-9hLj94QeCGVmGNz2xM5JQ,1350
17
+ dungeoncoder/_generated/api/__init__.py,sha256=87ApBzKyGb5zsgTMOkQXDqsLZCmaSFoJMwbGzCDQZMw,47
18
+ dungeoncoder/_generated/api/game/__init__.py,sha256=wYN6A3_bvYW13B1J9YvYCmcv5Els-q-E07kZJwJ7Vto,58
19
+ dungeoncoder/_generated/api/game/get_statistics.py,sha256=xf3zg-Cmv1-vc6s6pGUeqUrjOMwBNZLG3J-dR1HQqOo,3998
20
+ dungeoncoder/_generated/api/game/get_version.py,sha256=qFQ9_6E5fq0krHDr_Zr_tsx6g2wGT4MSjhfmJu7g6Ck,4388
21
+ dungeoncoder/_generated/api/hero/__init__.py,sha256=wYN6A3_bvYW13B1J9YvYCmcv5Els-q-E07kZJwJ7Vto,58
22
+ dungeoncoder/_generated/api/hero/ask_oracle.py,sha256=2vF_NNscEi8AY1dLpjOhwRKCD56ts03ToXH-bWEh_yY,5009
23
+ dungeoncoder/_generated/api/hero/configure.py,sha256=TTusVxlNCF0gVUQli1L-7A8uU-VPKdxfvzF9Vyy7a6U,4880
24
+ dungeoncoder/_generated/api/hero/drop.py,sha256=9Uzizy5b-vAMdkw4YrtDYLElfG15pbdOQH0Puey7u_c,4805
25
+ dungeoncoder/_generated/api/hero/get_inventory.py,sha256=AY4jlFaEBY-x9qnNfXL7LprHAoLhyoNB76IgVuBds2U,4433
26
+ dungeoncoder/_generated/api/hero/get_items_at_position.py,sha256=sN_xsXLQcZ-y2UTRGtwlDBbiZVn8beOmJPqiF5n9voY,4433
27
+ dungeoncoder/_generated/api/hero/interact.py,sha256=fLZnyDjwzengqjbFwdvsPp4T3JAboSwCEWE95tcHeUk,4484
28
+ dungeoncoder/_generated/api/hero/is_abyss_in_front.py,sha256=aoc7FLrR2LK4h4e55KnW1mmR3f8Yfdv75cccFFfRZM0,4432
29
+ dungeoncoder/_generated/api/hero/is_at_goal.py,sha256=k6JwNK8ujRc6f92RL2NoerDSF7HzeAh3KwgjxhPEQZc,4669
30
+ dungeoncoder/_generated/api/hero/is_collision_in_front.py,sha256=4DSrSFRm_f4F0xfNvKw4z6mhxY_vk5kWrFztrd_jiNE,4440
31
+ dungeoncoder/_generated/api/hero/is_enemy_in_front.py,sha256=bH2fN45-8wVqoYSUGQYz86bvaCzNOpRXPhq3rj20JkQ,4412
32
+ dungeoncoder/_generated/api/hero/is_facing_north.py,sha256=YVGZs_4c7c3O7aXfZC_y3lsCGM0xdkFKKZ9-skWvOmE,4342
33
+ dungeoncoder/_generated/api/hero/is_switch_in_front.py,sha256=5hkQVGMfJE-hwBimmZMMmV68G5FAAaYCXeYAIbmI4XQ,4401
34
+ dungeoncoder/_generated/api/hero/is_torch_in_front.py,sha256=cT-1XHDlMxRgEUyAOC39aayKB650sP3pTHDb35rMQMA,4396
35
+ dungeoncoder/_generated/api/hero/move.py,sha256=XMol15DR6Lbxqui1YK7tVPrpghxk64eyI0NcZeVks8k,4300
36
+ dungeoncoder/_generated/api/hero/peek_item_value.py,sha256=Ml8mizVE7na7fMEd6tyhEMrm6JXbhvZRQAb-6qiryJE,5297
37
+ dungeoncoder/_generated/api/hero/pickup.py,sha256=VLDn2qD0iK2YY4Q1wzDEgEwV1QUoB1UTXiQBrXU2CbM,4839
38
+ dungeoncoder/_generated/api/hero/read_item_value.py,sha256=ockVa8TCfc3NHTIxVUfwi5T3DKWmXku-QFJirrZ79AA,4639
39
+ dungeoncoder/_generated/api/hero/sense_goal.py,sha256=eGmulE3qaGxrLwXua5M9urmVTceM2gTr52LM5uagXeg,4850
40
+ dungeoncoder/_generated/api/hero/set_pace.py,sha256=6YZosGxLyzfPyOTT0F3G11Q_5sMmeCZhNRnvwGCljA4,4820
41
+ dungeoncoder/_generated/api/hero/turn_left.py,sha256=AP7tYD-lyyHsVV969PJoQRJzt6jvAV5mVebCihToMoU,4329
42
+ dungeoncoder/_generated/api/level/__init__.py,sha256=wYN6A3_bvYW13B1J9YvYCmcv5Els-q-E07kZJwJ7Vto,58
43
+ dungeoncoder/_generated/api/level/load_level.py,sha256=1iVkkyXHZNbjjOMwIJ42yESplmPoMK51INzpectpn3U,4902
44
+ dungeoncoder/_generated/api/level/reset_level.py,sha256=Id6Vcsl1Wavj7lYWeSE82AKg0mBKbnk4JUZnpo3oOro,3824
45
+ dungeoncoder/_generated/models/__init__.py,sha256=c4f_16DlsbV6LRjLHFHGLehO_bTheQFs53DuzgLO8Qg,1675
46
+ dungeoncoder/_generated/models/api_error_response.py,sha256=2nXlvesqNRP-2VGzVUfWEe-XyU20PvlbrS2x0AX4QXQ,2212
47
+ dungeoncoder/_generated/models/api_error_response_status.py,sha256=oTCGPrkFh-gFE_hm12L8qZ2GL88N3A4S7rwMV75UkGw,146
48
+ dungeoncoder/_generated/models/boolean_result.py,sha256=eKwEKhKC7QtfuNTy8Mn6859GKHl_2hojy4Htno0Nukw,2039
49
+ dungeoncoder/_generated/models/boolean_result_status.py,sha256=4NOZA9jv11OspDKT2Ve_x3yusew6ulZFtssf2FdiFs4,147
50
+ dungeoncoder/_generated/models/configure_params.py,sha256=Lu13I-dBox_S2VW9eUGVj8coknictO5JUZ7kVw7TmtA,1845
51
+ dungeoncoder/_generated/models/distance_param.py,sha256=sBwka39M4n6JgHdsnAXGHXauUGiPGtyZIS7rClXUiB8,1677
52
+ dungeoncoder/_generated/models/name_param.py,sha256=HUKqlv7F5QMnUbnIz3PJx3Ut8oFRRBJ-fISHlAfBzm4,1599
53
+ dungeoncoder/_generated/models/nullable_integer_result.py,sha256=F_6lO01BDRuw4CJQjdflgrTM8VKmUqc0lK54C9ixKNg,2357
54
+ dungeoncoder/_generated/models/nullable_integer_result_status.py,sha256=HJ3Ja0c2Eh9vUZ-wiXOcgTYsnbRcmm-nr2BHAW3bszU,155
55
+ dungeoncoder/_generated/models/nullable_string_result.py,sha256=RKbXYPKIcXiSJk7y5EhidHKO8pmvpZ1N1Yx4Zt8TXF8,2347
56
+ dungeoncoder/_generated/models/nullable_string_result_status.py,sha256=2LBvP2NtWwYNVeTC-6gN_Y5KPG9_fxeuyl_c3q9XZrQ,154
57
+ dungeoncoder/_generated/models/pace_params.py,sha256=gLoWR0ripIbFNb0HrZo2wISspoUnkS3Kgp-U_zzXv2U,1618
58
+ dungeoncoder/_generated/models/statistics.py,sha256=l_cq5x-I30JY0xEgHgQ-IBCB03kIpjXEPYOnTFDEbrc,5718
59
+ dungeoncoder/_generated/models/statistics_result.py,sha256=u0fTcIDmZ75qIVePbsDjWJW9nuZBZH92_SpXWygBrtA,2346
60
+ dungeoncoder/_generated/models/statistics_result_status.py,sha256=HjJ92u3UfD1Oz4KDE_x-JA5_TtfOrNHXGrPHrLae9tw,150
61
+ dungeoncoder/_generated/models/string_array_result.py,sha256=j2IcdEamX8buigvKH5_9_If6ZbVk-GyImnqkNQ6TOqA,2137
62
+ dungeoncoder/_generated/models/string_array_result_status.py,sha256=H1mw62iwwZIgVElO3hI9d9nmGFOUTk5ZLVON_5UE9GE,151
63
+ dungeoncoder/_generated/models/tiled_level.py,sha256=IKVBujaSycyKteryR1BMoCStKAUWoeYe0HEbFpgZ6Hw,1496
64
+ dungeoncoder/_generated/models/version_result.py,sha256=lPLIS4bjzd7u-CxAuhCO1hdDCLt_6cGiBbNw2zpl_U0,2362
65
+ dungeoncoder/_generated/models/version_result_result.py,sha256=uzwIJdobBpNAJOOt7tXjUvwJuojGNzo91TR2WWk_HLk,1871
66
+ dungeoncoder/_generated/models/version_result_status.py,sha256=slTpNJowot9-yOXffNiV4mGptdobN3B85EWyZr33cMs,147
67
+ dungeoncoder/packs/gelaende.json,sha256=Q8NzzL6rVhA2Bymzd6tWa9zVv6h41e9rrcRXiauUvg4,8021
68
+ dungeoncoder/packs/items.json,sha256=ZcuYBLo8larn3JH2qJ4E0nkfKtryntelnJx6lk4b8cU,1554
69
+ dungeoncoder/packs/station.json,sha256=ItoPil_83LprELwygrDU9vMHGhKDlceaLK2n3VqpPwA,7918
70
+ dungeoncoder/packs/studio.json,sha256=-KqKBgTT5DnaJcco1789cZHI5rJINQ0NT3VxAFaOuAg,7854
71
+ dungeoncoder/packs/tilesets.json,sha256=vVHjE_dOBEalXKLoIu3FRDaTT8UiXe0hzrH37sIgkr8,54226
72
+ dungeoncoder/packs/werkstatt.json,sha256=DbPvym5jwiZokBDn7U79zps5jHMAtD0bKvr88sdwczk,8091
73
+ dungeoncoder-0.2.0.dist-info/licenses/LICENSE.txt,sha256=6Hbha-oiKVwW83FDLzR4iCqHHYsM2aPrxXCHWGw60P4,1178
74
+ dungeoncoder-0.2.0.dist-info/METADATA,sha256=opqoq7XqdogE2_4IDIN4emVhxdDf9jkFosagmbU7ePE,1517
75
+ dungeoncoder-0.2.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
76
+ dungeoncoder-0.2.0.dist-info/top_level.txt,sha256=LyJOZeLnQba_mjU-xD0fXxLBj343jnnUwhOeaOEVyPc,13
77
+ dungeoncoder-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,25 @@
1
+ Copyright (c) Microsoft Corporation
2
+ Copyright (c) Munich University of Applied Sciences
3
+ Copyright (c) Benedikt Dietrich
4
+
5
+ All rights reserved.
6
+
7
+ MIT License
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ dungeoncoder