sonartk 0.1__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.
- sonartk/__init__.py +34 -0
- sonartk/map_builder/__init__.py +14 -0
- sonartk/map_builder/map_2d/__init__.py +25 -0
- sonartk/map_builder/map_2d/direction_tools.py +29 -0
- sonartk/map_builder/map_2d/map_2d.py +257 -0
- sonartk/map_builder/map_2d/map_loader.py +33 -0
- sonartk/map_builder/map_2d/map_object/__init__.py +4 -0
- sonartk/map_builder/map_2d/map_object/character.py +15 -0
- sonartk/map_builder/map_2d/map_object/map_object.py +11 -0
- sonartk/map_builder/map_2d/map_queries.py +1330 -0
- sonartk/map_builder/map_2d/map_tile.py +37 -0
- sonartk/map_builder/map_2d/map_tools.py +56 -0
- sonartk/map_builder/map_2d/parser/__init__.py +5 -0
- sonartk/map_builder/map_2d/parser/csv_parser.py +38 -0
- sonartk/map_builder/map_2d/parser/json_parser.py +36 -0
- sonartk/map_builder/map_2d/parser/map_parser.py +33 -0
- sonartk/map_builder/map_2d/parser/stop_parsing_exception.py +2 -0
- sonartk/orchestration/__init__.py +76 -0
- sonartk/orchestration/audio_controls.py +66 -0
- sonartk/orchestration/audio_lifecycle.py +24 -0
- sonartk/orchestration/game_builder.py +169 -0
- sonartk/orchestration/input_gate.py +17 -0
- sonartk/orchestration/map_object_collection.py +183 -0
- sonartk/orchestration/map_sound_navigation.py +384 -0
- sonartk/orchestration/message_action_state.py +91 -0
- sonartk/orchestration/proximity_audio.py +134 -0
- sonartk/orchestration/scene_audio_state.py +100 -0
- sonartk/py.typed +0 -0
- sonartk/sound/__init__.py +10 -0
- sonartk/sound/openal_lite/__init__.py +39 -0
- sonartk/sound/openal_lite/openal.py +5402 -0
- sonartk/sound/player_pool.py +93 -0
- sonartk/sound/sound_manager.py +473 -0
- sonartk/sound/sound_pool.py +158 -0
- sonartk/ui/__init__.py +22 -0
- sonartk/ui/element/__init__.py +21 -0
- sonartk/ui/element/button.py +36 -0
- sonartk/ui/element/checkbox.py +58 -0
- sonartk/ui/element/element.py +114 -0
- sonartk/ui/element/grid.py +274 -0
- sonartk/ui/element/menu.py +239 -0
- sonartk/ui/element/text_box.py +742 -0
- sonartk/ui/element/text_label.py +33 -0
- sonartk/ui/element/toggle_button.py +64 -0
- sonartk/ui/focusable_container.py +26 -0
- sonartk/ui/screen/__init__.py +5 -0
- sonartk/ui/screen/container_screen.py +65 -0
- sonartk/ui/screen/dialog.py +68 -0
- sonartk/ui/screen/screen.py +116 -0
- sonartk/ui/ui_component.py +80 -0
- sonartk/ui/window.py +411 -0
- sonartk/util/__init__.py +32 -0
- sonartk/util/key_handler.py +429 -0
- sonartk/util/speech_manager.py +234 -0
- sonartk/util/state.py +107 -0
- sonartk/util/state_machine.py +139 -0
- sonartk-0.1.dist-info/METADATA +426 -0
- sonartk-0.1.dist-info/RECORD +61 -0
- sonartk-0.1.dist-info/WHEEL +5 -0
- sonartk-0.1.dist-info/licenses/LICENSE +21 -0
- sonartk-0.1.dist-info/top_level.txt +1 -0
sonartk/__init__.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from importlib import import_module
|
|
2
|
+
from typing import TYPE_CHECKING, Any
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"Window",
|
|
6
|
+
"MapGridGameBuilder",
|
|
7
|
+
"BuiltMapGridGame",
|
|
8
|
+
"MapSoundNavigationController",
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from sonartk.orchestration.game_builder import (
|
|
13
|
+
BuiltMapGridGame,
|
|
14
|
+
MapGridGameBuilder,
|
|
15
|
+
)
|
|
16
|
+
from sonartk.orchestration.map_sound_navigation import (
|
|
17
|
+
MapSoundNavigationController,
|
|
18
|
+
)
|
|
19
|
+
from sonartk.ui.window import Window
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def __getattr__(name: str) -> Any:
|
|
23
|
+
if name == "Window":
|
|
24
|
+
from sonartk.ui.window import Window
|
|
25
|
+
|
|
26
|
+
return Window
|
|
27
|
+
if name in {
|
|
28
|
+
"MapGridGameBuilder",
|
|
29
|
+
"BuiltMapGridGame",
|
|
30
|
+
"MapSoundNavigationController",
|
|
31
|
+
}:
|
|
32
|
+
orchestration = import_module("sonartk.orchestration")
|
|
33
|
+
return getattr(orchestration, name)
|
|
34
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from importlib import import_module
|
|
2
|
+
from typing import TYPE_CHECKING, Any
|
|
3
|
+
|
|
4
|
+
__all__ = ["Map2d", "MapTile", "load_2d_map"]
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from sonartk.map_builder.map_2d import Map2d, MapTile, load_2d_map
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def __getattr__(name: str) -> Any:
|
|
11
|
+
if name in __all__:
|
|
12
|
+
module = import_module("sonartk.map_builder.map_2d")
|
|
13
|
+
return getattr(module, name)
|
|
14
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from sonartk.map_builder.map_2d.map_loader import load_2d_map
|
|
2
|
+
from sonartk.map_builder.map_2d.map_2d import Map2d
|
|
3
|
+
from sonartk.map_builder.map_2d.map_queries import (
|
|
4
|
+
Map2dQueries,
|
|
5
|
+
MapQueryResult,
|
|
6
|
+
PathfindingResult,
|
|
7
|
+
PathfindingState,
|
|
8
|
+
)
|
|
9
|
+
from sonartk.map_builder.map_2d.map_tile import MapTile
|
|
10
|
+
from sonartk.map_builder.map_2d.direction_tools import (
|
|
11
|
+
direction_offset,
|
|
12
|
+
step_coordinates,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"Map2d",
|
|
17
|
+
"Map2dQueries",
|
|
18
|
+
"MapQueryResult",
|
|
19
|
+
"PathfindingResult",
|
|
20
|
+
"PathfindingState",
|
|
21
|
+
"MapTile",
|
|
22
|
+
"direction_offset",
|
|
23
|
+
"step_coordinates",
|
|
24
|
+
"load_2d_map",
|
|
25
|
+
]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from sonartk.util import Coordinates, Direction
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def direction_offset(direction: Direction) -> tuple[int, int]:
|
|
5
|
+
"""Return the coordinate delta for a Direction value."""
|
|
6
|
+
direction_to_offset: dict[Direction, tuple[int, int]] = {
|
|
7
|
+
Direction.UP: (0, 1),
|
|
8
|
+
Direction.DIAGONAL_UPPER_RIGHT: (1, 1),
|
|
9
|
+
Direction.RIGHT: (1, 0),
|
|
10
|
+
Direction.DIAGONAL_LOWER_RIGHT: (1, -1),
|
|
11
|
+
Direction.DOWN: (0, -1),
|
|
12
|
+
Direction.DIAGONAL_LOWER_LEFT: (-1, -1),
|
|
13
|
+
Direction.LEFT: (-1, 0),
|
|
14
|
+
Direction.DIAGONAL_UPPER_LEFT: (-1, 1),
|
|
15
|
+
}
|
|
16
|
+
return direction_to_offset[direction]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def step_coordinates(
|
|
20
|
+
origin: Coordinates,
|
|
21
|
+
direction: Direction,
|
|
22
|
+
distance: int = 1,
|
|
23
|
+
) -> Coordinates:
|
|
24
|
+
"""Translate origin by direction and integer distance."""
|
|
25
|
+
if distance < 0:
|
|
26
|
+
raise ValueError("distance must be greater than or equal to 0")
|
|
27
|
+
|
|
28
|
+
dx, dy = direction_offset(direction)
|
|
29
|
+
return (origin[0] + (dx * distance), origin[1] + (dy * distance))
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
from types import MappingProxyType
|
|
2
|
+
from typing import Literal, Mapping, Optional
|
|
3
|
+
|
|
4
|
+
from sonartk.map_builder.map_2d.map_object.character import Character
|
|
5
|
+
from sonartk.map_builder.map_2d.map_tile import MapTile
|
|
6
|
+
from sonartk.map_builder.map_2d.map_object import MapObject
|
|
7
|
+
from sonartk.map_builder.map_2d.map_queries import Map2dQueries
|
|
8
|
+
from sonartk.util import Coordinates
|
|
9
|
+
|
|
10
|
+
CharacterCollisionPolicy = Literal["error", "replace"]
|
|
11
|
+
ObjectCollisionPolicy = Literal["error", "replace"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Map2d:
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
name: str,
|
|
18
|
+
character: Character,
|
|
19
|
+
*,
|
|
20
|
+
character_collision_policy: CharacterCollisionPolicy = "error",
|
|
21
|
+
object_collision_policy: ObjectCollisionPolicy = "error",
|
|
22
|
+
) -> None:
|
|
23
|
+
self.name: str = name
|
|
24
|
+
self.character: Character = character
|
|
25
|
+
self.tile_map: list[MapTile] = []
|
|
26
|
+
self.height: int = 0
|
|
27
|
+
self.width: int = 0
|
|
28
|
+
self.character_collision_policy = character_collision_policy
|
|
29
|
+
self.object_collision_policy = object_collision_policy
|
|
30
|
+
self._character_index: dict[Coordinates, Character] = {}
|
|
31
|
+
self._object_index: dict[Coordinates, MapObject] = {}
|
|
32
|
+
self._character_index_view: Mapping[Coordinates, Character] = (
|
|
33
|
+
MappingProxyType(self._character_index)
|
|
34
|
+
)
|
|
35
|
+
self._object_index_view: Mapping[Coordinates, MapObject] = (
|
|
36
|
+
MappingProxyType(self._object_index)
|
|
37
|
+
)
|
|
38
|
+
self.queries: Map2dQueries = Map2dQueries(self)
|
|
39
|
+
self.register_character(character)
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def character_index(self) -> Mapping[Coordinates, Character]:
|
|
43
|
+
"""Read-only coordinate index for registered characters."""
|
|
44
|
+
return self._character_index_view
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def object_index(self) -> Mapping[Coordinates, MapObject]:
|
|
48
|
+
"""Read-only coordinate index for registered map objects."""
|
|
49
|
+
return self._object_index_view
|
|
50
|
+
|
|
51
|
+
def add_row(self, row: list[MapTile]) -> None:
|
|
52
|
+
"""Insert a map row and update map dimensions.
|
|
53
|
+
|
|
54
|
+
New rows are prepended so ``y=0`` points at the most recently inserted
|
|
55
|
+
row, matching the current map coordinate convention.
|
|
56
|
+
"""
|
|
57
|
+
if self.tile_map and self.width != len(row):
|
|
58
|
+
raise IndexError(
|
|
59
|
+
f"The width of the new row must match the width of the map. Row Width: {len(row)} - Map Width: {self.width}"
|
|
60
|
+
)
|
|
61
|
+
if not self.tile_map:
|
|
62
|
+
self.width = len(row)
|
|
63
|
+
|
|
64
|
+
self.height += 1
|
|
65
|
+
self.tile_map[:0] = row
|
|
66
|
+
|
|
67
|
+
def get_tile(self, coordinates: Coordinates) -> MapTile:
|
|
68
|
+
"""Return the tile at coordinates, raising on out-of-range access."""
|
|
69
|
+
x, y = coordinates
|
|
70
|
+
if x >= self.width or x < 0:
|
|
71
|
+
raise IndexError(
|
|
72
|
+
f"x value is out of bounds. x cannot be less than0 or greater than map width. x: {x} - map width: {self.width}"
|
|
73
|
+
)
|
|
74
|
+
if y >= self.height or y < 0:
|
|
75
|
+
raise IndexError(
|
|
76
|
+
f"y value is out of bounds. y cannot be less than 0 or greater than map height. y: {y} - map height: {self.height}"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
return self.tile_map[y * self.width + x]
|
|
80
|
+
|
|
81
|
+
def set_tile(self, coordinates: Coordinates, tile: MapTile) -> None:
|
|
82
|
+
"""Replace the tile at coordinates, raising on out-of-range access."""
|
|
83
|
+
x, y = coordinates
|
|
84
|
+
if x >= self.width or x < 0:
|
|
85
|
+
raise IndexError(
|
|
86
|
+
f"x value is out of bounds. x cannot be less than0 or greater than map width. x: {x} - map width: {self.width}"
|
|
87
|
+
)
|
|
88
|
+
if y >= self.height or y < 0:
|
|
89
|
+
raise IndexError(
|
|
90
|
+
f"y value is out of bounds. y cannot be less than 0 or greater than map height. y: {y} - map height: {self.height}"
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
self.tile_map[y * self.width + x] = tile
|
|
94
|
+
|
|
95
|
+
def set_tiles(self, updates: Mapping[Coordinates, MapTile]) -> None:
|
|
96
|
+
"""Apply multiple tile replacements as a single convenience operation."""
|
|
97
|
+
for coordinates, tile in updates.items():
|
|
98
|
+
self.set_tile(coordinates, tile)
|
|
99
|
+
|
|
100
|
+
def register_character(self, character: Character) -> Optional[Character]:
|
|
101
|
+
"""Register a character and return any displaced occupant at that coordinate."""
|
|
102
|
+
self._validate_coordinate_for_registration(character.coordinates)
|
|
103
|
+
displaced = self._ensure_character_slot_available(
|
|
104
|
+
character.coordinates, character
|
|
105
|
+
)
|
|
106
|
+
self._character_index[character.coordinates] = character
|
|
107
|
+
return displaced
|
|
108
|
+
|
|
109
|
+
def move_character(
|
|
110
|
+
self, character: Character, new_coordinates: Coordinates
|
|
111
|
+
) -> Optional[Character]:
|
|
112
|
+
"""Move a character and return any displaced occupant at destination."""
|
|
113
|
+
self._validate_coordinate_for_registration(new_coordinates)
|
|
114
|
+
current_coordinates = character.coordinates
|
|
115
|
+
if self._character_index.get(current_coordinates) is not character:
|
|
116
|
+
raise LookupError(
|
|
117
|
+
f"The character {character.name} is not registered at coordinates {current_coordinates}."
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
displaced = self._ensure_character_slot_available(
|
|
121
|
+
new_coordinates, character
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
del self._character_index[current_coordinates]
|
|
125
|
+
character.coordinates = new_coordinates
|
|
126
|
+
self._character_index[new_coordinates] = character
|
|
127
|
+
return displaced
|
|
128
|
+
|
|
129
|
+
def remove_character(self, character: Character) -> None:
|
|
130
|
+
"""Remove a registered character from the coordinate index."""
|
|
131
|
+
current_coordinates = character.coordinates
|
|
132
|
+
if self._character_index.get(current_coordinates) is not character:
|
|
133
|
+
raise LookupError(
|
|
134
|
+
f"The character {character.name} is not registered at coordinates {current_coordinates}."
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
del self._character_index[current_coordinates]
|
|
138
|
+
|
|
139
|
+
def register_map_object(
|
|
140
|
+
self, map_object: MapObject
|
|
141
|
+
) -> Optional[MapObject]:
|
|
142
|
+
"""Register a map object and return any displaced occupant at that coordinate."""
|
|
143
|
+
self._validate_coordinate_for_registration(map_object.coordinates)
|
|
144
|
+
displaced = self._ensure_object_slot_available(
|
|
145
|
+
map_object.coordinates, map_object
|
|
146
|
+
)
|
|
147
|
+
self._object_index[map_object.coordinates] = map_object
|
|
148
|
+
return displaced
|
|
149
|
+
|
|
150
|
+
def move_map_object(
|
|
151
|
+
self, map_object: MapObject, new_coordinates: Coordinates
|
|
152
|
+
) -> Optional[MapObject]:
|
|
153
|
+
"""Move a map object and return any displaced occupant at destination."""
|
|
154
|
+
self._validate_coordinate_for_registration(new_coordinates)
|
|
155
|
+
current_coordinates = map_object.coordinates
|
|
156
|
+
if self._object_index.get(current_coordinates) is not map_object:
|
|
157
|
+
raise LookupError(
|
|
158
|
+
f"The map object {map_object.name} is not registered at coordinates {current_coordinates}."
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
displaced = self._ensure_object_slot_available(
|
|
162
|
+
new_coordinates, map_object
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
del self._object_index[current_coordinates]
|
|
166
|
+
map_object.coordinates = new_coordinates
|
|
167
|
+
self._object_index[new_coordinates] = map_object
|
|
168
|
+
return displaced
|
|
169
|
+
|
|
170
|
+
def remove_map_object(self, map_object: MapObject) -> None:
|
|
171
|
+
"""Remove a registered map object from the coordinate index."""
|
|
172
|
+
current_coordinates = map_object.coordinates
|
|
173
|
+
if self._object_index.get(current_coordinates) is not map_object:
|
|
174
|
+
raise LookupError(
|
|
175
|
+
f"The map object {map_object.name} is not registered at coordinates {current_coordinates}."
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
del self._object_index[current_coordinates]
|
|
179
|
+
|
|
180
|
+
def find_map_object_coordinates(
|
|
181
|
+
self, map_object: MapObject
|
|
182
|
+
) -> Optional[Coordinates]:
|
|
183
|
+
"""Return coordinates for a registered map object by identity."""
|
|
184
|
+
for coordinates, registered_object in self._object_index.items():
|
|
185
|
+
if registered_object is map_object:
|
|
186
|
+
return coordinates
|
|
187
|
+
|
|
188
|
+
return None
|
|
189
|
+
|
|
190
|
+
def is_map_object_registered(self, map_object: MapObject) -> bool:
|
|
191
|
+
"""Return whether a map object is currently registered by identity."""
|
|
192
|
+
return self.find_map_object_coordinates(map_object) is not None
|
|
193
|
+
|
|
194
|
+
def get_map_object_at(
|
|
195
|
+
self, coordinates: Coordinates
|
|
196
|
+
) -> Optional[MapObject]:
|
|
197
|
+
"""Return the registered map object at coordinates, if present."""
|
|
198
|
+
return self._object_index.get(coordinates)
|
|
199
|
+
|
|
200
|
+
def remove_map_object_at(
|
|
201
|
+
self, coordinates: Coordinates
|
|
202
|
+
) -> Optional[MapObject]:
|
|
203
|
+
"""Remove and return the map object at coordinates, if present."""
|
|
204
|
+
removed = self._object_index.get(coordinates)
|
|
205
|
+
if removed is None:
|
|
206
|
+
return None
|
|
207
|
+
|
|
208
|
+
del self._object_index[coordinates]
|
|
209
|
+
return removed
|
|
210
|
+
|
|
211
|
+
def _ensure_character_slot_available(
|
|
212
|
+
self, coordinates: Coordinates, character: Character
|
|
213
|
+
) -> Optional[Character]:
|
|
214
|
+
existing = self._character_index.get(coordinates)
|
|
215
|
+
if existing is None or existing is character:
|
|
216
|
+
return None
|
|
217
|
+
|
|
218
|
+
if self.character_collision_policy == "replace":
|
|
219
|
+
del self._character_index[coordinates]
|
|
220
|
+
return existing
|
|
221
|
+
|
|
222
|
+
raise ValueError(
|
|
223
|
+
f"Character coordinate collision at {coordinates} for '{character.name}'."
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
def _validate_coordinate_for_registration(
|
|
227
|
+
self, coordinates: Coordinates
|
|
228
|
+
) -> None:
|
|
229
|
+
"""Validate coordinates when map dimensions are known.
|
|
230
|
+
|
|
231
|
+
Map entities are constructed before rows are loaded in many flows, so
|
|
232
|
+
bounds checks are deferred until width/height are available.
|
|
233
|
+
"""
|
|
234
|
+
if self.width == 0 or self.height == 0:
|
|
235
|
+
return
|
|
236
|
+
|
|
237
|
+
x, y = coordinates
|
|
238
|
+
if x < 0 or y < 0 or x >= self.width or y >= self.height:
|
|
239
|
+
raise ValueError(
|
|
240
|
+
"Coordinates out of map bounds: "
|
|
241
|
+
f"{coordinates} for map size ({self.width}, {self.height})."
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
def _ensure_object_slot_available(
|
|
245
|
+
self, coordinates: Coordinates, map_object: MapObject
|
|
246
|
+
) -> Optional[MapObject]:
|
|
247
|
+
existing = self._object_index.get(coordinates)
|
|
248
|
+
if existing is None or existing is map_object:
|
|
249
|
+
return None
|
|
250
|
+
|
|
251
|
+
if self.object_collision_policy == "replace":
|
|
252
|
+
del self._object_index[coordinates]
|
|
253
|
+
return existing
|
|
254
|
+
|
|
255
|
+
raise ValueError(
|
|
256
|
+
f"Map object coordinate collision at {coordinates} for '{map_object.name}'."
|
|
257
|
+
)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from typing import Callable, TypeVar
|
|
2
|
+
|
|
3
|
+
from sonartk.map_builder.map_2d.map_2d import Map2d
|
|
4
|
+
from sonartk.map_builder.map_2d.map_object.character import Character
|
|
5
|
+
from sonartk.map_builder.map_2d.map_tile import MapTile
|
|
6
|
+
from sonartk.map_builder.map_2d.parser.map_parser import MapParser
|
|
7
|
+
from sonartk.map_builder.map_2d.parser.stop_parsing_exception import (
|
|
8
|
+
StopParsingException,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
T = TypeVar("T")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def load_2d_map(
|
|
15
|
+
map_name: str,
|
|
16
|
+
file_name: str,
|
|
17
|
+
parser: MapParser[T],
|
|
18
|
+
mapper: Callable[[T], MapTile],
|
|
19
|
+
character: Character,
|
|
20
|
+
) -> Map2d:
|
|
21
|
+
"""Load a 2D map file with a parser and convert each parsed entry to a MapTile."""
|
|
22
|
+
map2d: Map2d = Map2d(map_name, character)
|
|
23
|
+
with parser:
|
|
24
|
+
parser.open(file_name)
|
|
25
|
+
while True:
|
|
26
|
+
try:
|
|
27
|
+
row: list[T] = parser.read()
|
|
28
|
+
mapped_row: list[MapTile] = [mapper(tile) for tile in row]
|
|
29
|
+
map2d.add_row(mapped_row)
|
|
30
|
+
except StopParsingException:
|
|
31
|
+
break
|
|
32
|
+
|
|
33
|
+
return map2d
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from sonartk.map_builder.map_2d.map_object import MapObject
|
|
2
|
+
from sonartk.util import Coordinates, Direction
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Character(MapObject):
|
|
6
|
+
def __init__(
|
|
7
|
+
self,
|
|
8
|
+
name: str,
|
|
9
|
+
coordinates: Coordinates,
|
|
10
|
+
directional_orientation: Direction,
|
|
11
|
+
radius: int = 5,
|
|
12
|
+
) -> None:
|
|
13
|
+
super().__init__(name, coordinates)
|
|
14
|
+
self.directional_orientation: Direction = directional_orientation
|
|
15
|
+
self.radius: int = radius
|