mima-engine 0.1.5__py3-none-any.whl → 0.2.1__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 (80) hide show
  1. mima/__init__.py +1 -1
  2. mima/backend/pygame_assets.py +14 -8
  3. mima/backend/pygame_audio.py +5 -2
  4. mima/backend/pygame_backend.py +255 -57
  5. mima/backend/pygame_camera.py +63 -0
  6. mima/backend/pygame_events.py +369 -120
  7. mima/collision.py +182 -111
  8. mima/engine.py +155 -15
  9. mima/maps/tiled/tiled_map.py +3 -3
  10. mima/maps/tiled/tiled_tileset.py +1 -0
  11. mima/maps/tilemap.py +78 -15
  12. mima/maps/tileset.py +8 -2
  13. mima/maps/transition_map.py +6 -8
  14. mima/mode_engine.py +80 -0
  15. mima/objects/animated_sprite.py +23 -15
  16. mima/objects/attributes.py +3 -0
  17. mima/objects/creature.py +54 -17
  18. mima/objects/dynamic.py +30 -8
  19. mima/objects/effects/colorize_screen.py +22 -6
  20. mima/objects/effects/debug_box.py +124 -0
  21. mima/objects/effects/light.py +21 -30
  22. mima/objects/effects/show_sprite.py +39 -0
  23. mima/objects/effects/walking_on_grass.py +25 -7
  24. mima/objects/effects/walking_on_water.py +17 -6
  25. mima/objects/loader.py +24 -13
  26. mima/objects/projectile.py +21 -6
  27. mima/objects/sprite.py +7 -8
  28. mima/objects/world/color_gate.py +5 -2
  29. mima/objects/world/color_switch.py +12 -6
  30. mima/objects/world/container.py +17 -8
  31. mima/objects/world/floor_switch.py +8 -4
  32. mima/objects/world/gate.py +8 -5
  33. mima/objects/world/light_source.py +11 -9
  34. mima/objects/world/logic_gate.py +8 -7
  35. mima/objects/world/movable.py +72 -28
  36. mima/objects/world/oneway.py +14 -9
  37. mima/objects/world/pickup.py +10 -5
  38. mima/objects/world/switch.py +28 -25
  39. mima/objects/world/teleport.py +76 -55
  40. mima/scene_engine.py +19 -20
  41. mima/scripts/command.py +16 -2
  42. mima/scripts/commands/change_map.py +23 -4
  43. mima/scripts/commands/equip_weapon.py +23 -0
  44. mima/scripts/commands/give_item.py +5 -3
  45. mima/scripts/commands/move_map.py +9 -9
  46. mima/scripts/commands/parallel.py +16 -3
  47. mima/scripts/commands/present_item.py +7 -5
  48. mima/scripts/commands/screen_fade.py +30 -12
  49. mima/scripts/commands/serial.py +30 -7
  50. mima/scripts/commands/set_spawn_map.py +6 -3
  51. mima/scripts/commands/show_choices.py +16 -7
  52. mima/scripts/commands/show_dialog.py +110 -3
  53. mima/scripts/script_processor.py +41 -20
  54. mima/states/game_state.py +2 -0
  55. mima/states/memory.py +28 -0
  56. mima/states/quest.py +2 -3
  57. mima/types/keys.py +48 -0
  58. mima/types/mode.py +4 -10
  59. mima/types/player.py +9 -0
  60. mima/types/position.py +13 -0
  61. mima/types/tile_collision.py +11 -0
  62. mima/types/window.py +44 -0
  63. mima/usables/item.py +1 -0
  64. mima/util/colors.py +5 -0
  65. mima/util/constants.py +6 -0
  66. mima/util/functions.py +27 -0
  67. mima/util/input_defaults.py +109 -0
  68. mima/util/runtime_config.py +234 -30
  69. mima/util/trading_item.py +20 -0
  70. mima/view/camera.py +160 -19
  71. mima/view/mima_mode.py +612 -0
  72. mima/view/mima_scene.py +225 -0
  73. mima/view/mima_view.py +12 -0
  74. mima/view/mima_window.py +153 -0
  75. {mima_engine-0.1.5.dist-info → mima_engine-0.2.1.dist-info}/METADATA +4 -2
  76. mima_engine-0.2.1.dist-info/RECORD +128 -0
  77. {mima_engine-0.1.5.dist-info → mima_engine-0.2.1.dist-info}/WHEEL +1 -1
  78. mima/view/scene.py +0 -322
  79. mima_engine-0.1.5.dist-info/RECORD +0 -114
  80. {mima_engine-0.1.5.dist-info → mima_engine-0.2.1.dist-info}/top_level.txt +0 -0
@@ -1,14 +1,18 @@
1
- from typing import List, Optional, Union
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, List, Optional, Union
2
4
 
3
5
  from ...types.direction import Direction
4
6
  from ...types.gate_color import GateColor
5
7
  from ...types.graphic_state import GraphicState
6
8
  from ...types.nature import Nature
7
9
  from ...types.object import ObjectType
8
- from ...util.constants import TILE_HEIGHT, TILE_WIDTH
9
10
  from ..dynamic import Dynamic
10
11
  from .switch import Switch
11
12
 
13
+ if TYPE_CHECKING:
14
+ from ...maps.tilemap import Tilemap
15
+
12
16
 
13
17
  class ColorSwitch(Switch):
14
18
  def __init__(
@@ -22,10 +26,10 @@ class ColorSwitch(Switch):
22
26
  graphic_state: GraphicState,
23
27
  color: GateColor,
24
28
  initial_signal=True,
29
+ tilemap: Tilemap = None,
25
30
  dyn_id=-1,
26
31
  name="ColorSwitch",
27
32
  ):
28
-
29
33
  super().__init__(
30
34
  px,
31
35
  py,
@@ -35,6 +39,7 @@ class ColorSwitch(Switch):
35
39
  facing_direction,
36
40
  graphic_state,
37
41
  initial_signal,
42
+ tilemap,
38
43
  dyn_id,
39
44
  name,
40
45
  )
@@ -80,7 +85,7 @@ class ColorSwitch(Switch):
80
85
  return False
81
86
 
82
87
  @staticmethod
83
- def load_from_tiled_object(obj, px, py, width, height):
88
+ def load_from_tiled_object(obj, px, py, width, height, tilemap):
84
89
  switch = ColorSwitch(
85
90
  px=px,
86
91
  py=py,
@@ -95,11 +100,12 @@ class ColorSwitch(Switch):
95
100
  ],
96
101
  color=GateColor[obj.get_string("color", "red").upper()],
97
102
  initial_signal=False,
103
+ tilemap=tilemap,
98
104
  dyn_id=obj.object_id,
99
105
  name=obj.name,
100
106
  )
101
107
 
102
- switch.sprite.width = int(width * TILE_WIDTH)
103
- switch.sprite.height = int(height * TILE_HEIGHT)
108
+ switch.sprite.width = int(width * ColorSwitch.engine.rtc.tile_width)
109
+ switch.sprite.height = int(height * ColorSwitch.engine.rtc.tile_height)
104
110
 
105
111
  return [switch]
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import logging
3
4
  from typing import List, Optional
4
5
 
5
6
  from ...scripts.commands.give_item import CommandGiveItem
@@ -14,6 +15,8 @@ from ...types.object import ObjectType
14
15
  from ..animated_sprite import AnimatedSprite
15
16
  from ..dynamic import Dynamic
16
17
 
18
+ LOG = logging.getLogger(__name__)
19
+
17
20
 
18
21
  class Container(Dynamic):
19
22
  def __init__(
@@ -26,6 +29,7 @@ class Container(Dynamic):
26
29
  graphic_state: GraphicState,
27
30
  facing_direction: Direction,
28
31
  item_name: str,
32
+ tilemap=None,
29
33
  dyn_id: int = -1,
30
34
  name: str = "Container",
31
35
  ):
@@ -36,7 +40,7 @@ class Container(Dynamic):
36
40
  f"graphic_state of Container {name}{dyn_id} must be either 'open'"
37
41
  f" or 'closed', but it {graphic_state}"
38
42
  )
39
- super().__init__(name, px, py, dyn_id)
43
+ super().__init__(px, py, name, tilemap, dyn_id)
40
44
 
41
45
  self.sprite = AnimatedSprite(
42
46
  tileset_name,
@@ -59,7 +63,6 @@ class Container(Dynamic):
59
63
  self.is_resource: bool = False
60
64
  self.amount: int = 1
61
65
 
62
- # self.sprite = AnimatedSprite("simple_sheet", "simple_sheet", "chest01")
63
66
  self._gs_map = {False: GraphicState.OPEN, True: GraphicState.CLOSED}
64
67
 
65
68
  def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
@@ -76,11 +79,11 @@ class Container(Dynamic):
76
79
  elapsed_time, self.facing_direction, self.graphic_state
77
80
  )
78
81
 
79
- def draw_self(self, ox: float, oy: float):
82
+ def draw_self(self, ox: float, oy: float, camera_name: str = "display"):
80
83
  if not self.visible:
81
84
  return
82
85
 
83
- self.sprite.draw_self(self.px - ox, self.py - oy)
86
+ self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
84
87
 
85
88
  def on_interaction(self, target: Dynamic, nature: Nature):
86
89
  if nature == Nature.SIGNAL:
@@ -114,7 +117,7 @@ class Container(Dynamic):
114
117
  elif self.item_name == "Key":
115
118
  cgr = CommandGiveResource(target, keys=self.amount)
116
119
  else:
117
- print(f"Invalid resource type: {self.item_name}")
120
+ LOG.error(f"Invalid resource type: {self.item_name}")
118
121
  return False
119
122
 
120
123
  self.engine.script.add_command(
@@ -125,10 +128,12 @@ class Container(Dynamic):
125
128
  cgr,
126
129
  ],
127
130
  CommandParallel.FIRST_COMPLETED,
128
- )
131
+ ),
132
+ players=[target.get_player()],
129
133
  )
130
134
 
131
135
  else:
136
+
132
137
  self.engine.script.add_command(
133
138
  CommandParallel(
134
139
  [
@@ -139,7 +144,8 @@ class Container(Dynamic):
139
144
  CommandGiveItem(self.item_name, target),
140
145
  ],
141
146
  CommandParallel.FIRST_COMPLETED,
142
- )
147
+ ),
148
+ players=[target.get_player()],
143
149
  )
144
150
  self.closed = False
145
151
  self.state_changed = True
@@ -148,7 +154,9 @@ class Container(Dynamic):
148
154
  return False
149
155
 
150
156
  @staticmethod
151
- def load_from_tiled_object(obj, px, py, width, height) -> List[Container]:
157
+ def load_from_tiled_object(
158
+ obj, px, py, width, height, tilemap
159
+ ) -> List[Container]:
152
160
  container = Container(
153
161
  px=px,
154
162
  py=py,
@@ -162,6 +170,7 @@ class Container(Dynamic):
162
170
  obj.get_string("facing_direction", "south").upper()
163
171
  ],
164
172
  item_name=obj.get_string("item_name"),
173
+ tilemap=tilemap,
165
174
  dyn_id=obj.object_id,
166
175
  name=obj.name,
167
176
  )
@@ -2,7 +2,6 @@ from ...types.direction import Direction
2
2
  from ...types.graphic_state import GraphicState
3
3
  from ...types.nature import Nature
4
4
  from ...types.object import ObjectType
5
- from ...util.constants import TILE_HEIGHT, TILE_WIDTH
6
5
  from ..dynamic import Dynamic
7
6
  from .switch import Switch
8
7
 
@@ -18,6 +17,7 @@ class FloorSwitch(Switch):
18
17
  facing_direction: Direction,
19
18
  graphic_state: GraphicState,
20
19
  initial_signal=True,
20
+ tilemap=None,
21
21
  dyn_id=-1,
22
22
  name="Floor Switch",
23
23
  ):
@@ -30,6 +30,7 @@ class FloorSwitch(Switch):
30
30
  facing_direction,
31
31
  graphic_state,
32
32
  initial_signal,
33
+ tilemap,
33
34
  dyn_id,
34
35
  name,
35
36
  )
@@ -79,7 +80,7 @@ class FloorSwitch(Switch):
79
80
  return False
80
81
 
81
82
  @staticmethod
82
- def load_from_tiled_object(obj, px, py, width, height):
83
+ def load_from_tiled_object(obj, px, py, width, height, tilemap):
83
84
  fswitch = FloorSwitch(
84
85
  px=px,
85
86
  py=py,
@@ -93,11 +94,14 @@ class FloorSwitch(Switch):
93
94
  obj.get_string("facing_direction", "south").upper()
94
95
  ],
95
96
  initial_signal=obj.get_bool("initial_signal", True),
97
+ tilemap=tilemap,
96
98
  dyn_id=obj.object_id,
97
99
  name=obj.name,
98
100
  )
99
- fswitch.sprite.width = int(width * TILE_WIDTH)
100
- fswitch.sprite.height = int(height * TILE_HEIGHT)
101
+ fswitch.sprite.width = int(width * FloorSwitch.engine.rtc.tile_width)
102
+ fswitch.sprite.height = int(
103
+ height * FloorSwitch.engine.rtc.tile_height
104
+ )
101
105
 
102
106
  ctr = 1
103
107
  while True:
@@ -21,7 +21,8 @@ class Gate(Dynamic):
21
21
  graphic_state: GraphicState,
22
22
  facing_direction: Direction,
23
23
  bombable: bool = False,
24
- dyn_id: int = -1,
24
+ tilemap=None,
25
+ dyn_id: int = 0,
25
26
  name: str = "Gate",
26
27
  ):
27
28
  assert graphic_state in [
@@ -33,7 +34,7 @@ class Gate(Dynamic):
33
34
  f", 'closed', or 'locked', but it {graphic_state}"
34
35
  )
35
36
 
36
- super().__init__(name, px, py, dyn_id)
37
+ super().__init__(px, py, name, tilemap, dyn_id)
37
38
 
38
39
  self.sprite = AnimatedSprite(
39
40
  tileset_name,
@@ -114,12 +115,12 @@ class Gate(Dynamic):
114
115
 
115
116
  return False
116
117
 
117
- def draw_self(self, ox: float, oy: float):
118
- self.sprite.draw_self(self.px - ox, self.py - oy)
118
+ def draw_self(self, ox: float, oy: float, camera_name: str = "display"):
119
+ self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
119
120
 
120
121
  @staticmethod
121
122
  def load_from_tiled_object(
122
- obj, px: float, py: float, width: float, height: float
123
+ obj, px: float, py: float, width: float, height: float, tilemap
123
124
  ) -> Gate:
124
125
  gate = [
125
126
  Gate(
@@ -135,6 +136,7 @@ class Gate(Dynamic):
135
136
  obj.get_string("facing_direction", "south").upper()
136
137
  ],
137
138
  bombable=obj.get_bool("bombable"),
139
+ tilemap=tilemap,
138
140
  dyn_id=obj.object_id,
139
141
  name=obj.name,
140
142
  )
@@ -162,6 +164,7 @@ class Gate(Dynamic):
162
164
  relative=False,
163
165
  sliding=False,
164
166
  vertical=False,
167
+ tilemap=tilemap,
165
168
  dyn_id=gate[0].dyn_id + 2000,
166
169
  name=f"Teleport of {gate[0].name}",
167
170
  )
@@ -4,7 +4,6 @@ from ...types.direction import Direction
4
4
  from ...types.graphic_state import GraphicState
5
5
  from ...types.nature import Nature
6
6
  from ...types.object import ObjectType
7
- from ...util.constants import TILE_HEIGHT, TILE_WIDTH
8
7
  from ..animated_sprite import AnimatedSprite
9
8
  from ..dynamic import Dynamic
10
9
  from ..effects.light import Light
@@ -22,6 +21,7 @@ class LightSource(Dynamic):
22
21
  graphic_state: GraphicState,
23
22
  facing_direction: Direction,
24
23
  max_size: int,
24
+ tilemap=None,
25
25
  dyn_id: int = -1,
26
26
  name: str = "LightSource",
27
27
  ):
@@ -29,7 +29,7 @@ class LightSource(Dynamic):
29
29
  f"graphic_state of LightSource {name}{dyn_id} must be either "
30
30
  f"'off' or 'on', but it {graphic_state}"
31
31
  )
32
- super().__init__(name, px, py, dyn_id)
32
+ super().__init__(px, py, name, tilemap, dyn_id)
33
33
 
34
34
  self.sprite = AnimatedSprite(
35
35
  tileset_name,
@@ -52,7 +52,6 @@ class LightSource(Dynamic):
52
52
  self.hitbox_height = 1.0
53
53
  self.solid_vs_dyn = True
54
54
  self.solid_vs_map = False
55
- self.onscreen_collision_skippable = True
56
55
  self._state_changed = True
57
56
 
58
57
  def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
@@ -63,7 +62,9 @@ class LightSource(Dynamic):
63
62
  if self.active:
64
63
  if self._light is None:
65
64
  self._light = Light(self, self._max_size)
66
- self.engine.scene.add_effect(self._light)
65
+ self.engine.get_view().add_effect(
66
+ self._light, self.tilemap.name
67
+ )
67
68
  else:
68
69
  if self._light is not None:
69
70
  self._light.kill()
@@ -92,15 +93,15 @@ class LightSource(Dynamic):
92
93
  self._state_changed = True
93
94
  return True
94
95
 
95
- def draw_self(self, ox: float, oy: float):
96
- self.sprite.draw_self(self.px - ox, self.py - oy)
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)
97
98
 
98
99
  def on_death(self) -> bool:
99
100
  self._light.kill()
100
101
  return True
101
102
 
102
103
  @staticmethod
103
- def load_from_tiled_object(obj, px, py, width, height):
104
+ def load_from_tiled_object(obj, px, py, width, height, tilemap):
104
105
  light = LightSource(
105
106
  px=px,
106
107
  py=py,
@@ -114,11 +115,12 @@ class LightSource(Dynamic):
114
115
  obj.get_string("facing_direction", "south").upper()
115
116
  ],
116
117
  max_size=obj.get_int("max_size", 32),
118
+ tilemap=tilemap,
117
119
  dyn_id=obj.object_id,
118
120
  name=obj.name,
119
121
  )
120
122
 
121
- light.sprite.width = int(width * TILE_WIDTH)
122
- light.sprite.height = int(height * TILE_HEIGHT)
123
+ light.sprite.width = int(width * LightSource.engine.rtc.tile_width)
124
+ light.sprite.height = int(height * LightSource.engine.rtc.tile_height)
123
125
 
124
126
  return [light]
@@ -6,7 +6,6 @@ from ...types.direction import Direction
6
6
  from ...types.graphic_state import GraphicState
7
7
  from ...types.nature import Nature
8
8
  from ...types.object import ObjectType
9
- from ...util.constants import TILE_HEIGHT, TILE_WIDTH
10
9
  from ..animated_sprite import AnimatedSprite
11
10
  from ..dynamic import Dynamic
12
11
 
@@ -36,10 +35,11 @@ class LogicGate(Dynamic):
36
35
  mode=LogicFunction.LOGIC_PASS,
37
36
  initial_signal=False,
38
37
  visible=False,
38
+ tilemap=None,
39
39
  dyn_id=-1,
40
40
  name="Logic Gate",
41
41
  ):
42
- super().__init__(name, px, py, dyn_id)
42
+ super().__init__(px, py, name, tilemap, dyn_id)
43
43
 
44
44
  self.sprite = AnimatedSprite(
45
45
  tileset_name,
@@ -116,9 +116,9 @@ class LogicGate(Dynamic):
116
116
 
117
117
  return False
118
118
 
119
- def draw_self(self, ox: float, oy: float):
119
+ def draw_self(self, ox: float, oy: float, camera_name: str = "display"):
120
120
  if self.visible:
121
- self.sprite.draw_self(self.px - ox, self.py - oy)
121
+ self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
122
122
 
123
123
  def send_signal(self, nature: Union[Nature, bool]):
124
124
  if isinstance(nature, bool):
@@ -128,7 +128,7 @@ class LogicGate(Dynamic):
128
128
  listener.on_interaction(self, nature)
129
129
 
130
130
  @staticmethod
131
- def load_from_tiled_object(obj, px, py, width, height):
131
+ def load_from_tiled_object(obj, px, py, width, height, tilemap):
132
132
  logic = LogicGate(
133
133
  px=px,
134
134
  py=py,
@@ -144,13 +144,14 @@ class LogicGate(Dynamic):
144
144
  mode=LogicFunction[obj.get_string("mode", "logic_pass").upper()],
145
145
  initial_signal=obj.get_bool("initial_signal", False),
146
146
  visible=obj.get_bool("visible", True),
147
+ tilemap=tilemap,
147
148
  dyn_id=obj.object_id,
148
149
  name=obj.name,
149
150
  )
150
151
 
151
152
  # logic.send_initial_signal =
152
- logic.sprite.width = int(width * TILE_WIDTH)
153
- logic.sprite.height = int(height * TILE_HEIGHT)
153
+ logic.sprite.width = int(width * LogicGate.engine.rtc.tile_width)
154
+ logic.sprite.height = int(height * LogicGate.engine.rtc.tile_height)
154
155
 
155
156
  ctr = 1
156
157
  while True:
@@ -9,7 +9,6 @@ from ...types.keys import Key as K
9
9
  from ...types.nature import Nature
10
10
  from ...types.object import ObjectType
11
11
  from ...util.colors import BLACK
12
- from ...util.constants import TILE_HEIGHT, TILE_WIDTH
13
12
  from ..animated_sprite import AnimatedSprite
14
13
  from ..dynamic import Dynamic
15
14
  from ..projectile import Projectile
@@ -31,10 +30,11 @@ class Movable(Dynamic):
31
30
  movable: bool,
32
31
  intangible: bool,
33
32
  force_collision_check: bool,
33
+ tilemap=None,
34
34
  dyn_id=-1,
35
35
  name="Movable",
36
36
  ):
37
- super().__init__(name, px, py, dyn_id)
37
+ super().__init__(px, py, name, tilemap, dyn_id)
38
38
 
39
39
  self.sprite = AnimatedSprite(
40
40
  tileset_name,
@@ -68,9 +68,10 @@ class Movable(Dynamic):
68
68
  self.vx_mask = 0
69
69
  self.vy_mask = 0
70
70
  self.move_direction: str = ""
71
- self.onscreen_collision_skippable = (
72
- not self.movable and not force_collision_check
73
- )
71
+ self.moves_on_collision = self.movable or self.destroyable
72
+ # self.onscreen_collision_skippable = (
73
+ # not self.movable and not force_collision_check
74
+ # )
74
75
 
75
76
  def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
76
77
  if self.intangible:
@@ -97,7 +98,9 @@ class Movable(Dynamic):
97
98
  return self._move()
98
99
 
99
100
  if self.lift_started or self.lifted:
101
+ self.moves_on_collision = True
100
102
  return self._lift()
103
+ self.moves_on_collision = self.movable or self.destroyable
101
104
 
102
105
  def on_interaction(self, target: Dynamic, nature: Nature):
103
106
  if self.moving:
@@ -105,7 +108,8 @@ class Movable(Dynamic):
105
108
  if self.lifted:
106
109
  return False
107
110
 
108
- if target.type == ObjectType.PLAYER:
111
+ pt = target.get_player()
112
+ if pt.value > 0:
109
113
  if nature == Nature.TALK and self.liftable and target.can_lift:
110
114
  self.lift_started = True
111
115
  self.actor = target
@@ -118,35 +122,32 @@ class Movable(Dynamic):
118
122
  and self.visible
119
123
  and self.total_range < self.range
120
124
  and target.graphic_state
121
- in [
122
- GraphicState.WALKING,
123
- GraphicState.PUSHING,
124
- ]
125
+ in [GraphicState.WALKING, GraphicState.PUSHING]
125
126
  ):
126
127
  if (
127
128
  target.facing_direction == Direction.WEST
128
- and self.engine.keys.key_held(K.LEFT)
129
+ and self.engine.keys.key_held(K.LEFT, pt)
129
130
  and target.vy == 0
130
131
  ):
131
132
  self.move_direction = K.LEFT
132
133
  self.vx_mask = -1
133
134
  elif (
134
135
  target.facing_direction == Direction.EAST
135
- and self.engine.keys.key_held(K.RIGHT)
136
+ and self.engine.keys.key_held(K.RIGHT, pt)
136
137
  and target.vy == 0
137
138
  ):
138
139
  self.move_direction = K.RIGHT
139
140
  self.vx_mask = 1
140
141
  elif (
141
142
  target.facing_direction == Direction.SOUTH
142
- and self.engine.keys.key_held(K.DOWN)
143
+ and self.engine.keys.key_held(K.DOWN, pt)
143
144
  and target.vx == 0
144
145
  ):
145
146
  self.move_direction = K.DOWN
146
147
  self.vy_mask = 1
147
148
  elif (
148
149
  target.facing_direction == Direction.NORTH
149
- and self.engine.keys.key_held(K.UP)
150
+ and self.engine.keys.key_held(K.UP, pt)
150
151
  and target.vx == 0
151
152
  ):
152
153
  self.move_direction = K.UP
@@ -157,6 +158,7 @@ class Movable(Dynamic):
157
158
  self.actor = target
158
159
  self.moving = True
159
160
  self.actor.lock_graphic_state(GraphicState.PUSHING)
161
+
160
162
  return True
161
163
 
162
164
  elif target.type == ObjectType.PROJECTILE:
@@ -178,7 +180,7 @@ class Movable(Dynamic):
178
180
 
179
181
  return False
180
182
 
181
- def draw_self(self, ox: float, oy: float):
183
+ def draw_self(self, ox: float, oy: float, camera_name: str = "display"):
182
184
  if not self.visible:
183
185
  return
184
186
 
@@ -190,8 +192,9 @@ class Movable(Dynamic):
190
192
  (self.py - oy + 0.7) * self.sprite.height,
191
193
  0.3125 * self.sprite.width,
192
194
  BLACK,
195
+ camera_name,
193
196
  )
194
- self.sprite.draw_self(self.px - ox, py)
197
+ self.sprite.draw_self(self.px - ox, py, camera_name)
195
198
 
196
199
  def _throw(self):
197
200
  if self.pz < 0.5:
@@ -213,11 +216,15 @@ class Movable(Dynamic):
213
216
  stop_moving = False
214
217
  for button in [K.DOWN, K.LEFT, K.UP, K.RIGHT]:
215
218
  if button == self.move_direction:
216
- if self.engine.keys.key_held(button):
219
+ if self.engine.keys.key_held(
220
+ button, self.actor.get_player()
221
+ ):
217
222
  self.vx = self.vx_mask
218
223
  self.vy = self.vy_mask
219
224
  else:
220
- if self.engine.keys.key_held(button):
225
+ if self.engine.keys.key_held(
226
+ button, self.actor.get_player()
227
+ ):
221
228
  stop_moving = True
222
229
  self.vx = 0
223
230
  self.vy = 0
@@ -252,7 +259,9 @@ class Movable(Dynamic):
252
259
  return
253
260
 
254
261
  def _lift(self):
255
- if self.lifted and self.engine.keys.new_key_press(K.A):
262
+ if self.lifted and self.engine.keys.new_key_press(
263
+ K.A, self.actor.get_player()
264
+ ):
256
265
  # Throw away
257
266
  self.vx = self.vy = 0
258
267
  if self.actor.facing_direction == Direction.SOUTH:
@@ -272,7 +281,9 @@ class Movable(Dynamic):
272
281
  self.actor = None
273
282
  self.thrown = True
274
283
 
275
- elif self.lift_started and self.engine.keys.new_key_release(K.A):
284
+ elif self.lift_started and self.engine.keys.new_key_release(
285
+ K.A, self.actor.get_player()
286
+ ):
276
287
  self.lift_started = False
277
288
  self.lifted = True
278
289
  self.solid_vs_dyn = False
@@ -286,16 +297,48 @@ class Movable(Dynamic):
286
297
  def _create_impact(self):
287
298
  impact: List[Projectile] = []
288
299
  impact.append(
289
- Projectile(self.px + 0.5, self.py + 0.5, 0, 0, 0.2, self.alignment)
300
+ Projectile(
301
+ self.px + 0.5,
302
+ self.py + 0.5,
303
+ 0,
304
+ 0,
305
+ 0.2,
306
+ self.alignment,
307
+ self.tilemap,
308
+ )
290
309
  )
291
310
  impact.append(
292
- Projectile(self.px - 0.5, self.py + 0.5, 0, 0, 0.2, self.alignment)
311
+ Projectile(
312
+ self.px - 0.5,
313
+ self.py + 0.5,
314
+ 0,
315
+ 0,
316
+ 0.2,
317
+ self.alignment,
318
+ self.tilemap,
319
+ )
293
320
  )
294
321
  impact.append(
295
- Projectile(self.px - 0.5, self.py - 0.5, 0, 0, 0.2, self.alignment)
322
+ Projectile(
323
+ self.px - 0.5,
324
+ self.py - 0.5,
325
+ 0,
326
+ 0,
327
+ 0.2,
328
+ self.alignment,
329
+ self.tilemap,
330
+ )
296
331
  )
297
332
  impact.append(
298
- Projectile(self.px + 0.5, self.py - 0.5, 0, 0, 0.2, self.alignment)
333
+ Projectile(
334
+ self.px + 0.5,
335
+ self.py - 0.5,
336
+ 0,
337
+ 0,
338
+ 0.2,
339
+ self.alignment,
340
+ self.tilemap,
341
+ )
299
342
  )
300
343
 
301
344
  for pro in impact:
@@ -303,10 +346,10 @@ class Movable(Dynamic):
303
346
  pro.solid_vs_dyn = False
304
347
  pro.solid_vs_map = False
305
348
  pro.damage = 5
306
- self.engine.scene.add_projectile(pro)
349
+ self.engine.view.add_projectile(pro, self.tilemap.name)
307
350
 
308
351
  @staticmethod
309
- def load_from_tiled_object(obj, px, py, width, height):
352
+ def load_from_tiled_object(obj, px, py, width, height, tilemap):
310
353
  movable = Movable(
311
354
  px=px,
312
355
  py=py,
@@ -325,11 +368,12 @@ class Movable(Dynamic):
325
368
  movable=obj.get_bool("movable"),
326
369
  intangible=obj.get_bool("intangible"),
327
370
  force_collision_check=obj.get_bool("force_collision_check"),
371
+ tilemap=tilemap,
328
372
  dyn_id=obj.object_id,
329
373
  name=obj.name,
330
374
  )
331
- movable.sprite.width = int(width * TILE_WIDTH)
332
- movable.sprite.height = int(height * TILE_HEIGHT)
375
+ movable.sprite.width = int(width * Movable.engine.rtc.tile_width)
376
+ movable.sprite.height = int(height * Movable.engine.rtc.tile_height)
333
377
  for dt in Damage:
334
378
  movable.attributes.defense[dt] = obj.get_int(
335
379
  f"defense_{dt.name.lower()}"