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,178 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Optional
4
+
5
+ from ...maps.tilemap import Tilemap
6
+ from ...types.damage import Damage
7
+ from ...types.direction import Direction
8
+ from ...types.graphic_state import GraphicState
9
+ from ...types.nature import Nature
10
+ from ...types.object import ObjectType
11
+ from ..animated_sprite import AnimatedSprite
12
+ from ..dynamic import Dynamic
13
+ from .teleport import Teleport
14
+
15
+
16
+ class Gate(Dynamic):
17
+ def __init__(
18
+ self,
19
+ px: float,
20
+ py: float,
21
+ name: str = "Gate",
22
+ *,
23
+ sprite_name: str = "",
24
+ tilemap: Optional[Tilemap] = None,
25
+ dyn_id: int = 0,
26
+ graphic_state: GraphicState = GraphicState.STANDING,
27
+ facing_direction: Direction = Direction.SOUTH,
28
+ bombable: bool = False,
29
+ ):
30
+ if graphic_state not in (
31
+ GraphicState.OPEN,
32
+ GraphicState.CLOSED,
33
+ GraphicState.LOCKED,
34
+ ):
35
+ msg = (
36
+ f"graphic_state of Gate {name}{dyn_id} must be either 'open'"
37
+ f", 'closed', or 'locked', but it {graphic_state}"
38
+ )
39
+
40
+ raise ValueError(msg)
41
+
42
+ super().__init__(
43
+ px,
44
+ py,
45
+ name,
46
+ tilemap=tilemap,
47
+ sprite_name=sprite_name,
48
+ dyn_id=dyn_id,
49
+ )
50
+
51
+ self.type = ObjectType.GATE
52
+
53
+ self.graphic_state = graphic_state
54
+ self.facing_direction = facing_direction
55
+ self.open = self.graphic_state == GraphicState.OPEN
56
+
57
+ # self.closed_sprite_name = closed_sprite_name
58
+ # self.open_sprite_name = open_sprite_name
59
+ # self.closed_sprite_ox: float = closed_sprite_ox
60
+ # self.closed_sprite_oy: float = closed_sprite_oy
61
+ # self.open_sprite_ox: float = open_sprite_ox
62
+ # self.open_sprite_oy: float = open_sprite_oy
63
+
64
+ # self.open = open
65
+ self.bombable = bombable
66
+ self.requires_key = self.graphic_state == GraphicState.LOCKED
67
+ self.unlocked = False
68
+ self.solid_vs_map = False
69
+ self.layer = 0
70
+ self.hitbox_px = self.hitbox_py = 0.0
71
+ self.hitbox_width = self.hitbox_height = 1.0
72
+ # self._set_sprite_state()
73
+
74
+ def update(self, elapsed_time: float, target: Dynamic):
75
+ self.solid_vs_dyn = not self.open
76
+ self.graphic_state = (
77
+ GraphicState.OPEN
78
+ if self.open
79
+ else (
80
+ GraphicState.LOCKED
81
+ if self.requires_key
82
+ else GraphicState.CLOSED
83
+ )
84
+ )
85
+
86
+ self.sprite.update(
87
+ elapsed_time, self.facing_direction, self.graphic_state
88
+ )
89
+
90
+ def on_interaction(self, target: Dynamic, nature: Nature):
91
+ if nature == Nature.TALK:
92
+ if target.type == ObjectType.PLAYER:
93
+ if (
94
+ not self.open
95
+ and self.requires_key
96
+ and target.attributes.keys > 0
97
+ ):
98
+ target.attributes.keys -= 1
99
+ self.open = True
100
+ self.state_changed = True
101
+ self.unlocked = True
102
+ return True
103
+
104
+ if nature == Nature.SIGNAL:
105
+ self.open = True
106
+ self.state_changed = True
107
+ return True
108
+
109
+ if nature == Nature.NO_SIGNAL and not self.unlocked:
110
+ self.open = False
111
+ self.state_changed = True
112
+ return True
113
+
114
+ if self.bombable and target.type == ObjectType.PROJECTILE:
115
+ if target.dtype == Damage.EXPLOSION:
116
+ self.open = True
117
+ self.state_changed = True
118
+ if target.one_hit:
119
+ target.kill()
120
+
121
+ return False
122
+
123
+ def draw_self(self, ox: float, oy: float, camera_name: str = "display"):
124
+ self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
125
+
126
+ @staticmethod
127
+ def load_from_tiled_object(
128
+ obj, px: float, py: float, width: float, height: float, tilemap
129
+ ) -> Gate:
130
+ gate = [
131
+ Gate(
132
+ px=px,
133
+ py=py,
134
+ name=obj.name,
135
+ sprite_name=obj.get_string("sprite_name"),
136
+ tilemap=tilemap,
137
+ dyn_id=obj.object_id,
138
+ graphic_state=GraphicState[
139
+ obj.get_string("graphic_state", "closed").upper()
140
+ ],
141
+ facing_direction=Direction[
142
+ obj.get_string("facing_direction", "south").upper()
143
+ ],
144
+ bombable=obj.get_bool("bombable"),
145
+ )
146
+ ]
147
+
148
+ if obj.get_bool("has_teleport"):
149
+ if gate[0].facing_direction == Direction.NORTH:
150
+ py += 0.4
151
+ elif gate[0].facing_direction == Direction.SOUTH:
152
+ py -= 0.1
153
+
154
+ teleport = Teleport(
155
+ px,
156
+ py,
157
+ f"Teleport of {gate[0].name}",
158
+ sprite_name="",
159
+ tilemap=tilemap,
160
+ dyn_id=gate[0].dyn_id + 2000,
161
+ dst_map_name=obj.get_string("target_map"),
162
+ dst_px=obj.get_float("target_px"),
163
+ dst_py=obj.get_float("target_py"),
164
+ facing_direction=gate[0].facing_direction,
165
+ graphic_state=GraphicState.STANDING,
166
+ direction=gate[0].facing_direction,
167
+ invert_exit_direction=False,
168
+ relative=False,
169
+ sliding=False,
170
+ vertical=False,
171
+ )
172
+
173
+ teleport.visible = False
174
+ teleport.sfx_on_trigger = "pass_door"
175
+
176
+ gate.append(teleport)
177
+
178
+ return gate
@@ -0,0 +1,121 @@
1
+ from typing import Optional
2
+
3
+ from ...maps.tilemap import Tilemap
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 ..animated_sprite import AnimatedSprite
9
+ from ..dynamic import Dynamic
10
+ from ..effects.light import Light
11
+ from ..projectile import Projectile
12
+
13
+
14
+ class LightSource(Dynamic):
15
+ def __init__(
16
+ self,
17
+ px: float,
18
+ py: float,
19
+ name: str = "LightSource",
20
+ *,
21
+ sprite_name: str = "",
22
+ tilemap: Optional[Tilemap] = None,
23
+ dyn_id: int = -1,
24
+ graphic_state: GraphicState = GraphicState.ON,
25
+ max_size: int = 32,
26
+ ):
27
+ if graphic_state not in [GraphicState.OFF, GraphicState.ON]:
28
+ msg = (
29
+ f"graphic_state of LightSource {name}{dyn_id} must be either "
30
+ f"'off' or 'on', but it is {graphic_state}"
31
+ )
32
+ raise ValueError(msg)
33
+
34
+ super().__init__(
35
+ px,
36
+ py,
37
+ name,
38
+ sprite_name=sprite_name,
39
+ tilemap=tilemap,
40
+ dyn_id=dyn_id,
41
+ )
42
+
43
+ self.type = ObjectType.LIGHT_SOURCE
44
+ self.graphic_state = graphic_state
45
+ self._max_size = max_size
46
+ self.active = self.graphic_state == GraphicState.ON
47
+ self._light: Optional[Projectile] = None
48
+
49
+ self.hitbox_px = 0.0
50
+ self.hitbox_py = 0.0
51
+ self.hitbox_width = 1.0
52
+ self.hitbox_height = 1.0
53
+ self.solid_vs_dyn = True
54
+ self.solid_vs_map = False
55
+ self._state_changed = True
56
+
57
+ def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
58
+ if self._state_changed:
59
+ # self._set_sprite_state()
60
+ self._state_changed = False
61
+
62
+ if self.active:
63
+ if self._light is None:
64
+ self._light = Light(self, self._max_size)
65
+ self.engine.get_view().add_effect(
66
+ self._light, self.tilemap.name
67
+ )
68
+ else:
69
+ if self._light is not None:
70
+ self._light.kill()
71
+ self._light = None
72
+
73
+ self.graphic_state = (
74
+ GraphicState.ON if self.active else GraphicState.OFF
75
+ )
76
+ self.sprite.update(
77
+ elapsed_time, self.facing_direction, self.graphic_state
78
+ )
79
+
80
+ def on_interaction(self, target: Dynamic, nature: Nature):
81
+ if nature == Nature.SIGNAL:
82
+ self.active = True
83
+ self._state_changed = True
84
+ return True
85
+
86
+ if nature == Nature.NO_SIGNAL:
87
+ self.active = False
88
+ self._state_changed = True
89
+ return True
90
+
91
+ if nature == Nature.TALK:
92
+ self.active = not self.active
93
+ self._state_changed = True
94
+ return True
95
+
96
+ def draw_self(self, ox: float, oy: float, camera_name: str = "display"):
97
+ self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
98
+
99
+ def on_death(self) -> bool:
100
+ self._light.kill()
101
+ return True
102
+
103
+ @staticmethod
104
+ def load_from_tiled_object(obj, px, py, width, height, tilemap):
105
+ light = LightSource(
106
+ px=px,
107
+ py=py,
108
+ name=obj.name,
109
+ sprite_name=obj.get_string("sprite_name"),
110
+ tilemap=tilemap,
111
+ dyn_id=obj.object_id,
112
+ graphic_state=GraphicState[
113
+ obj.get_string("graphic_state", "on").upper()
114
+ ],
115
+ max_size=obj.get_int("max_size", 32),
116
+ )
117
+
118
+ # light.sprite.width = int(width * LightSource.engine.rtc.tile_width)
119
+ # light.sprite.height = int(height * LightSource.engine.rtc.tile_height)
120
+
121
+ return [light]
@@ -0,0 +1,157 @@
1
+ from enum import Enum
2
+ from typing import List, Optional, Union
3
+
4
+ from ...maps.tilemap import Tilemap
5
+ from ...types.alignment import Alignment
6
+ from ...types.direction import Direction
7
+ from ...types.graphic_state import GraphicState
8
+ from ...types.nature import Nature
9
+ from ...types.object import ObjectType
10
+ from ..animated_sprite import AnimatedSprite
11
+ from ..dynamic import Dynamic
12
+
13
+
14
+ class LogicFunction(Enum):
15
+ LOGIC_PASS = 0
16
+ LOGIC_NOT = 1
17
+ LOGIC_AND = 2
18
+ LOGIC_OR = 3
19
+ LOGIC_NAND = 4
20
+ LOGIC_NOR = 5
21
+ LOGIC_XOR = 6
22
+ LOGIC_IMPL = 7
23
+ LOGIC_EQUI = 8
24
+
25
+
26
+ class LogicGate(Dynamic):
27
+ def __init__(
28
+ self,
29
+ px: float,
30
+ py: float,
31
+ name: str = "Logic Gate",
32
+ *,
33
+ sprite_name: str = "",
34
+ tilemap: Optional[Tilemap] = None,
35
+ dyn_id: int = -1,
36
+ mode: LogicFunction = LogicFunction.LOGIC_PASS,
37
+ initial_signal: bool = False,
38
+ visible: bool = False,
39
+ ):
40
+ super().__init__(
41
+ px,
42
+ py,
43
+ name,
44
+ sprite_name=sprite_name,
45
+ tilemap=tilemap,
46
+ dyn_id=dyn_id,
47
+ )
48
+
49
+ self.type = ObjectType.LOGIC_GATE
50
+ self.alignment = Alignment.NEUTRAL
51
+ self.visible = visible
52
+
53
+ self.input_id1: int = -1
54
+ self.input_id2: int = -1
55
+
56
+ self.mode = mode
57
+ self.signal: bool = False
58
+ self.last_signal: bool = False
59
+ self.input1: bool = False
60
+ self.input2: bool = False
61
+
62
+ self.listener_ids: List[int] = []
63
+ self.listeners: List[Dynamic] = []
64
+ self.send_initial_signal: bool = initial_signal
65
+ self.state_changed: bool = False
66
+
67
+ def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
68
+ if self.mode == LogicFunction.LOGIC_NOT:
69
+ self.signal = not self.input1
70
+ elif self.mode == LogicFunction.LOGIC_AND:
71
+ self.signal = self.input1 and self.input2
72
+ elif self.mode == LogicFunction.LOGIC_OR:
73
+ self.signal = self.input1 or self.input2
74
+ else:
75
+ self.signal = self.input1
76
+
77
+ if self.last_signal != self.signal:
78
+ self.state_changed = True
79
+ else:
80
+ self.state_changed = False
81
+
82
+ if self.send_initial_signal or self.state_changed:
83
+ self.send_signal(self.signal)
84
+ self.send_initial_signal = False
85
+
86
+ self.last_signal = self.signal
87
+
88
+ self.graphic_state = (
89
+ GraphicState.ON if self.signal else GraphicState.OFF
90
+ )
91
+ self.sprite.update(
92
+ elapsed_time, self.facing_direction, self.graphic_state
93
+ )
94
+
95
+ def on_interaction(self, target: Dynamic, nature: Nature):
96
+ if nature == Nature.SIGNAL:
97
+ if target.dyn_id == self.input_id1:
98
+ self.input1 = True
99
+ elif target.dyn_id == self.input_id2:
100
+ self.input2 = True
101
+ else:
102
+ return False
103
+ return True
104
+ elif nature == Nature.NO_SIGNAL:
105
+ if target.dyn_id == self.input_id1:
106
+ self.input1 = False
107
+ elif target.dyn_id == self.input_id2:
108
+ self.input2 = False
109
+ else:
110
+ return False
111
+ return True
112
+
113
+ return False
114
+
115
+ def draw_self(self, ox: float, oy: float, camera_name: str = "display"):
116
+ if self.visible:
117
+ self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
118
+
119
+ def send_signal(self, nature: Union[Nature, bool]):
120
+ if isinstance(nature, bool):
121
+ nature = Nature.SIGNAL if nature else Nature.NO_SIGNAL
122
+
123
+ for listener in self.listeners:
124
+ listener.on_interaction(self, nature)
125
+
126
+ @staticmethod
127
+ def load_from_tiled_object(obj, px, py, width, height, tilemap):
128
+ logic = LogicGate(
129
+ px,
130
+ py,
131
+ obj.name,
132
+ sprite_name=obj.get_string("sprite_name"),
133
+ tilemap=tilemap,
134
+ dyn_id=obj.object_id,
135
+ mode=LogicFunction[obj.get_string("mode", "logic_pass").upper()],
136
+ initial_signal=obj.get_bool("initial_signal", False),
137
+ visible=obj.get_bool("visible", True),
138
+ )
139
+ logic.facing_direction = Direction[
140
+ obj.get_string("facing_direction", "south").upper()
141
+ ]
142
+ logic.graphic_state = GraphicState[
143
+ obj.get_string("graphic_state", "closed").upper()
144
+ ]
145
+ # logic.send_initial_signal =
146
+ # logic.sprite.width = int(width * LogicGate.engine.rtc.tile_width)
147
+ # logic.sprite.height = int(height * LogicGate.engine.rtc.tile_height)
148
+
149
+ ctr = 1
150
+ while True:
151
+ listener_id = obj.get_int(f"output{ctr}", -1)
152
+ if listener_id < 0:
153
+ break
154
+ logic.listener_ids.append(listener_id)
155
+ ctr += 1
156
+
157
+ return [logic]