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
mima/objects/sprite.py ADDED
@@ -0,0 +1,116 @@
1
+ from ..types.direction import Direction
2
+ from ..types.graphic_state import GraphicState
3
+ from ..util.constants import (
4
+ DEFAULT_GRAPHIC_TIMER,
5
+ DEFAULT_GRAPHIC_TIMER_DAMAGED,
6
+ DEFAULT_GRAPHIC_TIMER_DEAD,
7
+ DEFAULT_GRAPHIC_TIMER_STANDING,
8
+ DEFAULT_GRAPHIC_TIMER_WALKING,
9
+ DEFAULT_SPRITE_HEIGHT,
10
+ DEFAULT_SPRITE_WIDTH,
11
+ )
12
+
13
+
14
+ class Sprite:
15
+ engine = None
16
+
17
+ def __init__(self, name: str = "", *, ox=0, oy=0, width=0, height=0):
18
+ self.name = name
19
+ self.ox: int = 0
20
+ self.oy: int = 0
21
+ self.width: int = DEFAULT_SPRITE_WIDTH if width == 0 else width
22
+ self.height: int = DEFAULT_SPRITE_HEIGHT if height == 0 else height
23
+ self.num_frames: int = 1
24
+ self.frame_index: int = 0
25
+
26
+ self.timer: float = 0.25
27
+ self.timer_reset: float = 0.5
28
+
29
+ self.last_direction: Direction = Direction.SOUTH
30
+ self.last_graphic_state: GraphicState = GraphicState.STANDING
31
+
32
+ def update(
33
+ self,
34
+ elapsed_time: float,
35
+ direction: Direction = Direction.SOUTH,
36
+ graphic_state: GraphicState = GraphicState.STANDING,
37
+ ):
38
+ if (
39
+ direction == self.last_direction
40
+ and graphic_state == self.last_graphic_state
41
+ ):
42
+ # Nothing has changed, normal case
43
+ self.timer -= elapsed_time
44
+
45
+ if self.timer <= 0.0:
46
+ self.timer += self.timer_reset
47
+ self.frame_index = (self.frame_index + 1) % self.num_frames
48
+
49
+ else:
50
+ # Something changed
51
+ if graphic_state != self.last_graphic_state:
52
+ # State changed
53
+ if graphic_state == GraphicState.STANDING:
54
+ self.timer_reset = DEFAULT_GRAPHIC_TIMER_STANDING
55
+ elif graphic_state == GraphicState.WALKING:
56
+ self.timer_reset = DEFAULT_GRAPHIC_TIMER_WALKING
57
+ elif graphic_state == GraphicState.DAMAGED:
58
+ self.timer_reset = DEFAULT_GRAPHIC_TIMER_DAMAGED
59
+ elif graphic_state == GraphicState.DEAD:
60
+ self.timer_reset = DEFAULT_GRAPHIC_TIMER_DEAD
61
+ elif graphic_state == GraphicState.PUSHING:
62
+ self.timer_reset = DEFAULT_GRAPHIC_TIMER_WALKING
63
+ else:
64
+ self.timer_reset = DEFAULT_GRAPHIC_TIMER
65
+
66
+ # self.timer = self.timer_reset
67
+ # self.frame_index = 0
68
+
69
+ self.timer = self.timer_reset
70
+ self.frame_index = 0
71
+
72
+ self.last_direction = direction
73
+ self.last_graphic_state = graphic_state
74
+
75
+ def draw_self(
76
+ self,
77
+ px: float,
78
+ py: float,
79
+ camera_name: str = "display",
80
+ draw_to_ui: bool = False,
81
+ ):
82
+ if self.name == "":
83
+ return
84
+
85
+ sheet_ox = sheet_oy = 0
86
+ state_value = self.last_graphic_state.value
87
+
88
+ if self.last_graphic_state == GraphicState.CELEBRATING:
89
+ sheet_ox = (self.ox + self.frame_index) * self.width
90
+ sheet_oy = (self.oy + state_value) * self.height
91
+ elif self.last_graphic_state == GraphicState.DEAD:
92
+ sheet_ox = (self.ox + 2 + self.frame_index) * self.width
93
+ sheet_oy = (self.oy + state_value) * self.height
94
+ else:
95
+ if self.last_graphic_state == GraphicState.PUSHING:
96
+ state_value -= 1
97
+ sheet_ox = (
98
+ self.ox + 2 * self.last_direction.value + self.frame_index
99
+ ) * self.width
100
+ sheet_oy = (self.oy + state_value) * self.height
101
+
102
+ self.engine.backend.draw_partial_sprite(
103
+ px * self.engine.rtc.tile_width,
104
+ py * self.engine.rtc.tile_height,
105
+ self.name,
106
+ sheet_ox,
107
+ sheet_oy,
108
+ self.width,
109
+ self.height,
110
+ camera_name,
111
+ draw_to_ui=draw_to_ui,
112
+ )
113
+
114
+ def reset(self):
115
+ self.frame_index = 0
116
+ self.timer = 0.0
File without changes
@@ -0,0 +1,67 @@
1
+ from typing import List, Optional, Union
2
+
3
+ from ...maps.tilemap import Tilemap
4
+ from ...types.direction import Direction
5
+ from ...types.gate_color import GateColor
6
+ from ...types.graphic_state import GraphicState
7
+ from ...types.nature import Nature
8
+ from ...types.object import ObjectType
9
+ from ..dynamic import Dynamic
10
+ from .gate import Gate
11
+
12
+
13
+ class ColorGate(Gate):
14
+
15
+ def __init__(
16
+ self,
17
+ px: float,
18
+ py: float,
19
+ name: str = "ColorGate",
20
+ *,
21
+ sprite_name: str = "",
22
+ tilemap: Optional[Tilemap] = None,
23
+ dyn_id: int = -1,
24
+ graphic_state: GraphicState = GraphicState.STANDING,
25
+ facing_direction: Direction = Direction.SOUTH,
26
+ color: GateColor = GateColor.RED,
27
+ ):
28
+ super().__init__(
29
+ px,
30
+ py,
31
+ name,
32
+ sprite_name=sprite_name,
33
+ tilemap=tilemap,
34
+ dyn_id=dyn_id,
35
+ graphic_state=graphic_state,
36
+ facing_direction=facing_direction,
37
+ bombable=False,
38
+ )
39
+ self.color = color
40
+ self.type = ObjectType.COLOR_GATE
41
+
42
+ def update(self, elapsed_time, float, target: Optional[Dynamic] = None):
43
+ self.open = self.engine.gate_color == self.color
44
+ super().update(elapsed_time, target)
45
+
46
+ def on_interaction(self, target: Dynamic, nature: Nature):
47
+ return False
48
+
49
+ @staticmethod
50
+ def load_from_tiled_object(obj, px, py, width, height, tilemap):
51
+ gate = ColorGate(
52
+ px=px,
53
+ py=py,
54
+ name=obj.name,
55
+ sprite_name=obj.get_string("sprite_name"),
56
+ tilemap=tilemap,
57
+ dyn_id=obj.object_id,
58
+ graphic_state=GraphicState[
59
+ obj.get_string("graphic_state", "closed").upper()
60
+ ],
61
+ facing_direction=Direction[
62
+ obj.get_string("facing_direction", "south").upper()
63
+ ],
64
+ color=GateColor[obj.get_string("color", "red").upper()],
65
+ )
66
+
67
+ return [gate]
@@ -0,0 +1,101 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, List, Optional, Union
4
+
5
+ from ...types.direction import Direction
6
+ from ...types.gate_color import GateColor
7
+ from ...types.graphic_state import GraphicState
8
+ from ...types.nature import Nature
9
+ from ...types.object import ObjectType
10
+ from ..dynamic import Dynamic
11
+ from .switch import Switch
12
+
13
+ if TYPE_CHECKING:
14
+ from ...maps.tilemap import Tilemap
15
+
16
+
17
+ class ColorSwitch(Switch):
18
+ def __init__(
19
+ self,
20
+ px: float,
21
+ py: float,
22
+ name="ColorSwitch",
23
+ *,
24
+ sprite_name: str = "",
25
+ tilemap: Optional[Tilemap] = None,
26
+ dyn_id=-1,
27
+ graphic_state: GraphicState = GraphicState.OPEN,
28
+ initial_signal=False,
29
+ color: GateColor = GateColor.RED,
30
+ ):
31
+ super().__init__(
32
+ px,
33
+ py,
34
+ name,
35
+ sprite_name=sprite_name,
36
+ tilemap=tilemap,
37
+ dyn_id=dyn_id,
38
+ graphic_state=graphic_state,
39
+ initial_signal=initial_signal,
40
+ )
41
+ self.type = ObjectType.COLOR_SWITCH
42
+
43
+ self.color = color
44
+ self.graphic_state = (
45
+ GraphicState.CLOSED
46
+ if color == self.engine.gate_color
47
+ else GraphicState.OPEN
48
+ )
49
+ # self.signal = self.graphic_state == GraphicState.CLOSED
50
+ # self.send_initial_signal = False
51
+
52
+ def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
53
+ self.graphic_state = (
54
+ GraphicState.CLOSED
55
+ if self.color == self.engine.gate_color
56
+ else GraphicState.OPEN
57
+ )
58
+ # self.signal = self.graphic_state == GraphicState.CLOSED
59
+ #
60
+ self.sprite.update(
61
+ elapsed_time, self.facing_direction, self.graphic_state
62
+ )
63
+
64
+ def on_interaction(self, target: Dynamic, nature: Nature):
65
+ if (
66
+ nature == Nature.TALK
67
+ and target.type == ObjectType.PLAYER
68
+ and self.visible
69
+ ):
70
+ if self.engine.gate_color != self.color:
71
+ self.engine.gate_color = self.color
72
+ else:
73
+ self.engine.gate_color = GateColor(
74
+ (self.color.value + 1) % self.engine.n_gate_colors
75
+ )
76
+ self.state_changed = True
77
+ self.engine.audio.play_sound("switch")
78
+ return True
79
+
80
+ return False
81
+
82
+ @staticmethod
83
+ def load_from_tiled_object(obj, px, py, width, height, tilemap):
84
+ switch = ColorSwitch(
85
+ px=px,
86
+ py=py,
87
+ name=obj.name,
88
+ sprite_name=obj.get_string("sprite_name"),
89
+ tilemap=tilemap,
90
+ dyn_id=obj.object_id,
91
+ graphic_state=GraphicState[
92
+ obj.get_string("graphic_state", "closed").upper()
93
+ ],
94
+ color=GateColor[obj.get_string("color", "red").upper()],
95
+ initial_signal=False,
96
+ )
97
+
98
+ # switch.sprite.width = int(width * ColorSwitch.engine.rtc.tile_width)
99
+ # switch.sprite.height = int(height * ColorSwitch.engine.rtc.tile_height)
100
+
101
+ return [switch]
@@ -0,0 +1,175 @@
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.give_item import CommandGiveItem
8
+ from ...scripts.commands.give_resource import CommandGiveResource
9
+ from ...scripts.commands.parallel import CommandParallel
10
+ from ...scripts.commands.present_item import CommandPresentItem
11
+ from ...scripts.commands.show_dialog import CommandShowDialog
12
+ from ...types.direction import Direction
13
+ from ...types.graphic_state import GraphicState
14
+ from ...types.nature import Nature
15
+ from ...types.object import ObjectType
16
+ from ..animated_sprite import AnimatedSprite
17
+ from ..dynamic import Dynamic
18
+
19
+ LOG = logging.getLogger(__name__)
20
+
21
+
22
+ class Container(Dynamic):
23
+ def __init__(
24
+ self,
25
+ px: float,
26
+ py: float,
27
+ name: str = "Container",
28
+ *,
29
+ sprite_name: str = "",
30
+ tilemap: Optional[Tilemap] = None,
31
+ dyn_id: int = -1,
32
+ graphic_state: GraphicState = GraphicState.CLOSED,
33
+ item_name: str = "",
34
+ ):
35
+ if graphic_state not in [
36
+ GraphicState.OPEN,
37
+ GraphicState.CLOSED,
38
+ ]:
39
+ msg = (
40
+ f"graphic_state of Container {name}{dyn_id} must be either "
41
+ f"'open' or 'closed', but it is {graphic_state}"
42
+ )
43
+ raise ValueError(msg)
44
+ super().__init__(
45
+ px,
46
+ py,
47
+ name,
48
+ tilemap=tilemap,
49
+ sprite_name=sprite_name,
50
+ dyn_id=dyn_id,
51
+ )
52
+
53
+ self.type = ObjectType.CONTAINER
54
+ self.graphic_state = graphic_state
55
+ self.closed: bool = self.graphic_state != GraphicState.OPEN
56
+
57
+ self.item_name: str = item_name
58
+ self.item = self.engine.get_item(item_name)
59
+ self.solid_vs_dyn: bool = True
60
+ self.solid_vs_map: bool = True
61
+ self.visible: bool = True
62
+
63
+ self.is_resource: bool = False
64
+ self.amount: int = 1
65
+
66
+ self._gs_map = {False: GraphicState.OPEN, True: GraphicState.CLOSED}
67
+
68
+ def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
69
+ if self.visible:
70
+ self.solid_vs_dyn = True
71
+ else:
72
+ self.solid_vs_dyn = False
73
+
74
+ self.graphic_state = (
75
+ GraphicState.CLOSED if self.closed else GraphicState.OPEN
76
+ )
77
+
78
+ self.sprite.update(
79
+ elapsed_time, self.facing_direction, self.graphic_state
80
+ )
81
+
82
+ def draw_self(self, ox: float, oy: float, camera_name: str = "display"):
83
+ if not self.visible:
84
+ return
85
+
86
+ self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
87
+
88
+ def on_interaction(self, target: Dynamic, nature: Nature):
89
+ if nature == Nature.SIGNAL:
90
+ self.visible = True
91
+ return True
92
+
93
+ if nature == Nature.NO_SIGNAL:
94
+ self.visible = False
95
+ return True
96
+
97
+ if not self.visible:
98
+ return False
99
+
100
+ if nature == Nature.TALK:
101
+ if self.closed:
102
+ if self.is_resource:
103
+ text = "You received "
104
+ if self.amount > 1:
105
+ text += f"{self.amount} {self.item.name}s!"
106
+ elif self.amount == 1:
107
+ text += f"one {self.item.name}!"
108
+ else:
109
+ text += "nothing. The chest was empty!"
110
+
111
+ if self.item_name == "coin":
112
+ cgr = CommandGiveResource(target, coins=self.amount)
113
+ elif self.item_name == "bomb_refill":
114
+ cgr = CommandGiveResource(target, bombs=self.amount)
115
+ elif self.item_name == "arrow_refill":
116
+ cgr = CommandGiveResource(target, arrows=self.amount)
117
+ elif self.item_name == "key":
118
+ cgr = CommandGiveResource(target, keys=self.amount)
119
+ else:
120
+ LOG.error(f"Invalid resource type: {self.item_name}")
121
+ return False
122
+
123
+ self.engine.script.add_command(
124
+ CommandParallel(
125
+ [
126
+ CommandShowDialog([text]),
127
+ CommandPresentItem(self.item_name, target),
128
+ cgr,
129
+ ],
130
+ CommandParallel.FIRST_COMPLETED,
131
+ ),
132
+ players=[target.get_player()],
133
+ )
134
+
135
+ else:
136
+
137
+ self.engine.script.add_command(
138
+ CommandParallel(
139
+ [
140
+ CommandShowDialog(
141
+ [f"You received {self.item.name}"],
142
+ ),
143
+ CommandPresentItem(self.item_name, target),
144
+ CommandGiveItem(self.item_name, target),
145
+ ],
146
+ CommandParallel.FIRST_COMPLETED,
147
+ ),
148
+ players=[target.get_player()],
149
+ )
150
+ self.closed = False
151
+ self.state_changed = True
152
+ return True
153
+
154
+ return False
155
+
156
+ @staticmethod
157
+ def load_from_tiled_object(
158
+ obj, px, py, width, height, tilemap
159
+ ) -> List[Container]:
160
+ container = Container(
161
+ px=px,
162
+ py=py,
163
+ name=obj.name,
164
+ sprite_name=obj.get_string("sprite_name"),
165
+ tilemap=tilemap,
166
+ dyn_id=obj.object_id,
167
+ graphic_state=GraphicState[
168
+ obj.get_string("graphic_state", "closed").upper()
169
+ ],
170
+ item_name=obj.get_string("item_name"),
171
+ )
172
+ container.is_resource = obj.get_bool("is_resource", False)
173
+ container.amount = obj.get_int("amount", 1)
174
+
175
+ return [container]
@@ -0,0 +1,109 @@
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 ..dynamic import Dynamic
9
+ from .switch import Switch
10
+
11
+
12
+ class FloorSwitch(Switch):
13
+ def __init__(
14
+ self,
15
+ px: float,
16
+ py: float,
17
+ name="Floor Switch",
18
+ *,
19
+ sprite_name: str = "",
20
+ tilemap: Optional[Tilemap] = None,
21
+ dyn_id: int = -1,
22
+ graphic_state: GraphicState = GraphicState.OPEN,
23
+ initial_signal: bool = True,
24
+ ):
25
+ super().__init__(
26
+ px,
27
+ py,
28
+ name,
29
+ sprite_name=sprite_name,
30
+ tilemap=tilemap,
31
+ dyn_id=dyn_id,
32
+ graphic_state=graphic_state,
33
+ initial_signal=initial_signal,
34
+ )
35
+ self.layer = 0
36
+
37
+ self.type = ObjectType.FLOOR_SWITCH
38
+ self.interacted = False
39
+ self.interacted_before = False
40
+ self.solid_vs_dyn = False
41
+
42
+ def update(self, elapsed_time: float, target: Dynamic):
43
+ if self.send_initial_signal:
44
+ self.send_signal(self.signal)
45
+ self.send_initial_signal = False
46
+ self.state_changed = False
47
+ if not self.interacted:
48
+ if self.interacted_before:
49
+ self.state_changed = True
50
+ self.interacted_before = False
51
+
52
+ else:
53
+ if not self.interacted_before:
54
+ self.state_changed = True
55
+ self.interacted_before = True
56
+
57
+ self.interacted = False
58
+
59
+ if self.state_changed:
60
+ self.signal = not self.signal
61
+ self.send_signal(self.signal)
62
+
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 on_interaction(self, target: Dynamic, nature: Nature):
71
+ if nature == Nature.WALK and not target.type == ObjectType.PROJECTILE:
72
+ if target.type == ObjectType.MOVABLE:
73
+ if not target.visible:
74
+ return False
75
+ self.interacted = True
76
+ return True
77
+
78
+ return False
79
+
80
+ @staticmethod
81
+ def load_from_tiled_object(obj, px, py, width, height, tilemap):
82
+ fswitch = FloorSwitch(
83
+ px=px,
84
+ py=py,
85
+ name=obj.name,
86
+ sprite_name=obj.get_string("sprite_name"),
87
+ tilemap=tilemap,
88
+ dyn_id=obj.object_id,
89
+ graphic_state=GraphicState[
90
+ obj.get_string("graphic_state", "closed").upper()
91
+ ],
92
+ initial_signal=obj.get_bool("initial_signal", True),
93
+ )
94
+ # TODO: Why was this used?
95
+ # fswitch.sprite.width = int(width * FloorSwitch.engine.rtc.tile_width)
96
+ # fswitch.sprite.height = int(
97
+ # height * FloorSwitch.engine.rtc.tile_height
98
+ # )
99
+
100
+ ctr = 1
101
+ while True:
102
+ key = f"output{ctr}"
103
+ listener_id = obj.get_int(key, -1)
104
+ if listener_id < 0:
105
+ break
106
+ fswitch.listener_ids.append(listener_id)
107
+ ctr += 1
108
+
109
+ return [fswitch]