mima-engine 0.1.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.

Potentially problematic release.


This version of mima-engine might be problematic. Click here for more details.

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