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.
Files changed (153) hide show
  1. mima/__init__.py +4 -0
  2. mima/backend/__init__.py +1 -0
  3. mima/backend/pygame_assets.py +401 -0
  4. mima/backend/pygame_audio.py +78 -0
  5. mima/backend/pygame_backend.py +603 -0
  6. mima/backend/pygame_camera.py +63 -0
  7. mima/backend/pygame_events.py +695 -0
  8. mima/backend/touch_control_scheme_a.py +126 -0
  9. mima/backend/touch_control_scheme_b.py +132 -0
  10. mima/core/__init__.py +0 -0
  11. mima/core/collision.py +325 -0
  12. mima/core/database.py +58 -0
  13. mima/core/engine.py +367 -0
  14. mima/core/mode_engine.py +81 -0
  15. mima/core/scene_engine.py +81 -0
  16. mima/integrated/__init__.py +0 -0
  17. mima/integrated/entity.py +183 -0
  18. mima/integrated/layered_map.py +351 -0
  19. mima/integrated/sprite.py +156 -0
  20. mima/layered/__init__.py +0 -0
  21. mima/layered/assets.py +56 -0
  22. mima/layered/scene.py +415 -0
  23. mima/layered/shape.py +99 -0
  24. mima/layered/shaped_sprite.py +78 -0
  25. mima/layered/virtual_input.py +302 -0
  26. mima/maps/__init__.py +0 -0
  27. mima/maps/template.py +71 -0
  28. mima/maps/tile.py +20 -0
  29. mima/maps/tile_animation.py +7 -0
  30. mima/maps/tile_info.py +10 -0
  31. mima/maps/tile_layer.py +52 -0
  32. mima/maps/tiled/__init__.py +0 -0
  33. mima/maps/tiled/tiled_layer.py +48 -0
  34. mima/maps/tiled/tiled_map.py +95 -0
  35. mima/maps/tiled/tiled_object.py +79 -0
  36. mima/maps/tiled/tiled_objectgroup.py +25 -0
  37. mima/maps/tiled/tiled_template.py +49 -0
  38. mima/maps/tiled/tiled_tile.py +90 -0
  39. mima/maps/tiled/tiled_tileset.py +51 -0
  40. mima/maps/tilemap.py +216 -0
  41. mima/maps/tileset.py +39 -0
  42. mima/maps/tileset_info.py +9 -0
  43. mima/maps/transition_map.py +146 -0
  44. mima/objects/__init__.py +0 -0
  45. mima/objects/animated_sprite.py +217 -0
  46. mima/objects/attribute_effect.py +26 -0
  47. mima/objects/attributes.py +126 -0
  48. mima/objects/creature.py +384 -0
  49. mima/objects/dynamic.py +206 -0
  50. mima/objects/effects/__init__.py +0 -0
  51. mima/objects/effects/colorize_screen.py +60 -0
  52. mima/objects/effects/debug_box.py +133 -0
  53. mima/objects/effects/light.py +103 -0
  54. mima/objects/effects/show_sprite.py +50 -0
  55. mima/objects/effects/walking_on_grass.py +70 -0
  56. mima/objects/effects/walking_on_water.py +57 -0
  57. mima/objects/loader.py +111 -0
  58. mima/objects/projectile.py +111 -0
  59. mima/objects/sprite.py +116 -0
  60. mima/objects/world/__init__.py +0 -0
  61. mima/objects/world/color_gate.py +67 -0
  62. mima/objects/world/color_switch.py +101 -0
  63. mima/objects/world/container.py +175 -0
  64. mima/objects/world/floor_switch.py +109 -0
  65. mima/objects/world/gate.py +178 -0
  66. mima/objects/world/light_source.py +121 -0
  67. mima/objects/world/logic_gate.py +157 -0
  68. mima/objects/world/movable.py +399 -0
  69. mima/objects/world/oneway.py +195 -0
  70. mima/objects/world/pickup.py +157 -0
  71. mima/objects/world/switch.py +179 -0
  72. mima/objects/world/teleport.py +308 -0
  73. mima/py.typed +0 -0
  74. mima/scripts/__init__.py +2 -0
  75. mima/scripts/command.py +38 -0
  76. mima/scripts/commands/__init__.py +0 -0
  77. mima/scripts/commands/add_quest.py +19 -0
  78. mima/scripts/commands/change_map.py +34 -0
  79. mima/scripts/commands/close_dialog.py +9 -0
  80. mima/scripts/commands/equip_weapon.py +23 -0
  81. mima/scripts/commands/give_item.py +26 -0
  82. mima/scripts/commands/give_resource.py +51 -0
  83. mima/scripts/commands/move_map.py +152 -0
  84. mima/scripts/commands/move_to.py +49 -0
  85. mima/scripts/commands/oneway_move.py +58 -0
  86. mima/scripts/commands/parallel.py +66 -0
  87. mima/scripts/commands/play_sound.py +13 -0
  88. mima/scripts/commands/present_item.py +53 -0
  89. mima/scripts/commands/progress_quest.py +12 -0
  90. mima/scripts/commands/quit_game.py +8 -0
  91. mima/scripts/commands/save_game.py +14 -0
  92. mima/scripts/commands/screen_fade.py +83 -0
  93. mima/scripts/commands/serial.py +69 -0
  94. mima/scripts/commands/set_facing_direction.py +21 -0
  95. mima/scripts/commands/set_spawn_map.py +17 -0
  96. mima/scripts/commands/show_choices.py +52 -0
  97. mima/scripts/commands/show_dialog.py +118 -0
  98. mima/scripts/commands/take_coins.py +23 -0
  99. mima/scripts/script_processor.py +61 -0
  100. mima/standalone/__init__.py +0 -0
  101. mima/standalone/camera.py +153 -0
  102. mima/standalone/geometry.py +1318 -0
  103. mima/standalone/multicolumn_list.py +54 -0
  104. mima/standalone/pixel_font.py +84 -0
  105. mima/standalone/scripting.py +145 -0
  106. mima/standalone/spatial.py +186 -0
  107. mima/standalone/sprite.py +158 -0
  108. mima/standalone/tiled_map.py +1247 -0
  109. mima/standalone/transformed_view.py +433 -0
  110. mima/standalone/user_input.py +563 -0
  111. mima/states/__init__.py +0 -0
  112. mima/states/game_state.py +189 -0
  113. mima/states/memory.py +28 -0
  114. mima/states/quest.py +71 -0
  115. mima/types/__init__.py +0 -0
  116. mima/types/alignment.py +7 -0
  117. mima/types/blend.py +8 -0
  118. mima/types/damage.py +42 -0
  119. mima/types/direction.py +44 -0
  120. mima/types/gate_color.py +7 -0
  121. mima/types/graphic_state.py +23 -0
  122. mima/types/keys.py +64 -0
  123. mima/types/mode.py +9 -0
  124. mima/types/nature.py +12 -0
  125. mima/types/object.py +22 -0
  126. mima/types/player.py +9 -0
  127. mima/types/position.py +13 -0
  128. mima/types/start.py +7 -0
  129. mima/types/terrain.py +9 -0
  130. mima/types/tile_collision.py +11 -0
  131. mima/types/weapon_slot.py +6 -0
  132. mima/types/window.py +44 -0
  133. mima/usables/__init__.py +0 -0
  134. mima/usables/item.py +51 -0
  135. mima/usables/weapon.py +68 -0
  136. mima/util/__init__.py +1 -0
  137. mima/util/colors.py +50 -0
  138. mima/util/constants.py +55 -0
  139. mima/util/functions.py +38 -0
  140. mima/util/input_defaults.py +170 -0
  141. mima/util/logging.py +51 -0
  142. mima/util/property.py +8 -0
  143. mima/util/runtime_config.py +327 -0
  144. mima/util/trading_item.py +23 -0
  145. mima/view/__init__.py +0 -0
  146. mima/view/camera.py +192 -0
  147. mima/view/mima_mode.py +618 -0
  148. mima/view/mima_scene.py +231 -0
  149. mima/view/mima_view.py +12 -0
  150. mima/view/mima_window.py +244 -0
  151. mima_engine-0.4.0.dist-info/METADATA +47 -0
  152. mima_engine-0.4.0.dist-info/RECORD +153 -0
  153. mima_engine-0.4.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,157 @@
1
+ from typing import Optional
2
+
3
+ from ...maps.tilemap import Tilemap
4
+ from ...objects.dynamic import Dynamic
5
+ from ...types.direction import Direction
6
+ from ...types.graphic_state import GraphicState
7
+ from ...types.nature import Nature
8
+ from ...types.object import ObjectType
9
+ from ...types.terrain import Terrain
10
+ from ...usables.item import Item
11
+ from ...util.colors import BLACK
12
+ from ..animated_sprite import AnimatedSprite
13
+ from ..effects.walking_on_grass import WalkingOnGrass
14
+ from ..effects.walking_on_water import WalkingOnWater
15
+
16
+
17
+ class Pickup(Dynamic):
18
+ def __init__(
19
+ self,
20
+ px: float,
21
+ py: float,
22
+ item: Item,
23
+ *,
24
+ tilemap: Optional[Tilemap] = None,
25
+ dyn_id=0,
26
+ ):
27
+ super().__init__(
28
+ px,
29
+ py,
30
+ f"Pickup({item.name})",
31
+ sprite_name=item.sprite_name,
32
+ tilemap=tilemap,
33
+ dyn_id=dyn_id,
34
+ )
35
+ self.type: ObjectType = ObjectType.PICKUP
36
+ self.item = item
37
+ # if not sprite_name:
38
+ # sprite_name = self.item.sprite_name
39
+
40
+ self.collected = False
41
+ self.solid_vs_dyn = False
42
+ self.moves_on_collision = True
43
+ # self.sprite = AnimatedSprite(
44
+ # self.item.tileset_name,
45
+ # self.item.image_name,
46
+ # self.item.sprite_name,
47
+ # graphic_state,
48
+ # facing_direction,
49
+ # )
50
+
51
+ def update(self, elapsed_time: float, target=None):
52
+ if self.collected:
53
+ self.kill()
54
+ else:
55
+ self._handle_terrain(elapsed_time)
56
+ self.sprite.update(
57
+ elapsed_time, self.facing_direction, self.graphic_state
58
+ )
59
+
60
+ def on_interaction(self, target: Dynamic, nature: Nature):
61
+ if self.collected:
62
+ return False
63
+
64
+ pl = target.get_player()
65
+ if pl.value > 0:
66
+ if self.item.on_interaction(target):
67
+ if self.engine.give_item(self.item, pl):
68
+ self.collected = True
69
+ return True
70
+ else:
71
+ self.collected = True
72
+
73
+ return False
74
+
75
+ def draw_self(
76
+ self,
77
+ ox: float,
78
+ oy: float,
79
+ camera_name: str = "display",
80
+ draw_to_ui: bool = False,
81
+ ):
82
+ if self.collected:
83
+ return
84
+
85
+ if self.pz != 0:
86
+
87
+ # print("Draw item circle")
88
+ self.engine.backend.fill_circle(
89
+ (self.px - ox + 0.5) * self.sprite.width,
90
+ (self.py - oy + 0.7) * self.sprite.height,
91
+ 0.2875 * self.sprite.width,
92
+ BLACK,
93
+ camera_name,
94
+ )
95
+ self.sprite.draw_self(
96
+ self.px - ox,
97
+ self.py - oy - self.pz,
98
+ camera_name,
99
+ draw_to_ui=draw_to_ui,
100
+ )
101
+ # self.engine.backend.draw_partial_sprite(
102
+ # (self.px - ox) * self.item.sprite_width,
103
+ # (self.py - oy - self.pz) * self.item.sprite_height,
104
+ # self.item.sprite_name,
105
+ # self.item.sprite_ox * self.item.sprite_width,
106
+ # self.item.sprite_oy * self.item.sprite_height,
107
+ # self.item.sprite_width,
108
+ # self.item.sprite_height,
109
+ # camera_name,
110
+ # )
111
+
112
+ def _handle_terrain(self, elapsed_time: float):
113
+ """Method is duplicated."""
114
+ e2rm = []
115
+ for effect in self.effects:
116
+ if isinstance(effect, WalkingOnGrass):
117
+ if self.walking_on == Terrain.DEFAULT:
118
+ e2rm.append(effect)
119
+
120
+ for effect in e2rm:
121
+ self.effects.remove(effect)
122
+
123
+ if self.walking_on in [Terrain.GRASS, Terrain.SHALLOW_WATER]:
124
+ # self.attributes.speed_mod = 0.7
125
+ effect_active = False
126
+ for effect in self.effects:
127
+ if isinstance(effect, (WalkingOnGrass, WalkingOnWater)):
128
+ effect_active = True
129
+ effect.renew = True
130
+ break
131
+
132
+ if not effect_active:
133
+ if self.walking_on == Terrain.GRASS:
134
+ eff = WalkingOnGrass(self)
135
+ else:
136
+ eff = WalkingOnWater(self)
137
+ self.effects.append(eff)
138
+ self.engine.get_view().add_effect(eff, self.tilemap.name)
139
+ # else:
140
+ # self.attributes.speed_mod = 1.0
141
+
142
+ @staticmethod
143
+ def load_from_tiled_object(obj, px, py, width, height, tilemap):
144
+ item = Pickup.engine.get_item(obj.get_string("usable_id"))
145
+
146
+ pickup = Pickup(
147
+ px,
148
+ py,
149
+ item,
150
+ tilemap=tilemap,
151
+ dyn_id=obj.object_id,
152
+ )
153
+
154
+ # pickup.sprite.width = int(width * Pickup.engine.rtc.tile_width)
155
+ # pickup.sprite.height = int(height * Pickup.engine.rtc.tile_height)
156
+
157
+ return [pickup]
@@ -0,0 +1,179 @@
1
+ from typing import List, Optional, Union
2
+
3
+ from ...maps.tilemap import Tilemap
4
+ from ...types.alignment import Alignment
5
+ from ...types.direction import Direction
6
+ from ...types.graphic_state import GraphicState
7
+ from ...types.nature import Nature
8
+ from ...types.object import ObjectType
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
+ name="Switch",
19
+ *,
20
+ sprite_name: str = "",
21
+ tilemap: Optional[Tilemap] = None,
22
+ dyn_id=0,
23
+ graphic_state: GraphicState = GraphicState.OPEN,
24
+ initial_signal=True,
25
+ ):
26
+ if graphic_state not in [GraphicState.OPEN, GraphicState.CLOSED]:
27
+ msg = (
28
+ f"graphic_state of Switch {name}{dyn_id} must be either "
29
+ f" 'open' or 'closed', but it is {graphic_state.name}"
30
+ )
31
+ raise ValueError(msg)
32
+
33
+ super().__init__(
34
+ px,
35
+ py,
36
+ name,
37
+ tilemap=tilemap,
38
+ sprite_name=sprite_name,
39
+ dyn_id=dyn_id,
40
+ )
41
+
42
+ self.type = ObjectType.SWITCH
43
+ self.alignment = Alignment.NEUTRAL
44
+ self.graphic_state = graphic_state
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
+ self.cooldown = 0.0
50
+ self.cooldown_reset = 0.8
51
+
52
+ # self._gs_map = {False: GraphicState.OPEN, True: GraphicState.CLOSED}
53
+
54
+ def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
55
+ if self.cooldown > 0.0:
56
+ self.cooldown -= elapsed_time
57
+
58
+ if self.send_initial_signal:
59
+ self.send_signal(self.signal)
60
+ self.send_initial_signal = False
61
+
62
+ self.solid_vs_dyn = self.visible
63
+ self.graphic_state = (
64
+ GraphicState.CLOSED if self.signal else GraphicState.OPEN
65
+ )
66
+ self.sprite.update(
67
+ elapsed_time, self.facing_direction, self.graphic_state
68
+ )
69
+
70
+ def draw_self(self, ox: float, oy: float, camera_name: str = "display"):
71
+ if not self.visible:
72
+ # print(f"{self.name} is not visible")
73
+ return
74
+ self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
75
+
76
+ def on_interaction(self, target: Dynamic, nature: Nature):
77
+ # if target.is_player().value > 0:
78
+ # print(f"{target.is_player()} talked to me({self.name})")
79
+ if self.cooldown > 0.0:
80
+ return False
81
+
82
+ if (
83
+ nature == Nature.TALK
84
+ and target.type == ObjectType.PLAYER
85
+ and self.visible
86
+ ):
87
+ self.state_changed = True
88
+ self.engine.audio.play_sound("switch", 0.2)
89
+ self.cooldown = self.cooldown_reset
90
+ # print("Player talked")
91
+
92
+ elif nature == Nature.WALK and target.type == ObjectType.PROJECTILE:
93
+ if self.signal:
94
+ # Projectiles from the right will activate the switch
95
+ if target.px > self.px and target.vx < 0:
96
+ self.state_changed = True
97
+ if "body" not in target.name:
98
+ self.engine.audio.play_sound("switch", 0.2)
99
+ self.cooldown = self.cooldown_reset
100
+ else:
101
+ # Projectiles from the left will (de)activate the switch
102
+ if (
103
+ target.px <= self.px and target.vx > 0
104
+ ): # Sword does not activate because vx=0
105
+ self.state_changed = True
106
+ if "body" not in target.name:
107
+ self.engine.audio.play_sound("switch", 0.2)
108
+ self.cooldown = self.cooldown_reset
109
+
110
+ elif nature == Nature.SIGNAL:
111
+ self.visible = False
112
+ return True
113
+
114
+ elif nature == Nature.NO_SIGNAL:
115
+ self.visible = True
116
+ return True
117
+
118
+ if self.state_changed:
119
+ self.signal = not self.signal
120
+ self.send_signal(self.signal)
121
+
122
+ if target.type == ObjectType.PROJECTILE:
123
+ target.kill()
124
+ return True
125
+ return False
126
+
127
+ def send_signal(self, nature: Union[Nature, bool]):
128
+ if isinstance(nature, bool):
129
+ nature = Nature.SIGNAL if nature else Nature.NO_SIGNAL
130
+
131
+ for listener in self.listeners:
132
+ listener.on_interaction(self, nature)
133
+
134
+ # if (
135
+ # not self.send_initial_signal
136
+ # and abs(self.engine.player.px - self.px)
137
+ # < (self.engine.backend.render_width // (TILE_WIDTH * 2))
138
+ # and abs(self.engine.player.py - self.py)
139
+ # < (self.engine.backend.render_height // (TILE_HEIGHT * 2))
140
+ # ):
141
+ # print(
142
+ # (
143
+ # self.engine.player.px - self.px,
144
+ # self.engine.player.py - self.py,
145
+ # ),
146
+ # (
147
+ # self.engine.backend.render_width // (TILE_WIDTH * 2),
148
+ # self.engine.backend.render_height // (TILE_HEIGHT * 2),
149
+ # ),
150
+ # )
151
+
152
+ @staticmethod
153
+ def load_from_tiled_object(obj, px, py, width, height, tilemap):
154
+ switch = Switch(
155
+ px=px,
156
+ py=py,
157
+ name=obj.name,
158
+ sprite_name=obj.get_string("sprite_name"),
159
+ tilemap=tilemap,
160
+ dyn_id=obj.object_id,
161
+ graphic_state=GraphicState[
162
+ obj.get_string("graphic_state", "closed").upper()
163
+ ],
164
+ initial_signal=obj.get_bool("initial_signal", True),
165
+ )
166
+
167
+ # switch.sprite.width = int(width * Switch.engine.rtc.tile_width)
168
+ # switch.sprite.height = int(height * Switch.engine.rtc.tile_height)
169
+
170
+ ctr = 1
171
+ while True:
172
+ key = f"output{ctr}"
173
+ listener_id = obj.get_int(key, -1)
174
+ if listener_id < 0:
175
+ break
176
+ switch.listener_ids.append(listener_id)
177
+ ctr += 1
178
+
179
+ return [switch]
@@ -0,0 +1,308 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from typing import List, Optional
5
+
6
+ from ...maps.tilemap import Tilemap
7
+ from ...scripts.commands.change_map import CommandChangeMap
8
+ from ...scripts.commands.move_map import CommandMoveMap
9
+ from ...scripts.commands.parallel import CommandParallel
10
+ from ...scripts.commands.screen_fade import CommandScreenFade
11
+ from ...scripts.commands.serial import CommandSerial
12
+ from ...scripts.commands.set_facing_direction import CommandSetFacingDirection
13
+ from ...types.direction import Direction
14
+ from ...types.graphic_state import GraphicState
15
+ from ...types.nature import Nature
16
+ from ...types.object import ObjectType
17
+ from ...types.player import Player
18
+ from ..animated_sprite import AnimatedSprite
19
+ from ..dynamic import Dynamic
20
+
21
+ LOG = logging.getLogger(__name__)
22
+
23
+
24
+ class Teleport(Dynamic):
25
+ def __init__(
26
+ self,
27
+ px: float,
28
+ py: float,
29
+ name="Teleport",
30
+ *,
31
+ sprite_name: str = "str",
32
+ tilemap: Optional[Tilemap] = None,
33
+ dyn_id: int = -1,
34
+ facing_direction: Direction,
35
+ graphic_state: GraphicState,
36
+ dst_map_name: str,
37
+ dst_px: float,
38
+ dst_py: float,
39
+ direction: Direction,
40
+ invert_exit_direction: bool = False,
41
+ relative: bool = False,
42
+ sliding: bool = False,
43
+ vertical: bool = False,
44
+ ):
45
+ super().__init__(
46
+ px,
47
+ py,
48
+ name,
49
+ sprite_name=sprite_name,
50
+ tilemap=tilemap,
51
+ dyn_id=dyn_id,
52
+ )
53
+
54
+ # self.sprite = AnimatedSprite(
55
+ # tileset_name,
56
+ # image_name,
57
+ # sprite_name,
58
+ # graphic_state,
59
+ # facing_direction,
60
+ # )
61
+
62
+ self.type = ObjectType.TELEPORT
63
+ self.graphic_state = graphic_state
64
+ self.facing_direction = facing_direction
65
+ self.solid_vs_dyn = False
66
+ self.solid_vs_map = False
67
+
68
+ self.dst_px: float = dst_px
69
+ self.dst_py: float = dst_py
70
+ self.dst_map_name: str = dst_map_name
71
+ self.has_sprite = self.sprite.name != ""
72
+ self.teleport_direction: Direction = direction
73
+
74
+ self.visible = True
75
+ self.invert_exit_direction = invert_exit_direction
76
+ self.relative = relative
77
+ self.sliding = sliding
78
+ self.vertical = vertical
79
+ self.triggered = False
80
+ self.sfx_on_trigger: str = ""
81
+
82
+ def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
83
+ self.triggered = False
84
+ self.sprite.update(
85
+ elapsed_time, self.facing_direction, self.graphic_state
86
+ )
87
+
88
+ def on_interaction(self, target: Dynamic, nature: Nature):
89
+ if nature == Nature.SIGNAL:
90
+ self.visible = True
91
+ return True
92
+ if nature == Nature.NO_SIGNAL:
93
+ self.visible = False
94
+ return True
95
+
96
+ if self.has_sprite and not self.visible:
97
+ return False
98
+
99
+ pt = target.get_player()
100
+ if (
101
+ nature == Nature.WALK
102
+ and pt != Player.P0
103
+ and not self.engine.is_teleport_active(pt)
104
+ ):
105
+ self.engine.trigger_teleport(True, pt)
106
+ dst_px = self.dst_px
107
+ dst_py = self.dst_py
108
+ dst_vx = 0
109
+ dst_vy = 0
110
+
111
+ dst_vx, dst_vy = Direction.to_velocity(self.teleport_direction)
112
+ # self.sliding = False
113
+ if self.sliding:
114
+ if dst_vx != 0:
115
+ dst_py = target.py
116
+ elif dst_vy != 0:
117
+ dst_px = target.px
118
+
119
+ # self.engine.script.add_command(
120
+ # CommandMoveMap(
121
+ # new_map_name=self.dst_map_name,
122
+ # obj=target,
123
+ # target_px=dst_px,
124
+ # target_py=dst_py,
125
+ # vx=dst_vx,
126
+ # vy=dst_vy,
127
+ # players=[pt],
128
+ # )
129
+ # )
130
+ # else:
131
+ if self.triggered:
132
+ return False
133
+
134
+ new_direction = target.facing_direction
135
+ if self.invert_exit_direction:
136
+ new_direction = Direction(
137
+ (target.facing_direction.value + 2) % 4
138
+ )
139
+
140
+ cmd = CommandSerial(
141
+ [
142
+ CommandScreenFade(),
143
+ CommandParallel(
144
+ [
145
+ CommandChangeMap(
146
+ self.dst_map_name, dst_px, dst_py
147
+ ),
148
+ CommandSetFacingDirection(target, new_direction),
149
+ CommandScreenFade(
150
+ fadein=True, map_name=self.dst_map_name
151
+ ),
152
+ ]
153
+ ),
154
+ ]
155
+ )
156
+ cmd.set_players([pt])
157
+ self.engine.script.add_command(cmd)
158
+
159
+ if self.sfx_on_trigger:
160
+ self.engine.audio.play_sound(self.sfx_on_trigger)
161
+
162
+ self.triggered = True
163
+ return True
164
+
165
+ return False
166
+
167
+ def draw_self(self, ox: float, oy: float, camera_name: str = "display"):
168
+ if not self.visible:
169
+ self.engine.backend.draw_circle(
170
+ (self.px + 0.5 - ox) * self.engine.rtc.tile_width,
171
+ (self.py + 0.5 - oy) * self.engine.rtc.tile_height,
172
+ 0.5 * self.engine.rtc.tile_width,
173
+ self.engine.rtc.color_red,
174
+ camera_name,
175
+ )
176
+ return
177
+
178
+ if self.has_sprite:
179
+ self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
180
+
181
+ @staticmethod
182
+ def load_from_tiled_object(
183
+ obj, px, py, width, height, tilemap
184
+ ) -> List[Teleport]:
185
+ sprite_name = obj.get_string("sprite_name")
186
+ graphic_state = GraphicState[
187
+ obj.get_string("graphic_state", "closed").upper()
188
+ ]
189
+ facing_direction = Direction[
190
+ obj.get_string("facing_direction", "south").upper()
191
+ ]
192
+ target_map = obj.get_string("target_map", "map1_c1")
193
+ invert_exit_direction = obj.get_bool("invert_exit_direction")
194
+ relative = obj.get_bool("relative", False)
195
+ sliding = obj.get_bool("sliding", False)
196
+ vertical = obj.get_bool("vertical", False)
197
+ layer = obj.get_int("layer", 1)
198
+ target_px = obj.get_float("target_px")
199
+ target_py = obj.get_float("target_py")
200
+ direction = Direction[obj.get_string("direction", "south").upper()]
201
+ teleports = []
202
+ if width > height and int(width) > 1:
203
+ num_horizontal = int(width)
204
+ for idx in range(num_horizontal):
205
+ from_px = px + idx
206
+ from_py = py
207
+ to_px = target_px + idx
208
+ to_py = target_py
209
+
210
+ LOG.debug(
211
+ "Adding a teleport at (%f, %f) to map %s (%f, %f).",
212
+ from_px,
213
+ from_py,
214
+ target_map,
215
+ to_px,
216
+ to_py,
217
+ )
218
+ teleports.append(
219
+ Teleport(
220
+ px=from_px,
221
+ py=from_py,
222
+ sprite_name=sprite_name,
223
+ graphic_state=graphic_state,
224
+ facing_direction=facing_direction,
225
+ dst_map_name=target_map,
226
+ dst_px=to_px,
227
+ dst_py=to_py,
228
+ direction=direction,
229
+ invert_exit_direction=invert_exit_direction,
230
+ relative=relative,
231
+ sliding=sliding,
232
+ vertical=False,
233
+ tilemap=tilemap,
234
+ dyn_id=obj.object_id,
235
+ name=obj.name,
236
+ )
237
+ )
238
+ teleports[-1].layer = layer
239
+ elif height > width and int(height) > 1:
240
+ num_vertical = int(height)
241
+ for idx in range(num_vertical):
242
+ from_px = px
243
+ from_py = py + idx
244
+ to_px = target_px
245
+ to_py = target_py if relative else from_py
246
+
247
+ LOG.debug(
248
+ "Adding a teleport at (%f, %f) to map %s (%f, %f).",
249
+ from_px,
250
+ from_py,
251
+ target_map,
252
+ to_px,
253
+ to_py,
254
+ )
255
+ teleports.append(
256
+ Teleport(
257
+ px=from_px,
258
+ py=from_py,
259
+ sprite_name=sprite_name,
260
+ graphic_state=graphic_state,
261
+ facing_direction=facing_direction,
262
+ dst_map_name=target_map,
263
+ dst_px=to_px,
264
+ dst_py=to_py,
265
+ direction=direction,
266
+ invert_exit_direction=invert_exit_direction,
267
+ relative=relative,
268
+ sliding=sliding,
269
+ vertical=True,
270
+ tilemap=tilemap,
271
+ dyn_id=obj.object_id,
272
+ name=obj.name,
273
+ )
274
+ )
275
+ teleports[-1].layer = layer
276
+ else:
277
+ LOG.debug(
278
+ "Adding a teleport at (%f, %f) to map %s (%f, %f).",
279
+ px,
280
+ py,
281
+ target_map,
282
+ target_px,
283
+ target_py,
284
+ )
285
+ teleports.append(
286
+ Teleport(
287
+ px=px,
288
+ py=py,
289
+ sprite_name=sprite_name,
290
+ graphic_state=graphic_state,
291
+ facing_direction=facing_direction,
292
+ dst_map_name=target_map,
293
+ dst_px=target_px,
294
+ dst_py=target_py,
295
+ direction=direction,
296
+ invert_exit_direction=invert_exit_direction,
297
+ relative=relative,
298
+ sliding=sliding,
299
+ vertical=vertical,
300
+ tilemap=tilemap,
301
+ dyn_id=obj.object_id,
302
+ name=obj.name,
303
+ )
304
+ )
305
+ teleports[-1].sfx_on_trigger = obj.get_string("sfx_name")
306
+ teleports[-1].layer = layer
307
+
308
+ return teleports
mima/py.typed ADDED
File without changes
@@ -0,0 +1,2 @@
1
+ from .command import Command
2
+ from .script_processor import ScriptProcessor
@@ -0,0 +1,38 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, List, Optional
4
+
5
+ from ..types.player import Player
6
+
7
+ if TYPE_CHECKING:
8
+ from ..engine import MimaEngine
9
+
10
+
11
+ class Command:
12
+ engine: MimaEngine
13
+
14
+ def __init__(self, players: Optional[List[Player]] = None):
15
+ self.started: bool = False
16
+ self.completed: bool = False
17
+ self.uninterruptible: bool = False
18
+ self.players: List[Player] = (
19
+ players if (players is not None and players) else [Player.P0]
20
+ )
21
+
22
+ def start(self):
23
+ pass
24
+
25
+ def update(self, elapsed_time: float):
26
+ pass
27
+
28
+ def can_complete(self, force: bool = False) -> bool:
29
+ if self.uninterruptible and not force:
30
+ return False
31
+
32
+ return True
33
+
34
+ def finalize(self):
35
+ pass
36
+
37
+ def set_players(self, players: List[Player]):
38
+ self.players = players
File without changes