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
@@ -0,0 +1,399 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from typing import TYPE_CHECKING
5
+
6
+ import pygame
7
+
8
+ from ..types.blend import Blend
9
+ from ..util.colors import BLACK, WHITE, Color
10
+ from ..util.constants import (
11
+ BIG_FONT_HEIGHT,
12
+ BIG_FONT_NAME,
13
+ BIG_FONT_WIDTH,
14
+ SMALL_FONT_HEIGHT,
15
+ SMALL_FONT_NAME,
16
+ SMALL_FONT_WIDTH,
17
+ )
18
+ from .pygame_assets import PygameAssets
19
+ from .pygame_audio import PygameAudio
20
+ from .pygame_events import SDL2_BACKGROUND_EVENTS, PygameUserInput
21
+
22
+ if TYPE_CHECKING:
23
+ from ..engine import MimaEngine
24
+ from ..util import RuntimeConfig
25
+
26
+ LOG = logging.getLogger(__name__)
27
+
28
+
29
+ class PygameBackend:
30
+ engine: MimaEngine
31
+
32
+ def __init__(self, rtc: RuntimeConfig, init_file: str, platform: str):
33
+ self.rtc = rtc
34
+ self.init_file: str = init_file
35
+ self.platform: str = platform
36
+ self.icon_path: str = ""
37
+ self.splash_path: str = ""
38
+
39
+ self.render_width: int
40
+ self.render_height: int
41
+ self.pixel_size: int
42
+ self.display_width: int
43
+ self.display_height: int
44
+ self.target_fps: int
45
+
46
+ self.clock: pygame.time.Clock
47
+ self.manual_scale: bool = False
48
+ self.terminate: bool = False
49
+ self.user_input: PygameUserInput
50
+ self.assets: PygameAssets
51
+ self.audio: PygameAudio
52
+
53
+ self.display: pygame.Surface
54
+ self._screen: pygame.Surface
55
+ self._filter: pygame.Surface
56
+ self._filter_color: Color = BLACK
57
+ self._filter_blend: Blend = Blend.DEFAULT
58
+ self._last_sprite_name: str = ""
59
+ self._last_sprite: pygame.Surface
60
+
61
+ def init(self):
62
+ LOG.info("Initializing pygame backend.")
63
+ pygame.mixer.pre_init(44100, -16, 2, 2048)
64
+ pygame.init()
65
+
66
+ self.clock = pygame.time.Clock()
67
+ self.user_input = PygameUserInput(platform=self.platform)
68
+ self.assets = PygameAssets(self.rtc, self.init_file)
69
+ self.audio = PygameAudio(self.assets)
70
+
71
+ def construct(
72
+ self,
73
+ width: int,
74
+ height: int,
75
+ pixel_size: int,
76
+ fullscreen: bool = False,
77
+ target_fps: int = 60,
78
+ resizeable: bool = False,
79
+ ):
80
+ LOG.info("Constructing window.")
81
+ self.render_width, self.display_width = width, width
82
+ self.render_height, self.display_height = height, height
83
+ self.pixel_size = pixel_size
84
+ self.target_fps = target_fps
85
+
86
+ flags = pygame.HWSURFACE | pygame.DOUBLEBUF
87
+ if fullscreen:
88
+ flags = flags | pygame.FULLSCREEN | pygame.SCALED
89
+ self.pixel_size = -1 # Calculate later
90
+ elif pixel_size == 0:
91
+ flags = flags | pygame.SCALED
92
+ self.pixel_size = -1 # Calculate later
93
+ else:
94
+ self.display_width = self.render_width * self.pixel_size
95
+ self.display_height = self.render_height * self.pixel_size
96
+
97
+ self._screen = pygame.display.set_mode(
98
+ (self.display_width, self.display_height), flags
99
+ )
100
+
101
+ if pixel_size > 1:
102
+ self.manual_scale = True
103
+ self.display = pygame.Surface(
104
+ (self.render_width, self.render_height)
105
+ )
106
+ else:
107
+ self.display = self._screen
108
+
109
+ if self.platform == "PC":
110
+ if self.icon_path:
111
+ icon = pygame.image.load(self.icon_path).convert_alpha()
112
+ pygame.display.set_icon(icon)
113
+
114
+ if self.splash_path:
115
+ splash_screen = pygame.image.load(
116
+ self.splash_path
117
+ ).convert_alpha()
118
+ self.display.blit(splash_screen, (0, 0))
119
+ pygame.display.flip()
120
+
121
+ self.user_input.width = self.render_width
122
+ self.user_input.height = self.render_height
123
+ self.assets.load()
124
+ # self.assets.load_items()
125
+
126
+ def clear(self, color: Color = Color(0, 0, 0)):
127
+ self.display.fill(color.getRGBA())
128
+ self._filter = pygame.Surface((self.render_width, self.render_height))
129
+ self._filter.fill(self._filter_color.getRGBA())
130
+
131
+ def configure_filter(
132
+ self, color: Color = BLACK, blend_mode: Blend = Blend.DEFAULT
133
+ ):
134
+ self._filter_color = color
135
+ self._filter_blend = blend_mode
136
+
137
+ def apply_filter(self):
138
+ if self._filter_blend != Blend.DEFAULT:
139
+ self.display.blit(
140
+ self._filter,
141
+ pygame.Vector2(0, 0),
142
+ special_flags=blend_to_pygame_flag(self._filter_blend),
143
+ )
144
+
145
+ def draw_partial_sprite(
146
+ self,
147
+ px: float,
148
+ py: float,
149
+ sprite_name: float,
150
+ sx: float,
151
+ sy: float,
152
+ width: float,
153
+ height: float,
154
+ blend_mode: Blend = Blend.DEFAULT,
155
+ draw_to_filter: bool = False,
156
+ ):
157
+ if sprite_name:
158
+ if draw_to_filter:
159
+ display = self._filter
160
+ else:
161
+ display = self.display
162
+
163
+ if sprite_name != self._last_sprite_name:
164
+ self._last_sprite_name = sprite_name
165
+ self._last_sprite = self.assets.get_sprite(sprite_name)
166
+
167
+ sprite = self._last_sprite
168
+ if sprite is not None:
169
+ try:
170
+ display.blit(
171
+ sprite,
172
+ pygame.Vector2(px, py),
173
+ pygame.Rect(sx, sy, width, height),
174
+ special_flags=0
175
+ if blend_mode == Blend.DEFAULT
176
+ else blend_to_pygame_flag(blend_mode),
177
+ )
178
+ except Exception as e:
179
+ print(
180
+ f"Exception drawing sprite {sprite_name}: {px}, {py}, {sx}, {sy}, {width}, {height}"
181
+ )
182
+ raise e
183
+ # else:
184
+ # print(f"Draw sprite {sprite_name} at {(px, py)}.")
185
+
186
+ def draw_line(
187
+ self, sx: float, sy: float, ex: float, ey: float, color: Color
188
+ ):
189
+ pygame.draw.line(self.display, color.getRGBA(), (sx, sy), (ex, ey))
190
+
191
+ def fill_circle(
192
+ self,
193
+ px: float,
194
+ py: float,
195
+ radius: float,
196
+ color: Color,
197
+ blend_mode: Blend = Blend.DEFAULT,
198
+ draw_to_filter: bool = False,
199
+ ):
200
+ if draw_to_filter:
201
+ display = self._filter
202
+ else:
203
+ display = self.display
204
+
205
+ if blend_mode == Blend.DEFAULT:
206
+ pygame.draw.circle(display, color.getRGBA(), (px, py), radius)
207
+ else:
208
+ surf = pygame.Surface((radius * 2, radius * 2))
209
+ surf.fill((0, 0, 0))
210
+ pygame.draw.circle(surf, color.getRGBA(), (radius, radius), radius)
211
+ rect = surf.get_rect(center=(px, py))
212
+ display.blit(
213
+ surf,
214
+ rect,
215
+ special_flags=blend_to_pygame_flag(blend_mode),
216
+ )
217
+
218
+ def draw_circle(self, px: float, py: float, radius: float, color: Color):
219
+ pygame.draw.circle(
220
+ self.display, color.getRGBA(), (px, py), radius, width=1
221
+ )
222
+
223
+ def fill_rect(
224
+ self,
225
+ px: float,
226
+ py: float,
227
+ width: float,
228
+ height: float,
229
+ color: Color,
230
+ draw_to_filter: bool = False,
231
+ ):
232
+ r, g, b, a = color.getRGBA()
233
+ if draw_to_filter:
234
+ display = self._filter
235
+ else:
236
+ display = self.display
237
+
238
+ if a < 255:
239
+ surf = pygame.Surface((width, height))
240
+ surf.set_alpha(a)
241
+ surf.fill((r, g, b))
242
+ display.blit(surf, (px, py))
243
+ else:
244
+ pygame.draw.rect(
245
+ display,
246
+ (r, g, b),
247
+ pygame.Rect(px, py, width, height),
248
+ )
249
+
250
+ def draw_rect(
251
+ self,
252
+ px: float,
253
+ py: float,
254
+ width: float,
255
+ height: float,
256
+ color: Color,
257
+ line_width: int = 1,
258
+ ):
259
+ line_width = max(1, line_width)
260
+ pygame.draw.rect(
261
+ self.display,
262
+ color.getRGB(),
263
+ pygame.Rect(px, py, width, height),
264
+ width=line_width,
265
+ )
266
+
267
+ def draw_big_text(
268
+ self, text: str, px: float, py: float, color: Color = WHITE
269
+ ):
270
+ self.draw_text(
271
+ text,
272
+ px,
273
+ py,
274
+ BIG_FONT_NAME,
275
+ BIG_FONT_WIDTH,
276
+ BIG_FONT_HEIGHT,
277
+ color,
278
+ )
279
+
280
+ def draw_small_text(
281
+ self, text: str, px: float, py: float, color: Color = WHITE
282
+ ):
283
+ self.draw_text(
284
+ text,
285
+ px,
286
+ py,
287
+ SMALL_FONT_NAME,
288
+ SMALL_FONT_WIDTH,
289
+ SMALL_FONT_HEIGHT,
290
+ color,
291
+ )
292
+
293
+ def draw_text(
294
+ self,
295
+ text: str,
296
+ px: float,
297
+ py: float,
298
+ font_name: str,
299
+ font_width: int,
300
+ font_height: int,
301
+ color: Color = WHITE,
302
+ ):
303
+ if color != WHITE:
304
+ old_sprite = self.assets.get_sprite(font_name)
305
+ new_sprite = old_sprite.copy()
306
+ new_sprite.fill(
307
+ color.getRGBA(), special_flags=pygame.BLEND_RGBA_MIN
308
+ )
309
+ font_name = f"{font_name}_{color.short_name()}"
310
+ self.assets.new_sprite(font_name, new_sprite)
311
+
312
+ idx = 0
313
+ for c in text:
314
+ sx = ((ord(c) - 32) % 16) * font_width
315
+ sy = ((ord(c) - 32) // 16) * font_height
316
+ self.draw_partial_sprite(
317
+ px + idx * font_width,
318
+ py,
319
+ font_name,
320
+ sx,
321
+ sy,
322
+ font_width,
323
+ font_height,
324
+ )
325
+ idx += 1
326
+
327
+ def draw_pixel(self, px: float, py: float, color: Color):
328
+ self.display.set_at((int(px), int(py)), color.getRGB())
329
+
330
+ def set_caption(self, text: str):
331
+ pygame.display.set_caption(text)
332
+
333
+ def keep_running(self) -> bool:
334
+ return not self.terminate
335
+
336
+ def process_events(self):
337
+ self.user_input.reset()
338
+
339
+ for event in pygame.event.get():
340
+ if event.type == pygame.QUIT:
341
+ self.terminate = True
342
+ break
343
+ if event.type == pygame.KEYDOWN:
344
+ if event.key == pygame.K_ESCAPE:
345
+ self.on_user_terminate()
346
+ continue
347
+ if event.type in SDL2_BACKGROUND_EVENTS:
348
+ self._handle_background(event)
349
+ continue
350
+
351
+ self.user_input.process(event)
352
+
353
+ def update_display(self):
354
+ if self.manual_scale:
355
+ self._screen.blit(
356
+ pygame.transform.scale(
357
+ self.display, (self.display_width, self.display_height)
358
+ ),
359
+ (0, 0),
360
+ )
361
+
362
+ pygame.display.flip()
363
+
364
+ def tick(self) -> float:
365
+ return self.clock.tick(self.target_fps) / 1000.0
366
+
367
+ def on_user_terminate(self):
368
+ self.engine.on_user_terminate()
369
+
370
+ def shutdown(self):
371
+ pygame.mixer.quit()
372
+ pygame.quit()
373
+
374
+ def _handle_background(self, event):
375
+ if event.type == 259:
376
+ self.engine.on_enter_background()
377
+ elif event.type == 260:
378
+ self.engine.on_entered_background()
379
+ elif event.type == 261:
380
+ self.engine.on_enter_foreground()
381
+ else:
382
+ self.engine.on_entered_foreground()
383
+
384
+ @property
385
+ def data_path(self):
386
+ return self.assets.data_path
387
+
388
+
389
+ def blend_to_pygame_flag(blend_mode: Blend):
390
+ if blend_mode == Blend.DEFAULT:
391
+ return 0
392
+ elif blend_mode == Blend.ADD:
393
+ return pygame.BLEND_RGBA_ADD
394
+ elif blend_mode == Blend.SUB:
395
+ return pygame.BLEND_RGBA_SUB
396
+ elif blend_mode == Blend.MULT:
397
+ return pygame.BLEND_RGBA_MULT
398
+ else:
399
+ return 0