mima-engine 0.4.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.
- mima/__init__.py +4 -0
- mima/backend/__init__.py +1 -0
- mima/backend/pygame_assets.py +401 -0
- mima/backend/pygame_audio.py +78 -0
- mima/backend/pygame_backend.py +603 -0
- mima/backend/pygame_camera.py +63 -0
- mima/backend/pygame_events.py +695 -0
- mima/backend/touch_control_scheme_a.py +126 -0
- mima/backend/touch_control_scheme_b.py +132 -0
- mima/core/__init__.py +0 -0
- mima/core/collision.py +325 -0
- mima/core/database.py +58 -0
- mima/core/engine.py +367 -0
- mima/core/mode_engine.py +81 -0
- mima/core/scene_engine.py +81 -0
- mima/integrated/__init__.py +0 -0
- mima/integrated/entity.py +183 -0
- mima/integrated/layered_map.py +351 -0
- mima/integrated/sprite.py +156 -0
- mima/layered/__init__.py +0 -0
- mima/layered/assets.py +56 -0
- mima/layered/scene.py +415 -0
- mima/layered/shape.py +99 -0
- mima/layered/shaped_sprite.py +78 -0
- mima/layered/virtual_input.py +302 -0
- mima/maps/__init__.py +0 -0
- mima/maps/template.py +71 -0
- mima/maps/tile.py +20 -0
- mima/maps/tile_animation.py +7 -0
- mima/maps/tile_info.py +10 -0
- mima/maps/tile_layer.py +52 -0
- mima/maps/tiled/__init__.py +0 -0
- mima/maps/tiled/tiled_layer.py +48 -0
- mima/maps/tiled/tiled_map.py +95 -0
- mima/maps/tiled/tiled_object.py +79 -0
- mima/maps/tiled/tiled_objectgroup.py +25 -0
- mima/maps/tiled/tiled_template.py +49 -0
- mima/maps/tiled/tiled_tile.py +90 -0
- mima/maps/tiled/tiled_tileset.py +51 -0
- mima/maps/tilemap.py +216 -0
- mima/maps/tileset.py +39 -0
- mima/maps/tileset_info.py +9 -0
- mima/maps/transition_map.py +146 -0
- mima/objects/__init__.py +0 -0
- mima/objects/animated_sprite.py +217 -0
- mima/objects/attribute_effect.py +26 -0
- mima/objects/attributes.py +126 -0
- mima/objects/creature.py +384 -0
- mima/objects/dynamic.py +206 -0
- mima/objects/effects/__init__.py +0 -0
- mima/objects/effects/colorize_screen.py +60 -0
- mima/objects/effects/debug_box.py +133 -0
- mima/objects/effects/light.py +103 -0
- mima/objects/effects/show_sprite.py +50 -0
- mima/objects/effects/walking_on_grass.py +70 -0
- mima/objects/effects/walking_on_water.py +57 -0
- mima/objects/loader.py +111 -0
- mima/objects/projectile.py +111 -0
- mima/objects/sprite.py +116 -0
- mima/objects/world/__init__.py +0 -0
- mima/objects/world/color_gate.py +67 -0
- mima/objects/world/color_switch.py +101 -0
- mima/objects/world/container.py +175 -0
- mima/objects/world/floor_switch.py +109 -0
- mima/objects/world/gate.py +178 -0
- mima/objects/world/light_source.py +121 -0
- mima/objects/world/logic_gate.py +157 -0
- mima/objects/world/movable.py +399 -0
- mima/objects/world/oneway.py +195 -0
- mima/objects/world/pickup.py +157 -0
- mima/objects/world/switch.py +179 -0
- mima/objects/world/teleport.py +308 -0
- mima/py.typed +0 -0
- mima/scripts/__init__.py +2 -0
- mima/scripts/command.py +38 -0
- mima/scripts/commands/__init__.py +0 -0
- mima/scripts/commands/add_quest.py +19 -0
- mima/scripts/commands/change_map.py +34 -0
- mima/scripts/commands/close_dialog.py +9 -0
- mima/scripts/commands/equip_weapon.py +23 -0
- mima/scripts/commands/give_item.py +26 -0
- mima/scripts/commands/give_resource.py +51 -0
- mima/scripts/commands/move_map.py +152 -0
- mima/scripts/commands/move_to.py +49 -0
- mima/scripts/commands/oneway_move.py +58 -0
- mima/scripts/commands/parallel.py +66 -0
- mima/scripts/commands/play_sound.py +13 -0
- mima/scripts/commands/present_item.py +53 -0
- mima/scripts/commands/progress_quest.py +12 -0
- mima/scripts/commands/quit_game.py +8 -0
- mima/scripts/commands/save_game.py +14 -0
- mima/scripts/commands/screen_fade.py +83 -0
- mima/scripts/commands/serial.py +69 -0
- mima/scripts/commands/set_facing_direction.py +21 -0
- mima/scripts/commands/set_spawn_map.py +17 -0
- mima/scripts/commands/show_choices.py +52 -0
- mima/scripts/commands/show_dialog.py +118 -0
- mima/scripts/commands/take_coins.py +23 -0
- mima/scripts/script_processor.py +61 -0
- mima/standalone/__init__.py +0 -0
- mima/standalone/camera.py +153 -0
- mima/standalone/geometry.py +1318 -0
- mima/standalone/multicolumn_list.py +54 -0
- mima/standalone/pixel_font.py +84 -0
- mima/standalone/scripting.py +145 -0
- mima/standalone/spatial.py +186 -0
- mima/standalone/sprite.py +158 -0
- mima/standalone/tiled_map.py +1247 -0
- mima/standalone/transformed_view.py +433 -0
- mima/standalone/user_input.py +563 -0
- mima/states/__init__.py +0 -0
- mima/states/game_state.py +189 -0
- mima/states/memory.py +28 -0
- mima/states/quest.py +71 -0
- mima/types/__init__.py +0 -0
- mima/types/alignment.py +7 -0
- mima/types/blend.py +8 -0
- mima/types/damage.py +42 -0
- mima/types/direction.py +44 -0
- mima/types/gate_color.py +7 -0
- mima/types/graphic_state.py +23 -0
- mima/types/keys.py +64 -0
- mima/types/mode.py +9 -0
- mima/types/nature.py +12 -0
- mima/types/object.py +22 -0
- mima/types/player.py +9 -0
- mima/types/position.py +13 -0
- mima/types/start.py +7 -0
- mima/types/terrain.py +9 -0
- mima/types/tile_collision.py +11 -0
- mima/types/weapon_slot.py +6 -0
- mima/types/window.py +44 -0
- mima/usables/__init__.py +0 -0
- mima/usables/item.py +51 -0
- mima/usables/weapon.py +68 -0
- mima/util/__init__.py +1 -0
- mima/util/colors.py +50 -0
- mima/util/constants.py +55 -0
- mima/util/functions.py +38 -0
- mima/util/input_defaults.py +170 -0
- mima/util/logging.py +51 -0
- mima/util/property.py +8 -0
- mima/util/runtime_config.py +327 -0
- mima/util/trading_item.py +23 -0
- mima/view/__init__.py +0 -0
- mima/view/camera.py +192 -0
- mima/view/mima_mode.py +618 -0
- mima/view/mima_scene.py +231 -0
- mima/view/mima_view.py +12 -0
- mima/view/mima_window.py +244 -0
- mima_engine-0.4.0.dist-info/METADATA +47 -0
- mima_engine-0.4.0.dist-info/RECORD +153 -0
- mima_engine-0.4.0.dist-info/WHEEL +4 -0
mima/__init__.py
ADDED
mima/backend/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import csv
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Dict, Optional
|
|
7
|
+
|
|
8
|
+
import pygame
|
|
9
|
+
|
|
10
|
+
from ..maps.tiled.tiled_map import TiledMap
|
|
11
|
+
from ..maps.tiled.tiled_template import TiledTemplate
|
|
12
|
+
from ..maps.tiled.tiled_tileset import TiledTileset
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from ..maps.tilemap import Tilemap
|
|
16
|
+
from ..util import RuntimeConfig
|
|
17
|
+
|
|
18
|
+
LOG = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class PygameAssets:
|
|
22
|
+
def __init__(self, rtc: RuntimeConfig, init_file: str):
|
|
23
|
+
self.rtc = rtc
|
|
24
|
+
self._images: Dict[str, pygame.Surface] = {}
|
|
25
|
+
self._tilesets: Dict[str, TiledTileset] = {}
|
|
26
|
+
self._templates: Dict[str, TiledTemplate] = {}
|
|
27
|
+
self._sprite_sheets: Dict[str, Dict[Any]] = {}
|
|
28
|
+
self._maps: Dict[str, TiledMap] = {}
|
|
29
|
+
self._music: Dict[str, str] = {}
|
|
30
|
+
self._sound: Dict[str, str] = {}
|
|
31
|
+
self._csvs: Dict[str, str] = {}
|
|
32
|
+
self._assets_to_load: Dict[str, str] = {}
|
|
33
|
+
self._assets_to_preload: Dict[str, str] = {}
|
|
34
|
+
self._paths: Dict[str, str] = {}
|
|
35
|
+
self.data_path = ""
|
|
36
|
+
self._preprocess_asset_file(init_file)
|
|
37
|
+
|
|
38
|
+
def _preprocess_asset_file(self, init_file: str):
|
|
39
|
+
self.data_path = os.path.dirname(init_file)
|
|
40
|
+
# path = os.path.join(self._data_path, asset_file)
|
|
41
|
+
current_type = "paths"
|
|
42
|
+
|
|
43
|
+
with open(init_file) as f:
|
|
44
|
+
for line in f.readlines():
|
|
45
|
+
line = line.strip()
|
|
46
|
+
self._assets_to_load.setdefault(current_type, [])
|
|
47
|
+
self._assets_to_preload.setdefault(current_type, [])
|
|
48
|
+
|
|
49
|
+
assets_to_load = self._assets_to_load
|
|
50
|
+
|
|
51
|
+
if "_PRELOAD]" in line:
|
|
52
|
+
assets_to_load = self._assets_to_preload
|
|
53
|
+
if "[PATHS]" in line:
|
|
54
|
+
current_type = "paths"
|
|
55
|
+
elif "[GFX" in line:
|
|
56
|
+
current_type = "gfx"
|
|
57
|
+
elif "[MAPS" in line:
|
|
58
|
+
current_type = "maps"
|
|
59
|
+
elif "[TEMPLATES" in line:
|
|
60
|
+
current_type = "templates"
|
|
61
|
+
elif "[TILESETS" in line:
|
|
62
|
+
current_type = "tilesets"
|
|
63
|
+
elif "[MUSIC" in line:
|
|
64
|
+
current_type = "music"
|
|
65
|
+
elif "[SFX" in line:
|
|
66
|
+
current_type = "sound"
|
|
67
|
+
elif "[CSV" in line:
|
|
68
|
+
current_type = "csv"
|
|
69
|
+
else:
|
|
70
|
+
if line != "" and not line.startswith("#"):
|
|
71
|
+
if current_type != "paths":
|
|
72
|
+
# print(self.data_path, current_type, line)
|
|
73
|
+
assets_to_load[current_type].append(
|
|
74
|
+
os.path.abspath(
|
|
75
|
+
os.path.join(
|
|
76
|
+
self.data_path,
|
|
77
|
+
self._paths.get(current_type, "."),
|
|
78
|
+
line,
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
else:
|
|
83
|
+
name, p = line.split("=")
|
|
84
|
+
self._paths[name] = p
|
|
85
|
+
|
|
86
|
+
def load(self):
|
|
87
|
+
for gfx in self._assets_to_load.get("gfx", []):
|
|
88
|
+
name = os.path.split(gfx)[1].split(".")[0]
|
|
89
|
+
# print(gfx, name)
|
|
90
|
+
self._load_sprite(name, gfx)
|
|
91
|
+
|
|
92
|
+
for tts in self._assets_to_load.get("tilesets", []):
|
|
93
|
+
try:
|
|
94
|
+
LOG.debug("Attempting to load tileset %s", tts)
|
|
95
|
+
name = os.path.split(tts)[1].split(".")[0]
|
|
96
|
+
self._load_tileset(name, tts)
|
|
97
|
+
except Exception as err:
|
|
98
|
+
LOG.warning("Couldn't load tileset %s: %s", tts, err)
|
|
99
|
+
|
|
100
|
+
for tmp in self._assets_to_load.get("templates", []):
|
|
101
|
+
name = os.path.split(tmp)[1].split(".")[0]
|
|
102
|
+
self._load_template(name, tmp)
|
|
103
|
+
|
|
104
|
+
for tmap in self._assets_to_load.get("maps", []):
|
|
105
|
+
name = os.path.split(tmap)[1].split(".")[0]
|
|
106
|
+
self._load_map(name, tmap)
|
|
107
|
+
|
|
108
|
+
for mus in self._assets_to_load.get("music", []):
|
|
109
|
+
name = os.path.split(mus)[1].split(".")[0]
|
|
110
|
+
self._load_music(name, mus)
|
|
111
|
+
|
|
112
|
+
for snd in self._assets_to_load.get("sound", []):
|
|
113
|
+
name = os.path.split(snd)[1].split(".")[0]
|
|
114
|
+
self._load_sound(name, snd)
|
|
115
|
+
|
|
116
|
+
for csvf in self._assets_to_load.get("csv", []):
|
|
117
|
+
name = os.path.split(csvf)[1].split(".")[0]
|
|
118
|
+
self._load_csv(name, csvf)
|
|
119
|
+
|
|
120
|
+
def _load_csv(self, name, filename):
|
|
121
|
+
if not os.path.isfile(filename):
|
|
122
|
+
filename = os.path.join(
|
|
123
|
+
self.data_path, "csv", os.path.split(filename)[-1]
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
possible_name = os.path.split(filename)[-1][:-4]
|
|
127
|
+
if possible_name in self._csvs:
|
|
128
|
+
LOG.warning(f"CSV '{filename}' already loaded as {possible_name}.")
|
|
129
|
+
elif name in self._csvs:
|
|
130
|
+
LOG.debug(f"CSV '{name}' alread loaded. Skipping.")
|
|
131
|
+
return name
|
|
132
|
+
|
|
133
|
+
with open(filename, "r") as csv_file:
|
|
134
|
+
reader = csv.DictReader(csv_file, delimiter=",")
|
|
135
|
+
self._csvs[name] = [row for row in reader]
|
|
136
|
+
|
|
137
|
+
def _load_sprite(self, name, filename=None):
|
|
138
|
+
if filename is None:
|
|
139
|
+
filename = f"{name}.png"
|
|
140
|
+
|
|
141
|
+
# print(filename)
|
|
142
|
+
if not os.path.isfile(filename):
|
|
143
|
+
filename = os.path.join(
|
|
144
|
+
self.data_path, "gfx", os.path.split(filename)[-1]
|
|
145
|
+
)
|
|
146
|
+
# print(name, filename)
|
|
147
|
+
|
|
148
|
+
possible_name = os.path.split(filename)[-1][:-4]
|
|
149
|
+
if possible_name in self._images:
|
|
150
|
+
LOG.warning(
|
|
151
|
+
"Sprite '%s' is possibly already loaded with name %s.",
|
|
152
|
+
filename,
|
|
153
|
+
possible_name,
|
|
154
|
+
)
|
|
155
|
+
elif name in self._images:
|
|
156
|
+
LOG.debug("Sprite '%s' already loaded. Skipping.")
|
|
157
|
+
return name
|
|
158
|
+
|
|
159
|
+
self._images[name] = self._load_sprite_from_disk(filename)
|
|
160
|
+
|
|
161
|
+
return name
|
|
162
|
+
|
|
163
|
+
def _load_tileset(self, name, filename=None):
|
|
164
|
+
if filename is None:
|
|
165
|
+
filename = f"{name}.tsx"
|
|
166
|
+
|
|
167
|
+
if not os.path.isfile(filename):
|
|
168
|
+
filename = os.path.abspath(
|
|
169
|
+
os.path.join(
|
|
170
|
+
self.data_path,
|
|
171
|
+
self._paths.get("tilesets", "."),
|
|
172
|
+
os.path.split(filename)[-1],
|
|
173
|
+
)
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
possible_name = os.path.split(filename)[-1][:-4]
|
|
177
|
+
if possible_name in self._tilesets:
|
|
178
|
+
LOG.warning(
|
|
179
|
+
"Tileset at '%s' is possible already loaded with name %s.",
|
|
180
|
+
filename,
|
|
181
|
+
possible_name,
|
|
182
|
+
)
|
|
183
|
+
elif name in self._tilesets:
|
|
184
|
+
LOG.debug("Tileset at '%s' already loaded. Skipping", filename)
|
|
185
|
+
return name
|
|
186
|
+
ts = TiledTileset(name, filename)
|
|
187
|
+
self._tilesets[name] = ts
|
|
188
|
+
|
|
189
|
+
# Load sprite sheets
|
|
190
|
+
for tile in ts.tiles:
|
|
191
|
+
if not tile.sprite_name:
|
|
192
|
+
continue
|
|
193
|
+
|
|
194
|
+
self._sprite_sheets.setdefault(tile.sprite_name, {})
|
|
195
|
+
data = {
|
|
196
|
+
"duration": [],
|
|
197
|
+
"ox": [],
|
|
198
|
+
"oy": [],
|
|
199
|
+
"image": [],
|
|
200
|
+
"width": [],
|
|
201
|
+
"height": [],
|
|
202
|
+
}
|
|
203
|
+
if tile.animated:
|
|
204
|
+
for frame in tile._frames:
|
|
205
|
+
data["duration"].append(frame.duration)
|
|
206
|
+
data["ox"].append(frame.frame_id % ts.columns)
|
|
207
|
+
data["oy"].append(frame.frame_id // ts.columns)
|
|
208
|
+
data["image"].append(ts.image_name)
|
|
209
|
+
data["width"].append(ts.tile_width)
|
|
210
|
+
data["height"].append(ts.tile_height)
|
|
211
|
+
else:
|
|
212
|
+
data["duration"].append(1000)
|
|
213
|
+
data["ox"].append(tile.tile_id % ts.columns)
|
|
214
|
+
data["oy"].append(tile.tile_id // ts.columns)
|
|
215
|
+
data["image"].append(ts.image_name)
|
|
216
|
+
data["width"].append(ts.tile_width)
|
|
217
|
+
data["height"].append(ts.tile_height)
|
|
218
|
+
|
|
219
|
+
self._sprite_sheets[tile.sprite_name].setdefault(
|
|
220
|
+
tile.graphic_state, {}
|
|
221
|
+
)
|
|
222
|
+
self._sprite_sheets[tile.sprite_name][tile.graphic_state][
|
|
223
|
+
tile.facing_direction
|
|
224
|
+
] = data
|
|
225
|
+
LOG.debug(
|
|
226
|
+
"%s",
|
|
227
|
+
{
|
|
228
|
+
"operation": "add frames",
|
|
229
|
+
"image": ts.image_name,
|
|
230
|
+
"sprite": tile.sprite_name,
|
|
231
|
+
"graphic_state": tile.graphic_state.name,
|
|
232
|
+
"direction": tile.facing_direction.name,
|
|
233
|
+
"frame_data": data,
|
|
234
|
+
},
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
# for sprite_name in ts.sprite_names:
|
|
238
|
+
# self._sprites[sprite_name] = {}
|
|
239
|
+
return name
|
|
240
|
+
|
|
241
|
+
def _load_template(self, name, filename=None):
|
|
242
|
+
if filename is None:
|
|
243
|
+
filename = f"{name}.tx"
|
|
244
|
+
|
|
245
|
+
if not os.path.isfile(filename):
|
|
246
|
+
filename = os.path.join(
|
|
247
|
+
self.data_path, "templates", os.path.split(filename)[-1]
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
possible_name = os.path.split(filename)[-1][:-3]
|
|
251
|
+
if possible_name in self._templates:
|
|
252
|
+
LOG.warning(
|
|
253
|
+
"Template at '%s' is possible already loaded with name %s.",
|
|
254
|
+
filename,
|
|
255
|
+
possible_name,
|
|
256
|
+
)
|
|
257
|
+
elif name in self._templates:
|
|
258
|
+
LOG.debug("Template at '%s' already loaded. Skipping", filename)
|
|
259
|
+
return name
|
|
260
|
+
|
|
261
|
+
self._templates[name] = TiledTemplate(name, filename)
|
|
262
|
+
return name
|
|
263
|
+
|
|
264
|
+
def _load_map(self, name, filename=None):
|
|
265
|
+
possible_name = os.path.split(filename)[-1][:-4]
|
|
266
|
+
if possible_name in self._maps:
|
|
267
|
+
LOG.warning(
|
|
268
|
+
"Map at '%s' is possibly already loaded with name %s.",
|
|
269
|
+
filename,
|
|
270
|
+
possible_name,
|
|
271
|
+
)
|
|
272
|
+
elif name in self._maps:
|
|
273
|
+
LOG.debug("Map at '%s' already loaded. Skipping", filename)
|
|
274
|
+
return name
|
|
275
|
+
try:
|
|
276
|
+
self._maps[name] = TiledMap(name, filename)
|
|
277
|
+
except KeyError:
|
|
278
|
+
LOG.exception(f"Failed to load map={name}")
|
|
279
|
+
raise
|
|
280
|
+
|
|
281
|
+
return name
|
|
282
|
+
|
|
283
|
+
def _load_music(self, name, filename=None):
|
|
284
|
+
if filename is None:
|
|
285
|
+
filename = f"{name}.ogg"
|
|
286
|
+
|
|
287
|
+
if not os.path.isfile(filename):
|
|
288
|
+
filename = os.path.join(
|
|
289
|
+
self.data_path,
|
|
290
|
+
self._paths.get("music", "."),
|
|
291
|
+
os.path.split(filename)[-1],
|
|
292
|
+
)
|
|
293
|
+
possible_name = os.path.split(filename)[-1][:-4]
|
|
294
|
+
if possible_name in self._music:
|
|
295
|
+
LOG.warning(
|
|
296
|
+
"Music at '%s' is possibly already loaded with name %s.",
|
|
297
|
+
filename,
|
|
298
|
+
possible_name,
|
|
299
|
+
)
|
|
300
|
+
elif name in self._music:
|
|
301
|
+
LOG.debug("Music at '%s already loaded. Skipping.", filename)
|
|
302
|
+
return name
|
|
303
|
+
|
|
304
|
+
self._music[name] = filename
|
|
305
|
+
return name
|
|
306
|
+
|
|
307
|
+
def _load_sound(self, name, filename=None):
|
|
308
|
+
if filename is None:
|
|
309
|
+
filename = f"{name}.ogg"
|
|
310
|
+
|
|
311
|
+
if not os.path.isfile(filename):
|
|
312
|
+
filename = os.path.join(
|
|
313
|
+
self.data_path,
|
|
314
|
+
self._paths.get("sfx", "."),
|
|
315
|
+
os.path.split(filename)[-1],
|
|
316
|
+
)
|
|
317
|
+
possible_name = os.path.split(filename)[-1][:-4]
|
|
318
|
+
if possible_name in self._sound:
|
|
319
|
+
LOG.warning(
|
|
320
|
+
"Sound at '%s' is possibly already loaded with name %s.",
|
|
321
|
+
filename,
|
|
322
|
+
possible_name,
|
|
323
|
+
)
|
|
324
|
+
elif name in self._sound:
|
|
325
|
+
LOG.debug("Sound at '%s already loaded. Skipping.", filename)
|
|
326
|
+
return name
|
|
327
|
+
|
|
328
|
+
self._sound[name] = pygame.mixer.Sound(filename)
|
|
329
|
+
return name
|
|
330
|
+
|
|
331
|
+
def _load_item(self, item):
|
|
332
|
+
LOG.debug("Loading item %s.", item.name)
|
|
333
|
+
self._items[item.name] = item
|
|
334
|
+
|
|
335
|
+
def get_sprite(self, name) -> Optional[pygame.Surface]:
|
|
336
|
+
if name is None:
|
|
337
|
+
return None
|
|
338
|
+
else:
|
|
339
|
+
if self.rtc.flags.get("use_color", False):
|
|
340
|
+
name_color = f"{name}_color"
|
|
341
|
+
else:
|
|
342
|
+
name_color = name
|
|
343
|
+
return self._images.get(name_color, self._images[name])
|
|
344
|
+
|
|
345
|
+
def get_sprite_data(self, sprite_id):
|
|
346
|
+
if not sprite_id:
|
|
347
|
+
return {}
|
|
348
|
+
return self._sprite_sheets[sprite_id]
|
|
349
|
+
|
|
350
|
+
def new_map(self, name, tilemap: Tilemap):
|
|
351
|
+
self._maps[name] = tilemap
|
|
352
|
+
|
|
353
|
+
def new_sprite(self, name, surface: pygame.Surface):
|
|
354
|
+
self._images[name] = surface
|
|
355
|
+
|
|
356
|
+
def get_tileset(self, name):
|
|
357
|
+
if name not in self._tilesets:
|
|
358
|
+
msg = f"Could not find tileset '{name}'."
|
|
359
|
+
raise ValueError(msg)
|
|
360
|
+
# LOG.warning("Could not find tileset %s.", name)
|
|
361
|
+
# return self._tilesets["simple_sheet"]
|
|
362
|
+
return self._tilesets[name]
|
|
363
|
+
|
|
364
|
+
def get_template(self, name):
|
|
365
|
+
if name not in self._templates:
|
|
366
|
+
LOG.warning("Could not find template %s.", name)
|
|
367
|
+
return self._templates["bush01"]
|
|
368
|
+
return self._templates[name]
|
|
369
|
+
|
|
370
|
+
def get_map(self, name):
|
|
371
|
+
return self._maps[name]
|
|
372
|
+
|
|
373
|
+
def get_music(self, name):
|
|
374
|
+
return self._music[name]
|
|
375
|
+
|
|
376
|
+
def get_sound(self, name):
|
|
377
|
+
return self._sound[name]
|
|
378
|
+
|
|
379
|
+
def get_csv(self, name):
|
|
380
|
+
return self._csvs[name]
|
|
381
|
+
|
|
382
|
+
def _load_sprite_from_disk(self, filename: str) -> pygame.Surface:
|
|
383
|
+
if "color" in filename:
|
|
384
|
+
return pygame.image.load(filename).convert_alpha()
|
|
385
|
+
else:
|
|
386
|
+
image = pygame.image.load(filename).convert_alpha()
|
|
387
|
+
var = pygame.PixelArray(image)
|
|
388
|
+
|
|
389
|
+
new_colors = {
|
|
390
|
+
name: color
|
|
391
|
+
for name, color in self.rtc.colors.items()
|
|
392
|
+
if f"{name}_default" in self.rtc.colors
|
|
393
|
+
}
|
|
394
|
+
for name, new_color in new_colors.items():
|
|
395
|
+
var.replace(
|
|
396
|
+
self.rtc.colors[f"{name}_default"].getRGBA(),
|
|
397
|
+
new_color.getRGBA(),
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
del var
|
|
401
|
+
return image
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import TYPE_CHECKING, List, Tuple
|
|
5
|
+
|
|
6
|
+
import pygame
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from .pygame_assets import PygameAssets
|
|
10
|
+
|
|
11
|
+
LOG = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PygameAudio:
|
|
15
|
+
def __init__(self, assets: PygameAssets):
|
|
16
|
+
self.assets = assets
|
|
17
|
+
self.current_track: str = ""
|
|
18
|
+
self.is_playing: bool = False
|
|
19
|
+
self.sound_schedule: List[Tuple[float, str]] = []
|
|
20
|
+
self._time_so_far: float = 0.0
|
|
21
|
+
|
|
22
|
+
def update(self, elapsed_time: float):
|
|
23
|
+
self._time_so_far += elapsed_time
|
|
24
|
+
|
|
25
|
+
sounds_to_remove = []
|
|
26
|
+
for sound_tuple in self.sound_schedule:
|
|
27
|
+
if self._time_so_far >= sound_tuple[0]:
|
|
28
|
+
self._play_sound(sound_tuple[1])
|
|
29
|
+
sounds_to_remove.append(sound_tuple)
|
|
30
|
+
|
|
31
|
+
for sound in sounds_to_remove:
|
|
32
|
+
self.sound_schedule.remove(sound)
|
|
33
|
+
|
|
34
|
+
if self._time_so_far >= 10.0:
|
|
35
|
+
self._time_so_far -= 10.0
|
|
36
|
+
for idx in range(len(self.sound_schedule)):
|
|
37
|
+
self.sound_schedule[idx] = (
|
|
38
|
+
self.sound_schedule[idx][0] - 10.0,
|
|
39
|
+
self.sound_schedule[idx][1],
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
def play_music(self, name: str, repeat: int = -1):
|
|
43
|
+
if self.is_playing and name == self.current_track:
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
else:
|
|
47
|
+
try:
|
|
48
|
+
self._play_music(name)
|
|
49
|
+
self.current_track = name
|
|
50
|
+
self.is_playing = True
|
|
51
|
+
except Exception:
|
|
52
|
+
LOG.exception(f"Could not load {name}.")
|
|
53
|
+
|
|
54
|
+
def _play_music(self, name: str, repeat: int = -1):
|
|
55
|
+
pygame.mixer.music.load(self.assets.get_music(name))
|
|
56
|
+
pygame.mixer.music.play(repeat)
|
|
57
|
+
|
|
58
|
+
def _play_sound(self, name: str):
|
|
59
|
+
snd = self.assets.get_sound(name)
|
|
60
|
+
snd.set_volume(100)
|
|
61
|
+
snd.play()
|
|
62
|
+
|
|
63
|
+
def stop(self):
|
|
64
|
+
if self.is_playing:
|
|
65
|
+
pygame.mixer.music.pause()
|
|
66
|
+
self.is_playing = False
|
|
67
|
+
|
|
68
|
+
def stop_sound(self, sound_to_stop: str):
|
|
69
|
+
self.assets.get_sound(sound_to_stop).set_volume(0)
|
|
70
|
+
|
|
71
|
+
def set_music_volume(self, vol: float):
|
|
72
|
+
pygame.mixer.music.set_volume(vol)
|
|
73
|
+
|
|
74
|
+
def set_sound_volume(self, vol: float):
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
def play_sound(self, sound_to_play: str, delay: float = 0.0):
|
|
78
|
+
self.sound_schedule.append((self._time_so_far + delay, sound_to_play))
|