mima-engine 0.1.5__py3-none-any.whl → 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mima-engine might be problematic. Click here for more details.

Files changed (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 +331 -85
  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.0.dist-info}/METADATA +4 -2
  76. mima_engine-0.2.0.dist-info/RECORD +128 -0
  77. {mima_engine-0.1.5.dist-info → mima_engine-0.2.0.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.0.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,8 @@
1
+ from typing import List, Optional
2
+
1
3
  from ...types.alignment import Alignment
2
- from ...util.colors import Color, BLACK
4
+ from ...types.player import Player
5
+ from ...util.colors import BLACK, Color
3
6
  from ...util.constants import HEIGHT, WIDTH
4
7
  from ..dynamic import Dynamic
5
8
  from ..projectile import Projectile
@@ -12,14 +15,18 @@ class ColorizeScreen(Projectile):
12
15
  alpha=BLACK.alpha,
13
16
  duration: float = -1.0,
14
17
  to_filter: bool = False,
18
+ cameras: Optional[List[str]] = None,
15
19
  ):
16
- super().__init__(0, 0, 0, 0, duration, Alignment.GOOD)
20
+ super().__init__(0, 0, 0, 0, duration, Alignment.GOOD, None)
17
21
  self.layer = 1
18
22
  self.solid_vs_map = False
19
23
  self.color = color
20
24
  self.alpha = alpha
21
25
  self.vanishs_after_time: bool = duration > 0
22
26
  self.to_filter = to_filter
27
+ self._cameras = (
28
+ cameras if (cameras is not None and cameras) else ["C_DISPLAY"]
29
+ )
23
30
 
24
31
  def update(self, elapsed_time: float, target: Dynamic = None):
25
32
  if self.vanishs_after_time:
@@ -29,8 +36,17 @@ class ColorizeScreen(Projectile):
29
36
 
30
37
  # self.sprite.update(elapsed_time, self.facing_direction, self.graphic_state)
31
38
 
32
- def draw_self(self, ox: float, oy: float):
33
- color = Color(self.color.red, self.color.green, self.color.blue, self.alpha)
34
- self.engine.backend.fill_rect(
35
- self.px, self.py, self.engine.backend.render_width, self.engine.backend.render_height, color, draw_to_filter=self.to_filter
39
+ def draw_self(self, ox: float, oy: float, camera_name=None):
40
+ color = Color(
41
+ self.color.red, self.color.green, self.color.blue, self.alpha
36
42
  )
43
+ if camera_name in self._cameras:
44
+ self.engine.backend.fill_rect(
45
+ self.px,
46
+ self.py,
47
+ self.engine.backend.render_width,
48
+ self.engine.backend.render_height,
49
+ color,
50
+ camera_name,
51
+ draw_to_filter=self.to_filter,
52
+ )
@@ -0,0 +1,124 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, List
4
+
5
+ from ...types.alignment import Alignment
6
+ from ...util.colors import DARK_RED, TRANS_LIGHT_RED
7
+ from ...util.constants import SMALL_FONT_HEIGHT, SMALL_FONT_WIDTH
8
+ from ..projectile import Projectile
9
+
10
+ if TYPE_CHECKING:
11
+ from ...util.colors import Color
12
+ from ..dynamic import Dynamic
13
+
14
+
15
+ class DynamicDebugBox(Projectile):
16
+ def __init__(
17
+ self,
18
+ follow: Dynamic,
19
+ color: Color = TRANS_LIGHT_RED,
20
+ n_frames=1,
21
+ ids=None,
22
+ ) -> None:
23
+ super().__init__(
24
+ 0, 0, 0, 0, 0, Alignment.NEUTRAL, follow.tilemap, "DynamicDebugBox"
25
+ )
26
+ self.layer = 2
27
+ self.sprite = None
28
+
29
+ self._follow: Dynamic = follow
30
+ self._color: Color = color
31
+ self._n_frames: int = n_frames
32
+ self._ids: List[int] = ids if ids is not None else follow.chunks
33
+
34
+ def update(self, elapsed_time: float, target: Dynamic = None):
35
+ if self._n_frames >= 0:
36
+ if self._n_frames == 0:
37
+ self.kill()
38
+
39
+ self._n_frames -= 1
40
+
41
+ def draw_self(self, ox, oy, camera_name):
42
+ ppx = (
43
+ self._follow.px - ox + self._follow.hitbox_px
44
+ ) * self.engine.rtc.tile_width
45
+ ppy = (
46
+ self._follow.py - oy + self._follow.hitbox_py
47
+ ) * self.engine.rtc.tile_height
48
+ pwidth = self._follow.hitbox_width * self.engine.rtc.tile_width
49
+ pheight = self._follow.hitbox_height * self.engine.rtc.tile_height
50
+ self.engine.backend.fill_rect(
51
+ ppx, ppy, pwidth, pheight, self._color, camera_name
52
+ )
53
+ txt = ""
54
+ for i in self._ids:
55
+ txt += f"{i} "
56
+
57
+ if txt:
58
+ txt = txt.strip()
59
+ text_pw = len(txt) * SMALL_FONT_WIDTH + 1
60
+ text_ph = SMALL_FONT_HEIGHT + 1
61
+ text_ppx = ppx + pwidth / 2 - text_pw / 2
62
+ text_ppy = ppy + pheight / 2 - text_ph / 2
63
+ self.engine.backend.fill_rect(
64
+ text_ppx - 1,
65
+ text_ppy - 1,
66
+ text_pw + 1,
67
+ text_ph + 1,
68
+ DARK_RED,
69
+ camera_name,
70
+ )
71
+ self.engine.backend.draw_small_text(
72
+ txt, text_ppx, text_ppy, camera_name=camera_name
73
+ )
74
+
75
+
76
+ class StaticDebugBox(Projectile):
77
+ def __init__(self, px, py, width, height, color, n_frames=1, ids=None):
78
+ super().__init__(
79
+ px, py, 0, 0, 0, Alignment.NEUTRAL, None, "StaticDebugBox"
80
+ )
81
+ self.layer = 2
82
+ self._color = color
83
+ self._n_frames = n_frames
84
+ self._px = px
85
+ self._py = py
86
+ self._width = width
87
+ self._height = height
88
+ self._ids: List[int] = ids if ids is not None else []
89
+
90
+ def update(self, elapsed_time: float, target: Dynamic = None):
91
+ if self._n_frames <= 0:
92
+ self.kill()
93
+
94
+ self._n_frames -= 1
95
+
96
+ def draw_self(self, ox, oy, camera_name):
97
+ ppx = (self._px - ox) * self.engine.rtc.tile_width
98
+ ppy = (self._py - oy) * self.engine.rtc.tile_height
99
+ pwidth = self._width * self.engine.rtc.tile_width
100
+ pheight = self._height * self.engine.rtc.tile_height
101
+ self.engine.backend.fill_rect(
102
+ ppx, ppy, pwidth, pheight, self._color, camera_name
103
+ )
104
+ txt = ""
105
+ for i in self._ids:
106
+ txt += f"{i} "
107
+
108
+ if txt:
109
+ txt = txt.strip()
110
+ text_pw = len(txt) * self.engine.rtc.small_font_width + 1
111
+ text_ph = self.engine.rtc.small_font_height + 1
112
+ text_ppx = ppx + pwidth / 2 - text_pw / 2
113
+ text_ppy = ppy + pheight / 2 - text_ph / 2
114
+ self.engine.backend.fill_rect(
115
+ text_ppx - 1,
116
+ text_ppy - 1,
117
+ text_pw + 1,
118
+ text_ph + 1,
119
+ self.engine.rtc.color_dark_red,
120
+ camera_name,
121
+ )
122
+ self.engine.backend.draw_small_text(
123
+ txt, text_ppx, text_ppy, camera_name=camera_name
124
+ )
@@ -2,8 +2,6 @@ from typing import List
2
2
 
3
3
  from ...types.alignment import Alignment
4
4
  from ...types.blend import Blend
5
- from ...util.colors import BLACK, DARK_GREY, VERY_LIGHT_GREY, WHITE
6
- from ...util.constants import TILE_HEIGHT, TILE_WIDTH
7
5
  from ..dynamic import Dynamic
8
6
  from ..projectile import Projectile
9
7
 
@@ -16,12 +14,15 @@ class Light(Projectile):
16
14
  fixed_size: bool = False,
17
15
  update_from_target: bool = False,
18
16
  ):
19
- super().__init__(0, 0, 0, 0, 0, Alignment.GOOD)
17
+ super().__init__(
18
+ 0, 0, 0, 0, 0, Alignment.GOOD, follow.tilemap, "Light"
19
+ )
20
20
  self.layer = 1
21
21
  self.sprite.name = "light_small"
22
22
  self.sprite.width = 48
23
23
  self.sprite.height = 48
24
24
  self.solid_vs_map = False
25
+ # self.moves_on_collision = False
25
26
  self._follow: Dynamic = follow
26
27
  self._fixed_size: bool = fixed_size
27
28
  self._update_from_target: bool = update_from_target
@@ -35,14 +36,14 @@ class Light(Projectile):
35
36
 
36
37
  self._prepare_light(max_size)
37
38
 
38
- # print(f"Light({id(self)}, {self.layer}, {self.sprite.name}, {self.sprite.width, self.sprite.height}, {self._follow}, {self._max_size}, {self._fixed_size}, {self._sizes}, {self._size_idx})")
39
-
40
39
  def update(self, elapsed_time: float, target: Dynamic = None):
41
40
  self.px = (
42
- self._follow.px + self._follow.sprite.width / TILE_WIDTH * 0.5
41
+ self._follow.px
42
+ + self._follow.sprite.width / self.engine.rtc.tile_width * 0.5
43
43
  )
44
44
  self.py = (
45
- self._follow.py + self._follow.sprite.height / TILE_HEIGHT * 0.5
45
+ self._follow.py
46
+ + self._follow.sprite.height / self.engine.rtc.tile_height * 0.5
46
47
  )
47
48
 
48
49
  rad = self._follow.light_radius()
@@ -60,41 +61,31 @@ class Light(Projectile):
60
61
  self._timer += self._timer_reset
61
62
  self._size_idx = (self._size_idx + 1) % len(self._sizes)
62
63
 
63
- # self.sprite.update(elapsed_time, self.facing_direction, self.graphic_state)
64
-
65
- def draw_self(self, ox: float, oy: float):
66
- # color = Color(self.color.red, self.color.green, self.color.blue, self.alpha)
67
- # self.engine.backend.fill_rect(self.px, self.py, WIDTH, HEIGHT, color)
68
- # self.engine.backend.draw_partial_sprite(
69
- # (self.px - ox) * TILE_WIDTH,
70
- # (self.py - oy) * TILE_WIDTH,
71
- # self.sprite.name,
72
- # 0,
73
- # 0,
74
- # self.sprite.width,
75
- # self.sprite.height,
76
- # draw_to_filter=True,
77
- # )
78
- # print(f"Drawing light {self} of {self._follow} at {(self.px - ox + self._follow.extra_ox) * TILE_WIDTH,(self.py - oy + self._follow.extra_oy) * TILE_HEIGHT}")
64
+ def draw_self(self, ox: float, oy: float, camera_name: str):
79
65
  self.engine.backend.fill_circle(
80
- (self.px - ox + self._follow.extra_ox) * TILE_WIDTH,
81
- (self.py - oy + self._follow.extra_oy) * TILE_HEIGHT,
66
+ (self.px - ox + self._follow.extra_ox)
67
+ * self.engine.rtc.tile_width,
68
+ (self.py - oy + self._follow.extra_oy)
69
+ * self.engine.rtc.tile_height,
82
70
  self._sizes[self._size_idx] * 0.65, # 0.3125 *
83
- DARK_GREY,
71
+ self.engine.rtc.color_dark_grey,
72
+ camera_name,
84
73
  blend_mode=Blend.SUB,
85
74
  draw_to_filter=True,
86
75
  )
87
76
  self.engine.backend.fill_circle(
88
- (self.px - ox + self._follow.extra_ox) * TILE_WIDTH,
89
- (self.py - oy + self._follow.extra_oy) * TILE_HEIGHT,
77
+ (self.px - ox + self._follow.extra_ox)
78
+ * self.engine.rtc.tile_width,
79
+ (self.py - oy + self._follow.extra_oy)
80
+ * self.engine.rtc.tile_height,
90
81
  self._sizes[self._size_idx] * 0.5, # 0.3125 *
91
- VERY_LIGHT_GREY,
82
+ self.engine.rtc.color_very_light_grey,
83
+ camera_name,
92
84
  blend_mode=Blend.SUB,
93
85
  draw_to_filter=True,
94
86
  )
95
87
 
96
88
  def _prepare_light(self, max_size):
97
-
98
89
  self._max_size = max_size
99
90
  self._sizes = [max_size]
100
91
  if not self._fixed_size:
@@ -0,0 +1,39 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from ...types.alignment import Alignment
6
+ from ..projectile import Projectile
7
+
8
+ if TYPE_CHECKING:
9
+ from ...maps.tilemap import Tilemap
10
+ from ..sprite import Sprite
11
+
12
+
13
+ class ShowSprite(Projectile):
14
+ def __init__(
15
+ self,
16
+ px: float,
17
+ py: float,
18
+ sprite: Sprite,
19
+ tilemap: Tilemap,
20
+ layer: int = 0,
21
+ dyn_id: int = 0,
22
+ ):
23
+ super().__init__(
24
+ px, py, 0.0, 0.0, 0.0, Alignment.NEUTRAL, tilemap, "SpriteEffect"
25
+ )
26
+
27
+ self.layer = layer
28
+ self.sprite: Sprite = sprite
29
+
30
+ def update(self, elapsed_time: float):
31
+ self.sprite.update(
32
+ elapsed_time, self.facing_direction, self.graphic_state
33
+ )
34
+
35
+ def draw_self(self, ox: float, oy: float, camera_name: str):
36
+ if self.sprite is None:
37
+ return
38
+
39
+ self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
@@ -6,7 +6,9 @@ from ..projectile import Projectile
6
6
 
7
7
  class WalkingOnGrass(Projectile):
8
8
  def __init__(self, follow: Dynamic):
9
- super().__init__(follow.px, follow.py, 0, 0, 1.0, follow.alignment)
9
+ super().__init__(
10
+ follow.px, follow.py, 0, 0, 1.0, follow.alignment, follow.tilemap
11
+ )
10
12
  self.layer = 0
11
13
  self.sprite.name = "simple_sheet"
12
14
  self.sprite.ox = 32
@@ -17,22 +19,38 @@ class WalkingOnGrass(Projectile):
17
19
  self._follow = follow
18
20
  self.renew: bool = True
19
21
  self.solid_vs_map = False
22
+ # self.moves_on_collision = False
20
23
 
21
24
  def update(self, elapsed_time: float, target: Dynamic = None):
22
25
  if not self.renew:
23
26
  self.kill()
24
27
 
25
- self.px = self._follow.px
26
- self.py = self._follow.py
28
+ self.px = (
29
+ self._follow.px
30
+ + (self._follow.sprite.width - self.sprite.width)
31
+ / 2
32
+ / self.engine.rtc.tile_width
33
+ )
34
+ self.py = (
35
+ self._follow.py
36
+ + (self._follow.sprite.height - self.sprite.height)
37
+ / self.engine.rtc.tile_height
38
+ )
27
39
 
28
40
  if self._follow.graphic_state == GraphicState.STANDING:
29
41
  elapsed_time = 0
30
- self.sprite.update(elapsed_time, Direction.SOUTH, GraphicState.STANDING)
42
+ self.sprite.update(
43
+ elapsed_time, Direction.SOUTH, GraphicState.STANDING
44
+ )
31
45
 
32
46
  self.renew = False
33
47
 
34
- def draw_self(self, ox: float, oy: float):
35
- if self.sprite.name is None or self.sprite.name == "" or self.redundant:
48
+ def draw_self(self, ox: float, oy: float, camera_name):
49
+ if (
50
+ self.sprite.name is None
51
+ or self.sprite.name == ""
52
+ or self.redundant
53
+ ):
36
54
  return
37
55
 
38
- self.sprite.draw_self(self.px - ox, self.py - oy)
56
+ self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
@@ -22,20 +22,31 @@ class WalkingOnWater(WalkingOnGrass):
22
22
  self.kill()
23
23
 
24
24
  self.px = (
25
- self._follow.px + self._follow.sprite.width / 2 - self.sprite.width / 2
25
+ self._follow.px
26
+ + (self._follow.sprite.width - self.sprite.width)
27
+ / 2
28
+ / self.engine.rtc.tile_width
26
29
  )
27
30
  self.py = (
28
- self._follow.py + self._follow.sprite.height / 2 - self.sprite.width / 2
31
+ self._follow.py
32
+ + (self._follow.sprite.height - self.sprite.height)
33
+ / self.engine.rtc.tile_height
29
34
  )
30
35
 
31
36
  if self._follow.graphic_state == GraphicState.STANDING:
32
37
  elapsed_time = 0
33
- self.sprite.update(elapsed_time, Direction.SOUTH, GraphicState.STANDING)
38
+ self.sprite.update(
39
+ elapsed_time, Direction.SOUTH, GraphicState.STANDING
40
+ )
34
41
 
35
42
  self.renew = False
36
43
 
37
- def draw_self(self, ox: float, oy: float):
38
- if self.sprite.name is None or self.sprite.name == "" or self.redundant:
44
+ def draw_self(self, ox: float, oy: float, camera_name: str):
45
+ if (
46
+ self.sprite.name is None
47
+ or self.sprite.name == ""
48
+ or self.redundant
49
+ ):
39
50
  return
40
51
 
41
- self.sprite.draw_self(self.px - ox, self.py - oy)
52
+ self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
mima/objects/loader.py CHANGED
@@ -1,7 +1,11 @@
1
+ from __future__ import annotations
2
+
1
3
  import logging
4
+ from typing import TYPE_CHECKING
2
5
 
3
6
  from ..types.object import ObjectType
4
- from ..util.constants import TILE_HEIGHT, TILE_WIDTH
7
+ from .world.color_gate import ColorGate
8
+ from .world.color_switch import ColorSwitch
5
9
  from .world.container import Container
6
10
  from .world.floor_switch import FloorSwitch
7
11
  from .world.gate import Gate
@@ -9,17 +13,20 @@ from .world.light_source import LightSource
9
13
  from .world.logic_gate import LogicGate
10
14
  from .world.movable import Movable
11
15
  from .world.oneway import Oneway
12
- from .world.color_switch import ColorSwitch
13
- from .world.color_gate import ColorGate
14
16
 
15
17
  # from .world.pickup import Pickup
16
18
  from .world.switch import Switch
17
19
  from .world.teleport import Teleport
18
20
 
21
+ if TYPE_CHECKING:
22
+ from ..engine import MimaEngine
23
+
19
24
  LOG = logging.getLogger(__name__)
20
25
 
21
26
 
22
27
  class ObjectLoader:
28
+ engine: MimaEngine
29
+
23
30
  def __init__(self, object_dispatcher, creature_dispatcher):
24
31
  self._base_dispatcher = {
25
32
  "color_switch": ColorSwitch.load_from_tiled_object,
@@ -42,10 +49,10 @@ class ObjectLoader:
42
49
  def populate_dynamics(self, tilemap, dynamics):
43
50
  # self._current_map = tilemap
44
51
  for obj in tilemap.objects:
45
- px = obj.px / TILE_WIDTH
46
- py = obj.py / TILE_HEIGHT
47
- width = max(obj.width / TILE_WIDTH, 1.0)
48
- height = max(obj.height / TILE_HEIGHT, 1.0)
52
+ px = obj.px / self.engine.rtc.tile_width
53
+ py = obj.py / self.engine.rtc.tile_height
54
+ width = max(obj.width / self.engine.rtc.tile_width, 1.0)
55
+ height = max(obj.height / self.engine.rtc.tile_height, 1.0)
49
56
 
50
57
  LOG.debug(
51
58
  f"Loading object {obj.name} ({obj.object_id}): {obj.type}) "
@@ -58,13 +65,14 @@ class ObjectLoader:
58
65
 
59
66
  try:
60
67
  dynamics.extend(
61
- dispatcher[obj.type](obj, px, py, width, height)
68
+ dispatcher[obj.type](obj, px, py, width, height, tilemap)
62
69
  )
63
70
  except (KeyError, ValueError):
64
71
  LOG.exception(
65
- f"Failed to load '{obj.name}' ({obj.object_id}: {obj.type})"
72
+ f"Failed to load '{obj.name}' ({obj.object_id}: "
73
+ f"{obj.type})"
66
74
  )
67
- raise
75
+ # raise
68
76
 
69
77
  # Connect listener IDs to actual listeners
70
78
  for dyn in dynamics:
@@ -90,14 +98,17 @@ class ObjectLoader:
90
98
  f"Logic Gate {listener.dyn_id}"
91
99
  )
92
100
 
93
- def load_creature_from_tiled_object(self, obj, px, py, width, height):
101
+ def load_creature_from_tiled_object(
102
+ self, obj, px, py, width, height, tilemap
103
+ ):
94
104
  creature_type = obj.get_string("creature_type")
95
105
  try:
96
106
  return self._cstm_creature_dispatcher[creature_type](
97
- obj, px, py, width, height
107
+ obj, px, py, width, height, tilemap
98
108
  )
99
109
  except (KeyError, ValueError):
100
110
  LOG.exception(
101
111
  f"Failed to load '{obj.name}' ({obj.object_id}: {obj.type})"
102
112
  )
103
- raise
113
+ # raise
114
+ return []
@@ -1,8 +1,15 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
1
5
  from ..types.alignment import Alignment
2
6
  from ..types.damage import Damage
3
7
  from ..types.object import ObjectType
4
8
  from .dynamic import Dynamic
5
9
 
10
+ if TYPE_CHECKING:
11
+ from ..maps.tilemap import Tilemap
12
+
6
13
 
7
14
  class Projectile(Dynamic):
8
15
  def __init__(
@@ -13,9 +20,10 @@ class Projectile(Dynamic):
13
20
  vy: float,
14
21
  duration: float,
15
22
  alignment: Alignment,
23
+ tilemap: Tilemap = None,
16
24
  name: str = "Projectile",
17
25
  ):
18
- super().__init__(name, px, py)
26
+ super().__init__(px, py, name, tilemap)
19
27
 
20
28
  self.type = ObjectType.PROJECTILE
21
29
  self.vx = vx
@@ -31,6 +39,7 @@ class Projectile(Dynamic):
31
39
  self.one_hit = False
32
40
  self.inherit_pos = False
33
41
  self.gravity = False
42
+ self.moves_on_collision = True
34
43
  self.change_solid_vs_map_timer = 0
35
44
  self.dtype = Damage.BODY
36
45
  self.damage = 0
@@ -47,12 +56,13 @@ class Projectile(Dynamic):
47
56
  self.change_solid_vs_map_timer = 0
48
57
 
49
58
  self.speed = self.attributes.speed
50
-
59
+ # if "body" not in self.name:
60
+ # print(self.name, self.pz)
51
61
  self.sprite.update(
52
62
  elapsed_time, self.facing_direction, self.graphic_state
53
63
  )
54
64
 
55
- def draw_self(self, ox: float, oy: float):
65
+ def draw_self(self, ox: float, oy: float, camera_name: str = "display"):
56
66
  if (
57
67
  self.sprite.name is None
58
68
  or self.sprite.name == ""
@@ -60,7 +70,7 @@ class Projectile(Dynamic):
60
70
  ):
61
71
  return
62
72
 
63
- self.sprite.draw_self(self.px - ox, self.py - oy)
73
+ self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
64
74
 
65
75
  def on_death(self) -> bool:
66
76
  if self.spawn_on_death:
@@ -69,9 +79,11 @@ class Projectile(Dynamic):
69
79
  if self.inherit_pos:
70
80
  do.px = self.px
71
81
  do.py = self.py
72
- self.engine.scene.add_projectile(do)
82
+ self.engine.get_view().add_projectile(
83
+ do, self.tilemap.name
84
+ )
73
85
  else:
74
- self.engine.scene.add_dynamic(do)
86
+ self.engine.get_view().add_dynamic(do, self.tilemap.name)
75
87
 
76
88
  return False
77
89
 
@@ -84,3 +96,6 @@ class Projectile(Dynamic):
84
96
  do.kill()
85
97
  self.kill()
86
98
  return True
99
+
100
+ def __str__(self):
101
+ return f"P({self.name}, {self.dyn_id})"
mima/objects/sprite.py CHANGED
@@ -8,20 +8,18 @@ from ..util.constants import (
8
8
  DEFAULT_GRAPHIC_TIMER_WALKING,
9
9
  DEFAULT_SPRITE_HEIGHT,
10
10
  DEFAULT_SPRITE_WIDTH,
11
- TILE_HEIGHT,
12
- TILE_WIDTH,
13
11
  )
14
12
 
15
13
 
16
14
  class Sprite:
17
15
  engine = None
18
16
 
19
- def __init__(self, name: str = ""):
17
+ def __init__(self, name: str = "", *, ox=0, oy=0, width=0, height=0):
20
18
  self.name = name
21
19
  self.ox: int = 0
22
20
  self.oy: int = 0
23
- self.width: int = DEFAULT_SPRITE_WIDTH
24
- self.height: int = DEFAULT_SPRITE_HEIGHT
21
+ self.width: int = DEFAULT_SPRITE_WIDTH if width == 0 else width
22
+ self.height: int = DEFAULT_SPRITE_HEIGHT if height == 0 else height
25
23
  self.num_frames: int = 1
26
24
  self.frame_index: int = 0
27
25
 
@@ -74,7 +72,7 @@ class Sprite:
74
72
  self.last_direction = direction
75
73
  self.last_graphic_state = graphic_state
76
74
 
77
- def draw_self(self, px: float, py: float):
75
+ def draw_self(self, px: float, py: float, camera_name: str = "display"):
78
76
  if self.name == "":
79
77
  return
80
78
 
@@ -96,13 +94,14 @@ class Sprite:
96
94
  sheet_oy = (self.oy + state_value) * self.height
97
95
 
98
96
  self.engine.backend.draw_partial_sprite(
99
- px * TILE_WIDTH,
100
- py * TILE_HEIGHT,
97
+ px * self.engine.rtc.tile_width,
98
+ py * self.engine.rtc.tile_height,
101
99
  self.name,
102
100
  sheet_ox,
103
101
  sheet_oy,
104
102
  self.width,
105
103
  self.height,
104
+ camera_name,
106
105
  )
107
106
 
108
107
  def reset(self):
@@ -21,20 +21,22 @@ class ColorGate(Gate):
21
21
  graphic_state: GraphicState,
22
22
  facing_direction: Direction,
23
23
  color: GateColor,
24
+ tilemap=None,
24
25
  dyn_id: int = -1,
25
26
  name: str = "ColorGate",
26
27
  ):
27
28
  super().__init__(
28
29
  px,
29
30
  py,
31
+ name,
30
32
  tileset_name,
31
33
  image_name,
32
34
  sprite_name,
33
35
  graphic_state,
34
36
  facing_direction,
35
37
  False,
38
+ tilemap,
36
39
  dyn_id,
37
- name,
38
40
  )
39
41
  self.color = color
40
42
  self.type = ObjectType.COLOR_GATE
@@ -47,7 +49,7 @@ class ColorGate(Gate):
47
49
  return False
48
50
 
49
51
  @staticmethod
50
- def load_from_tiled_object(obj, px, py, width, height):
52
+ def load_from_tiled_object(obj, px, py, width, height, tilemap):
51
53
  gate = ColorGate(
52
54
  px=px,
53
55
  py=py,
@@ -61,6 +63,7 @@ class ColorGate(Gate):
61
63
  obj.get_string("facing_direction", "south").upper()
62
64
  ],
63
65
  color=GateColor[obj.get_string("color", "red").upper()],
66
+ tilemap=tilemap,
64
67
  dyn_id=obj.object_id,
65
68
  name=obj.name,
66
69
  )