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,88 @@
1
+ from ...objects.dynamic import Dynamic
2
+ from ...types.nature import Nature
3
+ from ...types.object import ObjectType
4
+ from ...types.terrain import Terrain
5
+ from ...util.colors import BLACK
6
+ from ..effects.walking_on_grass import WalkingOnGrass
7
+ from ..effects.walking_on_water import WalkingOnWater
8
+
9
+
10
+ class Pickup(Dynamic):
11
+ def __init__(self, px: float, py: float, item_name: str, dyn_id=-1):
12
+ super().__init__("Pickup", px, py, dyn_id)
13
+ self.type: ObjectType = ObjectType.PICKUP
14
+ self.item = self.engine.get_item(item_name)
15
+ self.collected = False
16
+ self.solid_vs_dyn = False
17
+
18
+ def update(self, elapsed_time: float, target=None):
19
+ if self.collected:
20
+ self.kill()
21
+ else:
22
+ self._handle_terrain(elapsed_time)
23
+
24
+ def on_interaction(self, target: Dynamic, nature: Nature):
25
+ if self.collected:
26
+ return False
27
+
28
+ if target.type == ObjectType.PLAYER:
29
+ if self.item.on_interaction(target):
30
+ if self.engine.give_item(self.item):
31
+ self.collected = True
32
+ return True
33
+ else:
34
+ self.collected = True
35
+
36
+ return False
37
+
38
+ def draw_self(self, ox: float, oy: float):
39
+ if self.collected:
40
+ return
41
+
42
+ if self.pz != 0:
43
+ self.engine.backend.fill_circle(
44
+ (self.px - ox + 0.5) * self.item.sprite_width,
45
+ (self.py - oy + 0.7) * self.item.sprite_height,
46
+ 0.2875 * self.item.sprite_width,
47
+ BLACK,
48
+ )
49
+
50
+ self.engine.backend.draw_partial_sprite(
51
+ (self.px - ox) * self.item.sprite_width,
52
+ (self.py - oy - self.pz) * self.item.sprite_height,
53
+ self.item.sprite_name,
54
+ self.item.sprite_ox * self.item.sprite_width,
55
+ self.item.sprite_oy * self.item.sprite_height,
56
+ self.item.sprite_width,
57
+ self.item.sprite_height,
58
+ )
59
+
60
+ def _handle_terrain(self, elapsed_time: float):
61
+ """Method is duplicated."""
62
+ e2rm = []
63
+ for effect in self.effects:
64
+ if isinstance(effect, WalkingOnGrass):
65
+ if self.walking_on == Terrain.DEFAULT:
66
+ e2rm.append(effect)
67
+
68
+ for effect in e2rm:
69
+ self.effects.remove(effect)
70
+
71
+ if self.walking_on in [Terrain.GRASS, Terrain.SHALLOW_WATER]:
72
+ # self.attributes.speed_mod = 0.7
73
+ effect_active = False
74
+ for effect in self.effects:
75
+ if isinstance(effect, (WalkingOnGrass, WalkingOnWater)):
76
+ effect_active = True
77
+ effect.renew = True
78
+ break
79
+
80
+ if not effect_active:
81
+ if self.walking_on == Terrain.GRASS:
82
+ eff = WalkingOnGrass(self)
83
+ else:
84
+ eff = WalkingOnWater(self)
85
+ self.effects.append(eff)
86
+ self.engine.scene.add_effect(eff)
87
+ # else:
88
+ # self.attributes.speed_mod = 1.0
@@ -0,0 +1,165 @@
1
+ from typing import List, Optional, Union
2
+
3
+ from ...types.alignment import Alignment
4
+ from ...types.direction import Direction
5
+ from ...types.graphic_state import GraphicState
6
+ from ...types.nature import Nature
7
+ from ...types.object import ObjectType
8
+ from ...util.constants import TILE_HEIGHT, TILE_WIDTH
9
+ from ..animated_sprite import AnimatedSprite
10
+ from ..dynamic import Dynamic
11
+
12
+
13
+ class Switch(Dynamic):
14
+ def __init__(
15
+ self,
16
+ px: float,
17
+ py: float,
18
+ tileset_name: str,
19
+ image_name: str,
20
+ sprite_name: str,
21
+ facing_direction: Direction,
22
+ graphic_state: GraphicState,
23
+ initial_signal=True,
24
+ dyn_id=-1,
25
+ name="Switch",
26
+ ):
27
+ assert graphic_state in [GraphicState.OPEN, GraphicState.CLOSED], (
28
+ f"graphic_state of Switch {name}{dyn_id} must be either 'open'"
29
+ f" or 'closed', but it {graphic_state}"
30
+ )
31
+ super().__init__(name, px, py, dyn_id)
32
+
33
+ self.sprite = AnimatedSprite(
34
+ tileset_name,
35
+ image_name,
36
+ sprite_name,
37
+ graphic_state,
38
+ facing_direction,
39
+ )
40
+
41
+ self.type = ObjectType.SWITCH
42
+ self.alignment = Alignment.NEUTRAL
43
+ self.graphic_state = graphic_state
44
+ self.facing_direction = facing_direction
45
+ self.signal = self.graphic_state == GraphicState.CLOSED
46
+ self.listener_ids: List[int] = []
47
+ self.listeners: List[Dynamic] = []
48
+ self.send_initial_signal = initial_signal
49
+
50
+ # self._gs_map = {False: GraphicState.OPEN, True: GraphicState.CLOSED}
51
+
52
+ def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
53
+ if self.send_initial_signal:
54
+ self.send_signal(self.signal)
55
+ self.send_initial_signal = False
56
+
57
+ self.solid_vs_dyn = self.visible
58
+ self.graphic_state = (
59
+ GraphicState.CLOSED if self.signal else GraphicState.OPEN
60
+ )
61
+ self.sprite.update(
62
+ elapsed_time, self.facing_direction, self.graphic_state
63
+ )
64
+
65
+ def draw_self(self, ox: float, oy: float):
66
+ if not self.visible:
67
+ # print(f"{self.name} is not visible")
68
+ return
69
+ self.sprite.draw_self(self.px - ox, self.py - oy)
70
+
71
+ def on_interaction(self, target: Dynamic, nature: Nature):
72
+ if (
73
+ nature == Nature.TALK
74
+ and target.type == ObjectType.PLAYER
75
+ and self.visible
76
+ ):
77
+ self.state_changed = True
78
+ self.engine.audio.play_sound("switch")
79
+
80
+ elif nature == Nature.WALK and target.type == ObjectType.PROJECTILE:
81
+ if self.signal:
82
+ # Projectiles from the right will activate the switch
83
+ if target.px > self.px and target.vx < 0:
84
+ self.state_changed = True
85
+ else:
86
+ # Projectiles from the left will (de)activate the switch
87
+ if target.px <= self.px and target.vx > 0:
88
+ self.state_changed = True
89
+ if "body" not in target.name:
90
+ self.engine.audio.play_sound("switch")
91
+
92
+ elif nature == Nature.SIGNAL:
93
+ self.visible = False
94
+ return True
95
+
96
+ elif nature == Nature.NO_SIGNAL:
97
+ self.visible = True
98
+ return True
99
+
100
+ if self.state_changed:
101
+ self.signal = not self.signal
102
+ self.send_signal(self.signal)
103
+
104
+ if target.type == ObjectType.PROJECTILE:
105
+ target.kill()
106
+ return True
107
+ return False
108
+
109
+ def send_signal(self, nature: Union[Nature, bool]):
110
+ if isinstance(nature, bool):
111
+ nature = Nature.SIGNAL if nature else Nature.NO_SIGNAL
112
+
113
+ for listener in self.listeners:
114
+ listener.on_interaction(self, nature)
115
+
116
+ if (
117
+ not self.send_initial_signal
118
+ and abs(self.engine.player.px - self.px)
119
+ < (self.engine.backend.render_width // (TILE_WIDTH * 2))
120
+ and abs(self.engine.player.py - self.py)
121
+ < (self.engine.backend.render_height // (TILE_HEIGHT * 2))
122
+ ):
123
+ print(
124
+ (
125
+ self.engine.player.px - self.px,
126
+ self.engine.player.py - self.py,
127
+ ),
128
+ (
129
+ self.engine.backend.render_width // (TILE_WIDTH * 2),
130
+ self.engine.backend.render_height // (TILE_HEIGHT * 2),
131
+ ),
132
+ )
133
+
134
+ @staticmethod
135
+ def load_from_tiled_object(obj, px, py, width, height):
136
+ switch = Switch(
137
+ px=px,
138
+ py=py,
139
+ tileset_name=obj.get_string("tileset_name"),
140
+ image_name=obj.get_string("tileset_name"),
141
+ sprite_name=obj.get_string("sprite_name"),
142
+ graphic_state=GraphicState[
143
+ obj.get_string("graphic_state", "closed").upper()
144
+ ],
145
+ facing_direction=Direction[
146
+ obj.get_string("facing_direction", "south").upper()
147
+ ],
148
+ initial_signal=obj.get_bool("initial_signal", True),
149
+ dyn_id=obj.object_id,
150
+ name=obj.name,
151
+ )
152
+
153
+ switch.sprite.width = int(width * TILE_WIDTH)
154
+ switch.sprite.height = int(height * TILE_HEIGHT)
155
+
156
+ ctr = 1
157
+ while True:
158
+ key = f"output{ctr}"
159
+ listener_id = obj.get_int(key, -1)
160
+ if listener_id < 0:
161
+ break
162
+ switch.listener_ids.append(listener_id)
163
+ ctr += 1
164
+
165
+ return [switch]
@@ -0,0 +1,288 @@
1
+ from __future__ import annotations
2
+ import logging
3
+ from typing import List, Optional
4
+
5
+ from ...scripts.commands.change_map import CommandChangeMap
6
+ from ...scripts.commands.move_map import CommandMoveMap
7
+ from ...scripts.commands.parallel import CommandParallel
8
+ from ...scripts.commands.screen_fade import CommandScreenFade
9
+ from ...scripts.commands.serial import CommandSerial
10
+ from ...scripts.commands.set_facing_direction import CommandSetFacingDirection
11
+ from ...types.direction import Direction
12
+ from ...types.graphic_state import GraphicState
13
+ from ...types.nature import Nature
14
+ from ...types.object import ObjectType
15
+ from ...util.colors import RED
16
+ from ...util.constants import TILE_HEIGHT, TILE_WIDTH
17
+ from ..animated_sprite import AnimatedSprite
18
+ from ..dynamic import Dynamic
19
+
20
+ LOG = logging.getLogger(__name__)
21
+
22
+
23
+ class Teleport(Dynamic):
24
+ def __init__(
25
+ self,
26
+ px: float,
27
+ py: float,
28
+ tileset_name: str,
29
+ image_name: str,
30
+ sprite_name: str,
31
+ facing_direction: Direction,
32
+ graphic_state: GraphicState,
33
+ dst_map_name: str,
34
+ dst_px: float,
35
+ dst_py: float,
36
+ direction: Direction,
37
+ invert_exit_direction: bool = False,
38
+ relative: bool = False,
39
+ sliding: bool = False,
40
+ vertical: bool = False,
41
+ dyn_id: int = -1,
42
+ name="Teleport",
43
+ ):
44
+ super().__init__(name, px, py, dyn_id)
45
+
46
+ self.sprite = AnimatedSprite(
47
+ tileset_name, image_name, sprite_name, graphic_state, facing_direction
48
+ )
49
+
50
+ self.type = ObjectType.TELEPORT
51
+ self.graphic_state = graphic_state
52
+ self.facing_direction = facing_direction
53
+ self.solid_vs_dyn = False
54
+ self.solid_vs_map = False
55
+
56
+ self.dst_px: float = dst_px
57
+ self.dst_py: float = dst_py
58
+ self.dst_map_name: str = dst_map_name
59
+ self.has_sprite = self.sprite.name != ""
60
+ self.teleport_direction: Direction = direction
61
+
62
+ self.visible = True
63
+ self.invert_exit_direction = invert_exit_direction
64
+ self.relative = relative
65
+ self.sliding = sliding
66
+ self.vertical = vertical
67
+ self.triggered = False
68
+ self.sfx_on_trigger: str = ""
69
+
70
+ def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
71
+ self.sprite.update(elapsed_time, self.facing_direction, self.graphic_state)
72
+
73
+ def on_interaction(self, target: Dynamic, nature: Nature):
74
+ if nature == Nature.SIGNAL:
75
+ self.visible = True
76
+ return True
77
+ if nature == Nature.NO_SIGNAL:
78
+ self.visible = False
79
+ return True
80
+
81
+ if self.has_sprite and not self.visible:
82
+ return False
83
+
84
+ if (
85
+ nature == Nature.WALK
86
+ and target.type == ObjectType.PLAYER
87
+ and not self.engine.teleport_triggered
88
+ ):
89
+ self.engine.teleport_triggered = True
90
+ dst_px = self.dst_px
91
+ dst_py = self.dst_py
92
+ dst_vx = 0
93
+ dst_vy = 0
94
+
95
+ dst_vx, dst_vy = Direction.to_velocity(self.teleport_direction)
96
+
97
+ # if self.relative:
98
+ # if self.vertical:
99
+ # dst_py += target.py
100
+ # else:
101
+ # dst_px += target.px
102
+
103
+ if self.sliding:
104
+ if dst_vx != 0:
105
+ dst_py = target.py
106
+ elif dst_vy != 0:
107
+ dst_px = target.px
108
+
109
+ self.engine.script.add_command(
110
+ CommandMoveMap(
111
+ self.dst_map_name,
112
+ target,
113
+ dst_px,
114
+ dst_py,
115
+ dst_vx,
116
+ dst_vy,
117
+ )
118
+ )
119
+ else:
120
+ if self.triggered:
121
+ return False
122
+
123
+ new_direction = target.facing_direction
124
+ if self.invert_exit_direction:
125
+ new_direction = Direction((target.facing_direction.value + 2) % 4)
126
+
127
+ self.engine.script.add_command(
128
+ CommandSerial(
129
+ [
130
+ CommandScreenFade(),
131
+ CommandParallel(
132
+ [
133
+ CommandChangeMap(self.dst_map_name, dst_px, dst_py),
134
+ CommandSetFacingDirection(target, new_direction),
135
+ CommandScreenFade(fadein=True),
136
+ ]
137
+ ),
138
+ ],
139
+ )
140
+ )
141
+ if self.sfx_on_trigger:
142
+ self.engine.audio.play_sound(self.sfx_on_trigger)
143
+
144
+ self.triggered = True
145
+ return True
146
+
147
+ return False
148
+
149
+ def draw_self(self, ox: float, oy: float):
150
+ if not self.visible:
151
+ self.engine.backend.draw_circle(
152
+ (self.px + 0.5 - ox) * TILE_WIDTH,
153
+ (self.py + 0.5 - oy) * TILE_HEIGHT,
154
+ 0.5 * TILE_WIDTH,
155
+ RED,
156
+ )
157
+ return
158
+
159
+ if self.has_sprite:
160
+ self.sprite.draw_self(self.px - ox, self.py - oy)
161
+
162
+ @staticmethod
163
+ def load_from_tiled_object(obj, px, py, width, height) -> List[Teleport]:
164
+ sprite_name = obj.get_string("sprite_name")
165
+ tileset_name = obj.get_string("tileset_name")
166
+ image_name = obj.get_string("tileset_name")
167
+ graphic_state = GraphicState[obj.get_string("graphic_state", "closed").upper()]
168
+ facing_direction = Direction[obj.get_string("facing_direction", "south").upper()]
169
+ target_map = obj.get_string("target_map", "map1_c1")
170
+ invert_exit_direction = obj.get_bool("invert_exit_direction")
171
+ relative = obj.get_bool("relative", False)
172
+ sliding = obj.get_bool("sliding", False)
173
+ vertical = obj.get_bool("vertical", False)
174
+ layer = obj.get_int("layer", 1)
175
+ target_px = obj.get_float("target_px")
176
+ target_py = obj.get_float("target_py")
177
+ direction = Direction[obj.get_string("direction", "south").upper()]
178
+ teleports = []
179
+ if width > height and int(width) > 1:
180
+ num_horizontal = int(width)
181
+ for idx in range(num_horizontal):
182
+ from_px = px + idx
183
+ from_py = py
184
+ to_px = target_px + idx
185
+ to_py = target_py
186
+
187
+ LOG.debug(
188
+ "Adding a teleport at (%f, %f) to map %s (%f, %f).",
189
+ from_px,
190
+ from_py,
191
+ target_map,
192
+ to_px,
193
+ to_py,
194
+ )
195
+ teleports.append(
196
+ Teleport(
197
+ px=from_px,
198
+ py=from_py,
199
+ tileset_name=tileset_name,
200
+ image_name=image_name,
201
+ sprite_name=sprite_name,
202
+ graphic_state=graphic_state,
203
+ facing_direction=facing_direction,
204
+ dst_map_name=target_map,
205
+ dst_px=to_px,
206
+ dst_py=to_py,
207
+ direction=direction,
208
+ invert_exit_direction=invert_exit_direction,
209
+ relative=relative,
210
+ sliding=sliding,
211
+ vertical=False,
212
+ dyn_id=obj.object_id,
213
+ name=obj.name,
214
+ )
215
+ )
216
+ teleports[-1].layer = layer
217
+ elif height > width and int(height) > 1:
218
+ num_vertical = int(height)
219
+ for idx in range(num_vertical):
220
+ from_px = px
221
+ from_py = py + idx
222
+ to_px = target_px
223
+ to_py = target_py if relative else from_py
224
+
225
+ LOG.debug(
226
+ "Adding a teleport at (%f, %f) to map %s (%f, %f).",
227
+ from_px,
228
+ from_py,
229
+ target_map,
230
+ to_px,
231
+ to_py,
232
+ )
233
+ teleports.append(
234
+ Teleport(
235
+ px=from_px,
236
+ py=from_py,
237
+ tileset_name=tileset_name,
238
+ image_name=image_name,
239
+ sprite_name=sprite_name,
240
+ graphic_state=graphic_state,
241
+ facing_direction=facing_direction,
242
+ dst_map_name=target_map,
243
+ dst_px=to_px,
244
+ dst_py=to_py,
245
+ direction=direction,
246
+ invert_exit_direction=invert_exit_direction,
247
+ relative=relative,
248
+ sliding=sliding,
249
+ vertical=True,
250
+ dyn_id=obj.object_id,
251
+ name=obj.name,
252
+ )
253
+ )
254
+ teleports[-1].layer = layer
255
+ else:
256
+ LOG.debug(
257
+ "Adding a teleport at (%f, %f) to map %s (%f, %f).",
258
+ px,
259
+ py,
260
+ target_map,
261
+ target_px,
262
+ target_py,
263
+ )
264
+ teleports.append(
265
+ Teleport(
266
+ px=px,
267
+ py=py,
268
+ tileset_name=tileset_name,
269
+ image_name=image_name,
270
+ sprite_name=sprite_name,
271
+ graphic_state=graphic_state,
272
+ facing_direction=facing_direction,
273
+ dst_map_name=target_map,
274
+ dst_px=target_px,
275
+ dst_py=target_py,
276
+ direction=direction,
277
+ invert_exit_direction=invert_exit_direction,
278
+ relative=relative,
279
+ sliding=sliding,
280
+ vertical=vertical,
281
+ dyn_id=obj.object_id,
282
+ name=obj.name,
283
+ )
284
+ )
285
+ teleports[-1].sfx_on_trigger = obj.get_string("sfx_name")
286
+ teleports[-1].layer = layer
287
+
288
+ return teleports
mima/scene_engine.py ADDED
@@ -0,0 +1,79 @@
1
+ from typing import TYPE_CHECKING, Dict, List, Optional, Union
2
+
3
+ from .engine import MimaEngine
4
+ from .states.game_state import GameState
5
+ from .types.keys import Key as K
6
+ from .types.nature import Nature
7
+ from .view.scene import Scene
8
+ from .types.mode import Mode
9
+
10
+
11
+ class MimaSceneEngine(MimaEngine):
12
+ def __init__(
13
+ self, init_file: str, platform: str = "PC", caption: str = "MimaEngine"
14
+ ):
15
+ super().__init__(init_file, platform, caption)
16
+
17
+ self.scene_stack: List[str] = []
18
+ self._scenes: Dict[str, Scene] = {}
19
+ self._current_scene: Scene
20
+
21
+ self.all_games: Dict[str, GameState] = {}
22
+ self.current_game: str = ""
23
+ self.save_timer_reset = 1.0
24
+ self._save_timer = self.save_timer_reset
25
+ self.teleport_triggered: bool = False
26
+ self.dialog_active: bool = False
27
+
28
+ def on_user_create(self):
29
+ return True
30
+
31
+ def on_user_update(self, elapsed_time: float):
32
+ self.audio.update(elapsed_time)
33
+ self._current_scene = self._scenes[self.scene_stack[-1]]
34
+
35
+ # self._current_scene = self.mode.name.lower()
36
+
37
+ self._save_timer -= elapsed_time
38
+ if self._save_timer <= 0.0:
39
+ self._save_timer += self.save_timer_reset
40
+ if self._current_scene.autosave:
41
+ for quest in self.quests:
42
+ for obj in self.scene.dynamics:
43
+ quest.on_interaction(
44
+ self.scene.dynamics, obj, Nature.SAVE
45
+ )
46
+ quest.save_state()
47
+ if self.keys.new_key_press(K.SELECT):
48
+ self.game_state.save_to_disk()
49
+
50
+ self.scene.update(elapsed_time)
51
+
52
+ return True
53
+
54
+ def change_map(self, map_name: str, px: float, py: float):
55
+ type_string = (
56
+ self.get_map(map_name).get_string("type", "local").upper()
57
+ )
58
+ if type_string == "WORLD":
59
+ type_string = "WORLD_MAP"
60
+ if type_string == "LOCAL":
61
+ type_string = "LOCAL_MAP"
62
+ mode = Mode[type_string]
63
+
64
+ self.scene_stack.append(mode)
65
+ self._scenes[self.scene_stack[-1]].change_map(map_name, px, py)
66
+ # print(self.scene_stack)
67
+
68
+ @property
69
+ def scene(self) -> Scene:
70
+ # return self._scenes[self._current_scene]
71
+ return self._current_scene
72
+
73
+ @property
74
+ def previous_scene(self) -> Scene:
75
+ return self._scenes[self.scene_stack[-2]]
76
+
77
+ @property
78
+ def game_state(self) -> GameState:
79
+ return self.all_games[self.current_game]
@@ -0,0 +1,2 @@
1
+ from .command import Command
2
+ from .script_processor import ScriptProcessor
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from ..engine import MimaEngine
7
+
8
+
9
+ class Command:
10
+ engine: MimaEngine
11
+
12
+ def __init__(self):
13
+ self.started: bool = False
14
+ self.completed: bool = False
15
+ self.uninterruptible: bool = False
16
+
17
+ def start(self):
18
+ pass
19
+
20
+ def update(self, elapsed_time: float):
21
+ pass
22
+
23
+ def finalize(self):
24
+ pass
File without changes
@@ -0,0 +1,19 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from ..command import Command
6
+
7
+ if TYPE_CHECKING:
8
+ from ...states.quest import Quest
9
+
10
+
11
+ class CommandAddQuest(Command):
12
+ def __init__(self, quest: Quest):
13
+ super().__init__()
14
+
15
+ self._quest: Quest = quest
16
+
17
+ def start(self):
18
+ self.engine.add_quest(self._quest)
19
+ self.completed = True
@@ -0,0 +1,15 @@
1
+ from ..command import Command
2
+
3
+
4
+ class CommandChangeMap(Command):
5
+ def __init__(self, map_name: str, spawn_px: float, spawn_py):
6
+ super().__init__()
7
+
8
+ self._map_name: str = map_name
9
+ self._spawn_px: float = spawn_px
10
+ self._spawn_py: float = spawn_py
11
+
12
+ def start(self):
13
+ self.engine.scene_stack.pop()
14
+ self.engine.change_map(self._map_name, self._spawn_px, self._spawn_py)
15
+ self.completed = True
@@ -0,0 +1,8 @@
1
+ from ..command import Command
2
+
3
+
4
+ class CommandCloseDialog(Command):
5
+ def start(self):
6
+ self.engine.dialog_active = False
7
+ self.engine.exit_dialog_active = False
8
+ self.completed = True