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.
- mima/__init__.py +4 -0
- mima/backend/__init__.py +1 -0
- mima/backend/pygame_assets.py +401 -0
- mima/backend/pygame_audio.py +78 -0
- mima/backend/pygame_backend.py +603 -0
- mima/backend/pygame_camera.py +63 -0
- mima/backend/pygame_events.py +695 -0
- mima/backend/touch_control_scheme_a.py +126 -0
- mima/backend/touch_control_scheme_b.py +132 -0
- mima/core/__init__.py +0 -0
- mima/core/collision.py +325 -0
- mima/core/database.py +58 -0
- mima/core/engine.py +367 -0
- mima/core/mode_engine.py +81 -0
- mima/core/scene_engine.py +81 -0
- mima/integrated/__init__.py +0 -0
- mima/integrated/entity.py +183 -0
- mima/integrated/layered_map.py +351 -0
- mima/integrated/sprite.py +156 -0
- mima/layered/__init__.py +0 -0
- mima/layered/assets.py +56 -0
- mima/layered/scene.py +415 -0
- mima/layered/shape.py +99 -0
- mima/layered/shaped_sprite.py +78 -0
- mima/layered/virtual_input.py +302 -0
- mima/maps/__init__.py +0 -0
- mima/maps/template.py +71 -0
- mima/maps/tile.py +20 -0
- mima/maps/tile_animation.py +7 -0
- mima/maps/tile_info.py +10 -0
- mima/maps/tile_layer.py +52 -0
- mima/maps/tiled/__init__.py +0 -0
- mima/maps/tiled/tiled_layer.py +48 -0
- mima/maps/tiled/tiled_map.py +95 -0
- mima/maps/tiled/tiled_object.py +79 -0
- mima/maps/tiled/tiled_objectgroup.py +25 -0
- mima/maps/tiled/tiled_template.py +49 -0
- mima/maps/tiled/tiled_tile.py +90 -0
- mima/maps/tiled/tiled_tileset.py +51 -0
- mima/maps/tilemap.py +216 -0
- mima/maps/tileset.py +39 -0
- mima/maps/tileset_info.py +9 -0
- mima/maps/transition_map.py +146 -0
- mima/objects/__init__.py +0 -0
- mima/objects/animated_sprite.py +217 -0
- mima/objects/attribute_effect.py +26 -0
- mima/objects/attributes.py +126 -0
- mima/objects/creature.py +384 -0
- mima/objects/dynamic.py +206 -0
- mima/objects/effects/__init__.py +0 -0
- mima/objects/effects/colorize_screen.py +60 -0
- mima/objects/effects/debug_box.py +133 -0
- mima/objects/effects/light.py +103 -0
- mima/objects/effects/show_sprite.py +50 -0
- mima/objects/effects/walking_on_grass.py +70 -0
- mima/objects/effects/walking_on_water.py +57 -0
- mima/objects/loader.py +111 -0
- mima/objects/projectile.py +111 -0
- mima/objects/sprite.py +116 -0
- mima/objects/world/__init__.py +0 -0
- mima/objects/world/color_gate.py +67 -0
- mima/objects/world/color_switch.py +101 -0
- mima/objects/world/container.py +175 -0
- mima/objects/world/floor_switch.py +109 -0
- mima/objects/world/gate.py +178 -0
- mima/objects/world/light_source.py +121 -0
- mima/objects/world/logic_gate.py +157 -0
- mima/objects/world/movable.py +399 -0
- mima/objects/world/oneway.py +195 -0
- mima/objects/world/pickup.py +157 -0
- mima/objects/world/switch.py +179 -0
- mima/objects/world/teleport.py +308 -0
- mima/py.typed +0 -0
- mima/scripts/__init__.py +2 -0
- mima/scripts/command.py +38 -0
- mima/scripts/commands/__init__.py +0 -0
- mima/scripts/commands/add_quest.py +19 -0
- mima/scripts/commands/change_map.py +34 -0
- mima/scripts/commands/close_dialog.py +9 -0
- mima/scripts/commands/equip_weapon.py +23 -0
- mima/scripts/commands/give_item.py +26 -0
- mima/scripts/commands/give_resource.py +51 -0
- mima/scripts/commands/move_map.py +152 -0
- mima/scripts/commands/move_to.py +49 -0
- mima/scripts/commands/oneway_move.py +58 -0
- mima/scripts/commands/parallel.py +66 -0
- mima/scripts/commands/play_sound.py +13 -0
- mima/scripts/commands/present_item.py +53 -0
- mima/scripts/commands/progress_quest.py +12 -0
- mima/scripts/commands/quit_game.py +8 -0
- mima/scripts/commands/save_game.py +14 -0
- mima/scripts/commands/screen_fade.py +83 -0
- mima/scripts/commands/serial.py +69 -0
- mima/scripts/commands/set_facing_direction.py +21 -0
- mima/scripts/commands/set_spawn_map.py +17 -0
- mima/scripts/commands/show_choices.py +52 -0
- mima/scripts/commands/show_dialog.py +118 -0
- mima/scripts/commands/take_coins.py +23 -0
- mima/scripts/script_processor.py +61 -0
- mima/standalone/__init__.py +0 -0
- mima/standalone/camera.py +153 -0
- mima/standalone/geometry.py +1318 -0
- mima/standalone/multicolumn_list.py +54 -0
- mima/standalone/pixel_font.py +84 -0
- mima/standalone/scripting.py +145 -0
- mima/standalone/spatial.py +186 -0
- mima/standalone/sprite.py +158 -0
- mima/standalone/tiled_map.py +1247 -0
- mima/standalone/transformed_view.py +433 -0
- mima/standalone/user_input.py +563 -0
- mima/states/__init__.py +0 -0
- mima/states/game_state.py +189 -0
- mima/states/memory.py +28 -0
- mima/states/quest.py +71 -0
- mima/types/__init__.py +0 -0
- mima/types/alignment.py +7 -0
- mima/types/blend.py +8 -0
- mima/types/damage.py +42 -0
- mima/types/direction.py +44 -0
- mima/types/gate_color.py +7 -0
- mima/types/graphic_state.py +23 -0
- mima/types/keys.py +64 -0
- mima/types/mode.py +9 -0
- mima/types/nature.py +12 -0
- mima/types/object.py +22 -0
- mima/types/player.py +9 -0
- mima/types/position.py +13 -0
- mima/types/start.py +7 -0
- mima/types/terrain.py +9 -0
- mima/types/tile_collision.py +11 -0
- mima/types/weapon_slot.py +6 -0
- mima/types/window.py +44 -0
- mima/usables/__init__.py +0 -0
- mima/usables/item.py +51 -0
- mima/usables/weapon.py +68 -0
- mima/util/__init__.py +1 -0
- mima/util/colors.py +50 -0
- mima/util/constants.py +55 -0
- mima/util/functions.py +38 -0
- mima/util/input_defaults.py +170 -0
- mima/util/logging.py +51 -0
- mima/util/property.py +8 -0
- mima/util/runtime_config.py +327 -0
- mima/util/trading_item.py +23 -0
- mima/view/__init__.py +0 -0
- mima/view/camera.py +192 -0
- mima/view/mima_mode.py +618 -0
- mima/view/mima_scene.py +231 -0
- mima/view/mima_view.py +12 -0
- mima/view/mima_window.py +244 -0
- mima_engine-0.4.0.dist-info/METADATA +47 -0
- mima_engine-0.4.0.dist-info/RECORD +153 -0
- mima_engine-0.4.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,133 @@
|
|
|
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,
|
|
25
|
+
0,
|
|
26
|
+
"DynamicDebugBox",
|
|
27
|
+
duration=0.0,
|
|
28
|
+
alignment=Alignment.NEUTRAL,
|
|
29
|
+
tilemap=follow.tilemap,
|
|
30
|
+
)
|
|
31
|
+
self.layer = 2
|
|
32
|
+
self.sprite = None
|
|
33
|
+
|
|
34
|
+
self._follow: Dynamic = follow
|
|
35
|
+
self._color: Color = color
|
|
36
|
+
self._n_frames: int = n_frames
|
|
37
|
+
self._ids: List[int] = ids if ids is not None else follow.chunks
|
|
38
|
+
|
|
39
|
+
def update(self, elapsed_time: float, target: Dynamic = None):
|
|
40
|
+
if self._n_frames >= 0:
|
|
41
|
+
if self._n_frames == 0:
|
|
42
|
+
self.kill()
|
|
43
|
+
|
|
44
|
+
self._n_frames -= 1
|
|
45
|
+
|
|
46
|
+
def draw_self(self, ox, oy, camera_name):
|
|
47
|
+
ppx = (
|
|
48
|
+
self._follow.px - ox + self._follow.hitbox_px
|
|
49
|
+
) * self.engine.rtc.tile_width
|
|
50
|
+
ppy = (
|
|
51
|
+
self._follow.py - oy + self._follow.hitbox_py
|
|
52
|
+
) * self.engine.rtc.tile_height
|
|
53
|
+
pwidth = self._follow.hitbox_width * self.engine.rtc.tile_width
|
|
54
|
+
pheight = self._follow.hitbox_height * self.engine.rtc.tile_height
|
|
55
|
+
self.engine.backend.fill_rect(
|
|
56
|
+
ppx, ppy, pwidth, pheight, self._color, camera_name
|
|
57
|
+
)
|
|
58
|
+
txt = ""
|
|
59
|
+
for i in self._ids:
|
|
60
|
+
txt += f"{i} "
|
|
61
|
+
|
|
62
|
+
if txt:
|
|
63
|
+
txt = txt.strip()
|
|
64
|
+
text_pw = len(txt) * SMALL_FONT_WIDTH + 1
|
|
65
|
+
text_ph = SMALL_FONT_HEIGHT + 1
|
|
66
|
+
text_ppx = ppx + pwidth / 2 - text_pw / 2
|
|
67
|
+
text_ppy = ppy + pheight / 2 - text_ph / 2
|
|
68
|
+
self.engine.backend.fill_rect(
|
|
69
|
+
text_ppx - 1,
|
|
70
|
+
text_ppy - 1,
|
|
71
|
+
text_pw + 1,
|
|
72
|
+
text_ph + 1,
|
|
73
|
+
DARK_RED,
|
|
74
|
+
camera_name,
|
|
75
|
+
)
|
|
76
|
+
self.engine.backend.draw_small_text(
|
|
77
|
+
txt, text_ppx, text_ppy, camera_name=camera_name
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class StaticDebugBox(Projectile):
|
|
82
|
+
def __init__(self, px, py, width, height, color, n_frames=1, ids=None):
|
|
83
|
+
super().__init__(
|
|
84
|
+
px,
|
|
85
|
+
py,
|
|
86
|
+
"StaticDebugBox",
|
|
87
|
+
duration=0.0,
|
|
88
|
+
alignment=Alignment.NEUTRAL,
|
|
89
|
+
)
|
|
90
|
+
self.layer = 2
|
|
91
|
+
self._color = color
|
|
92
|
+
self._n_frames = n_frames
|
|
93
|
+
self._px = px
|
|
94
|
+
self._py = py
|
|
95
|
+
self._width = width
|
|
96
|
+
self._height = height
|
|
97
|
+
self._ids: List[int] = ids if ids is not None else []
|
|
98
|
+
|
|
99
|
+
def update(self, elapsed_time: float, target: Dynamic = None):
|
|
100
|
+
if self._n_frames <= 0:
|
|
101
|
+
self.kill()
|
|
102
|
+
|
|
103
|
+
self._n_frames -= 1
|
|
104
|
+
|
|
105
|
+
def draw_self(self, ox, oy, camera_name):
|
|
106
|
+
ppx = (self._px - ox) * self.engine.rtc.tile_width
|
|
107
|
+
ppy = (self._py - oy) * self.engine.rtc.tile_height
|
|
108
|
+
pwidth = self._width * self.engine.rtc.tile_width
|
|
109
|
+
pheight = self._height * self.engine.rtc.tile_height
|
|
110
|
+
self.engine.backend.fill_rect(
|
|
111
|
+
ppx, ppy, pwidth, pheight, self._color, camera_name
|
|
112
|
+
)
|
|
113
|
+
txt = ""
|
|
114
|
+
for i in self._ids:
|
|
115
|
+
txt += f"{i} "
|
|
116
|
+
|
|
117
|
+
if txt:
|
|
118
|
+
txt = txt.strip()
|
|
119
|
+
text_pw = len(txt) * self.engine.rtc.small_font_width + 1
|
|
120
|
+
text_ph = self.engine.rtc.small_font_height + 1
|
|
121
|
+
text_ppx = ppx + pwidth / 2 - text_pw / 2
|
|
122
|
+
text_ppy = ppy + pheight / 2 - text_ph / 2
|
|
123
|
+
self.engine.backend.fill_rect(
|
|
124
|
+
text_ppx - 1,
|
|
125
|
+
text_ppy - 1,
|
|
126
|
+
text_pw + 1,
|
|
127
|
+
text_ph + 1,
|
|
128
|
+
self.engine.rtc.color_dark_red,
|
|
129
|
+
camera_name,
|
|
130
|
+
)
|
|
131
|
+
self.engine.backend.draw_small_text(
|
|
132
|
+
txt, text_ppx, text_ppy, camera_name=camera_name
|
|
133
|
+
)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from ...types.alignment import Alignment
|
|
4
|
+
from ...types.blend import Blend
|
|
5
|
+
from ..dynamic import Dynamic
|
|
6
|
+
from ..projectile import Projectile
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Light(Projectile):
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
follow: Dynamic,
|
|
13
|
+
max_size: int = 64,
|
|
14
|
+
fixed_size: bool = False,
|
|
15
|
+
update_from_target: bool = False,
|
|
16
|
+
):
|
|
17
|
+
super().__init__(
|
|
18
|
+
0,
|
|
19
|
+
0,
|
|
20
|
+
name="Light",
|
|
21
|
+
tilemap=follow.tilemap,
|
|
22
|
+
duration=0,
|
|
23
|
+
alignment=Alignment.GOOD,
|
|
24
|
+
)
|
|
25
|
+
self.layer = 1
|
|
26
|
+
self.sprite.name = "light_small"
|
|
27
|
+
self.sprite.width = 48
|
|
28
|
+
self.sprite.height = 48
|
|
29
|
+
self.solid_vs_map = False
|
|
30
|
+
# self.moves_on_collision = False
|
|
31
|
+
self._follow: Dynamic = follow
|
|
32
|
+
self._fixed_size: bool = fixed_size
|
|
33
|
+
self._update_from_target: bool = update_from_target
|
|
34
|
+
|
|
35
|
+
self._timer: float = 0.2
|
|
36
|
+
self._timer_reset: float = 0.2
|
|
37
|
+
self._size_idx: int = 0
|
|
38
|
+
|
|
39
|
+
self._sizes: List[int]
|
|
40
|
+
self._max_size: int
|
|
41
|
+
|
|
42
|
+
self._prepare_light(max_size)
|
|
43
|
+
|
|
44
|
+
def update(self, elapsed_time: float, target: Dynamic = None):
|
|
45
|
+
self.px = (
|
|
46
|
+
self._follow.px
|
|
47
|
+
+ self._follow.sprite.width / self.engine.rtc.tile_width * 0.5
|
|
48
|
+
)
|
|
49
|
+
self.py = (
|
|
50
|
+
self._follow.py
|
|
51
|
+
+ self._follow.sprite.height / self.engine.rtc.tile_height * 0.5
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
rad = self._follow.light_radius()
|
|
55
|
+
if self._max_size != rad:
|
|
56
|
+
self._prepare_light(rad)
|
|
57
|
+
|
|
58
|
+
if self._follow.redundant:
|
|
59
|
+
self.kill()
|
|
60
|
+
|
|
61
|
+
if self._fixed_size:
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
self._timer -= elapsed_time
|
|
65
|
+
if self._timer <= 0.0:
|
|
66
|
+
self._timer += self._timer_reset
|
|
67
|
+
self._size_idx = (self._size_idx + 1) % len(self._sizes)
|
|
68
|
+
|
|
69
|
+
def draw_self(self, ox: float, oy: float, camera_name: str):
|
|
70
|
+
self.engine.backend.fill_circle(
|
|
71
|
+
(self.px - ox + self._follow.extra_ox)
|
|
72
|
+
* self.engine.rtc.tile_width,
|
|
73
|
+
(self.py - oy + self._follow.extra_oy)
|
|
74
|
+
* self.engine.rtc.tile_height,
|
|
75
|
+
self._sizes[self._size_idx] * 0.65, # 0.3125 *
|
|
76
|
+
self.engine.rtc.color_dark_grey,
|
|
77
|
+
camera_name,
|
|
78
|
+
blend_mode=Blend.SUB,
|
|
79
|
+
draw_to_filter=True,
|
|
80
|
+
)
|
|
81
|
+
self.engine.backend.fill_circle(
|
|
82
|
+
(self.px - ox + self._follow.extra_ox)
|
|
83
|
+
* self.engine.rtc.tile_width,
|
|
84
|
+
(self.py - oy + self._follow.extra_oy)
|
|
85
|
+
* self.engine.rtc.tile_height,
|
|
86
|
+
self._sizes[self._size_idx] * 0.5, # 0.3125 *
|
|
87
|
+
self.engine.rtc.color_very_light_grey,
|
|
88
|
+
camera_name,
|
|
89
|
+
blend_mode=Blend.SUB,
|
|
90
|
+
draw_to_filter=True,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
def _prepare_light(self, max_size):
|
|
94
|
+
self._max_size = max_size
|
|
95
|
+
self._sizes = [max_size]
|
|
96
|
+
if not self._fixed_size:
|
|
97
|
+
self._sizes.extend(
|
|
98
|
+
[
|
|
99
|
+
int(max_size * 0.97),
|
|
100
|
+
int(max_size * 0.94),
|
|
101
|
+
int(max_size * 0.97),
|
|
102
|
+
]
|
|
103
|
+
)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Optional
|
|
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
|
+
name: str = "ShowSprite",
|
|
19
|
+
*,
|
|
20
|
+
sprite_name: str = "",
|
|
21
|
+
tilemap: Optional[Tilemap] = None,
|
|
22
|
+
dyn_id: int = 0,
|
|
23
|
+
layer: int = 0,
|
|
24
|
+
):
|
|
25
|
+
super().__init__(
|
|
26
|
+
px,
|
|
27
|
+
py,
|
|
28
|
+
name,
|
|
29
|
+
sprite_name=sprite_name,
|
|
30
|
+
tilemap=tilemap,
|
|
31
|
+
dyn_id=dyn_id,
|
|
32
|
+
vx=0.0,
|
|
33
|
+
vy=0.0,
|
|
34
|
+
duration=0.0,
|
|
35
|
+
alignment=Alignment.NEUTRAL,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
self.layer = layer
|
|
39
|
+
self.draw_to_ui: bool = False
|
|
40
|
+
|
|
41
|
+
def update(self, elapsed_time: float):
|
|
42
|
+
self.sprite.update(
|
|
43
|
+
elapsed_time, self.facing_direction, self.graphic_state
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def draw_self(self, ox: float, oy: float, camera_name: str):
|
|
47
|
+
if self.sprite is None:
|
|
48
|
+
return
|
|
49
|
+
|
|
50
|
+
self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from ...types.direction import Direction
|
|
2
|
+
from ...types.graphic_state import GraphicState
|
|
3
|
+
from ..dynamic import Dynamic
|
|
4
|
+
from ..projectile import Projectile
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class WalkingOnGrass(Projectile):
|
|
8
|
+
def __init__(
|
|
9
|
+
self,
|
|
10
|
+
follow: Dynamic,
|
|
11
|
+
name: str = "WalkingOnGrass",
|
|
12
|
+
sprite_name: str = "walking_on_grass",
|
|
13
|
+
):
|
|
14
|
+
super().__init__(
|
|
15
|
+
follow.px,
|
|
16
|
+
follow.py,
|
|
17
|
+
name,
|
|
18
|
+
sprite_name=sprite_name,
|
|
19
|
+
tilemap=follow.tilemap,
|
|
20
|
+
vx=0,
|
|
21
|
+
vy=0,
|
|
22
|
+
duration=1.0,
|
|
23
|
+
alignment=follow.alignment,
|
|
24
|
+
)
|
|
25
|
+
self.layer = 0
|
|
26
|
+
# self.sprite.name = "simple_sheet"
|
|
27
|
+
# self.sprite.ox = 32
|
|
28
|
+
# self.sprite.oy = 10
|
|
29
|
+
# self.sprite.num_frames = 2
|
|
30
|
+
# self.sprite.timer = 0.2
|
|
31
|
+
# self.sprite.timer_reset = 0.2
|
|
32
|
+
self._follow = follow
|
|
33
|
+
self.renew: bool = True
|
|
34
|
+
self.solid_vs_map = False
|
|
35
|
+
# self.moves_on_collision = False
|
|
36
|
+
|
|
37
|
+
def update(self, elapsed_time: float, target: Dynamic = None):
|
|
38
|
+
if not self.renew:
|
|
39
|
+
self.kill()
|
|
40
|
+
|
|
41
|
+
self.px = (
|
|
42
|
+
self._follow.px
|
|
43
|
+
+ (self._follow.sprite.width - self.sprite.width)
|
|
44
|
+
/ 2
|
|
45
|
+
/ self.engine.rtc.tile_width
|
|
46
|
+
)
|
|
47
|
+
self.py = (
|
|
48
|
+
self._follow.py
|
|
49
|
+
+ (self._follow.sprite.height - self.sprite.height)
|
|
50
|
+
/ self.engine.rtc.tile_height
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if self._follow.graphic_state == GraphicState.WALKING:
|
|
54
|
+
self.graphic_state = GraphicState.WALKING
|
|
55
|
+
else:
|
|
56
|
+
self.graphic_state = GraphicState.STANDING
|
|
57
|
+
# elapsed_time = 0
|
|
58
|
+
self.sprite.update(elapsed_time, Direction.SOUTH, self.graphic_state)
|
|
59
|
+
|
|
60
|
+
self.renew = False
|
|
61
|
+
|
|
62
|
+
def draw_self(self, ox: float, oy: float, camera_name):
|
|
63
|
+
if (
|
|
64
|
+
self.sprite.name is None
|
|
65
|
+
or self.sprite.name == ""
|
|
66
|
+
or self.redundant
|
|
67
|
+
):
|
|
68
|
+
return
|
|
69
|
+
|
|
70
|
+
self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from ...types.direction import Direction
|
|
2
|
+
from ...types.graphic_state import GraphicState
|
|
3
|
+
from ..dynamic import Dynamic
|
|
4
|
+
from .walking_on_grass import WalkingOnGrass
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class WalkingOnWater(WalkingOnGrass):
|
|
8
|
+
def __init__(
|
|
9
|
+
self,
|
|
10
|
+
follow: Dynamic,
|
|
11
|
+
name: str = "WalkingOnWater",
|
|
12
|
+
sprite_name: str = "walking_on_water",
|
|
13
|
+
):
|
|
14
|
+
super().__init__(follow, name, sprite_name)
|
|
15
|
+
# self.sprite.name = "simple_sheet"
|
|
16
|
+
# self.sprite.ox = 32
|
|
17
|
+
# self.sprite.oy = 9
|
|
18
|
+
# self.sprite.num_frames = 2
|
|
19
|
+
# self.sprite.timer = 0.2
|
|
20
|
+
# self.sprite.timer_reset = 0.2
|
|
21
|
+
self._follow = follow
|
|
22
|
+
self.renew: bool = True
|
|
23
|
+
self.solid_vs_map = False
|
|
24
|
+
|
|
25
|
+
# def update(self, elapsed_time: float, target: Dynamic = None):
|
|
26
|
+
# if not self.renew:
|
|
27
|
+
# self.kill()
|
|
28
|
+
|
|
29
|
+
# self.px = (
|
|
30
|
+
# self._follow.px
|
|
31
|
+
# + (self._follow.sprite.width - self.sprite.width)
|
|
32
|
+
# / 2
|
|
33
|
+
# / self.engine.rtc.tile_width
|
|
34
|
+
# )
|
|
35
|
+
# self.py = (
|
|
36
|
+
# self._follow.py
|
|
37
|
+
# + (self._follow.sprite.height - self.sprite.height)
|
|
38
|
+
# / self.engine.rtc.tile_height
|
|
39
|
+
# )
|
|
40
|
+
|
|
41
|
+
# if self._follow.graphic_state == GraphicState.STANDING:
|
|
42
|
+
# elapsed_time = 0
|
|
43
|
+
# self.sprite.update(
|
|
44
|
+
# elapsed_time, Direction.SOUTH, GraphicState.STANDING
|
|
45
|
+
# )
|
|
46
|
+
|
|
47
|
+
# self.renew = False
|
|
48
|
+
|
|
49
|
+
def draw_self(self, ox: float, oy: float, camera_name: str):
|
|
50
|
+
if (
|
|
51
|
+
self.sprite.name is None
|
|
52
|
+
or self.sprite.name == ""
|
|
53
|
+
or self.redundant
|
|
54
|
+
):
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
|
mima/objects/loader.py
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from ..types.object import ObjectType
|
|
7
|
+
from .world.color_gate import ColorGate
|
|
8
|
+
from .world.color_switch import ColorSwitch
|
|
9
|
+
from .world.container import Container
|
|
10
|
+
from .world.floor_switch import FloorSwitch
|
|
11
|
+
from .world.gate import Gate
|
|
12
|
+
from .world.light_source import LightSource
|
|
13
|
+
from .world.logic_gate import LogicGate
|
|
14
|
+
from .world.movable import Movable
|
|
15
|
+
from .world.oneway import Oneway
|
|
16
|
+
from .world.pickup import Pickup
|
|
17
|
+
|
|
18
|
+
# from .world.pickup import Pickup
|
|
19
|
+
from .world.switch import Switch
|
|
20
|
+
from .world.teleport import Teleport
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from ..engine import MimaEngine
|
|
24
|
+
|
|
25
|
+
LOG = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ObjectLoader:
|
|
29
|
+
engine: MimaEngine
|
|
30
|
+
|
|
31
|
+
def __init__(self, object_dispatcher, creature_dispatcher):
|
|
32
|
+
self._base_dispatcher = {
|
|
33
|
+
"color_switch": ColorSwitch.load_from_tiled_object,
|
|
34
|
+
"color_gate": ColorGate.load_from_tiled_object,
|
|
35
|
+
"container": Container.load_from_tiled_object,
|
|
36
|
+
"floor_switch": FloorSwitch.load_from_tiled_object,
|
|
37
|
+
"gate": Gate.load_from_tiled_object,
|
|
38
|
+
"light_source": LightSource.load_from_tiled_object,
|
|
39
|
+
"logic_gate": LogicGate.load_from_tiled_object,
|
|
40
|
+
"movable": Movable.load_from_tiled_object,
|
|
41
|
+
"oneway": Oneway.load_from_tiled_object,
|
|
42
|
+
"pickup": Pickup.load_from_tiled_object,
|
|
43
|
+
"switch": Switch.load_from_tiled_object,
|
|
44
|
+
"teleport": Teleport.load_from_tiled_object,
|
|
45
|
+
"creature": self.load_creature_from_tiled_object,
|
|
46
|
+
}
|
|
47
|
+
self._cstm_object_dispatcher = object_dispatcher
|
|
48
|
+
self._cstm_creature_dispatcher = creature_dispatcher
|
|
49
|
+
# self._current_map = None
|
|
50
|
+
|
|
51
|
+
def populate_dynamics(self, tilemap, dynamics):
|
|
52
|
+
# self._current_map = tilemap
|
|
53
|
+
for obj in tilemap.objects:
|
|
54
|
+
px = obj.px / self.engine.rtc.tile_width
|
|
55
|
+
py = obj.py / self.engine.rtc.tile_height
|
|
56
|
+
width = max(obj.width / self.engine.rtc.tile_width, 1.0)
|
|
57
|
+
height = max(obj.height / self.engine.rtc.tile_height, 1.0)
|
|
58
|
+
|
|
59
|
+
LOG.debug(
|
|
60
|
+
f"Loading object {obj.name} ({obj.object_id}): {obj.type}) "
|
|
61
|
+
f"at {px, py}."
|
|
62
|
+
)
|
|
63
|
+
if obj.type in self._cstm_object_dispatcher:
|
|
64
|
+
dispatcher = self._cstm_object_dispatcher
|
|
65
|
+
else:
|
|
66
|
+
dispatcher = self._base_dispatcher
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
dynamics.extend(
|
|
70
|
+
dispatcher[obj.type](obj, px, py, width, height, tilemap)
|
|
71
|
+
)
|
|
72
|
+
except (KeyError, ValueError):
|
|
73
|
+
LOG.exception(
|
|
74
|
+
f"Failed to load '{obj.name}' ({obj.object_id}: " f"{obj.type})"
|
|
75
|
+
)
|
|
76
|
+
raise
|
|
77
|
+
|
|
78
|
+
# Connect listener IDs to actual listeners
|
|
79
|
+
for dyn in dynamics:
|
|
80
|
+
if dyn.type in [
|
|
81
|
+
ObjectType.SWITCH,
|
|
82
|
+
ObjectType.FLOOR_SWITCH,
|
|
83
|
+
ObjectType.LOGIC_GATE,
|
|
84
|
+
]:
|
|
85
|
+
for listener_id in dyn.listener_ids:
|
|
86
|
+
for listener in dynamics:
|
|
87
|
+
if listener.dyn_id == listener_id:
|
|
88
|
+
dyn.listeners.append(listener)
|
|
89
|
+
|
|
90
|
+
if listener.type == ObjectType.LOGIC_GATE:
|
|
91
|
+
if listener.input_id1 == -1:
|
|
92
|
+
listener.input_id1 = dyn.dyn_id
|
|
93
|
+
elif listener.input_id2 == -1:
|
|
94
|
+
listener.input_id2 = dyn.dyn_id
|
|
95
|
+
else:
|
|
96
|
+
LOG.warning(
|
|
97
|
+
f"Object with ID {dyn.dyn_id} "
|
|
98
|
+
"has no free input port at "
|
|
99
|
+
f"Logic Gate {listener.dyn_id}"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
def load_creature_from_tiled_object(self, obj, px, py, width, height, tilemap):
|
|
103
|
+
creature_type = obj.get_string("creature_type")
|
|
104
|
+
try:
|
|
105
|
+
return self._cstm_creature_dispatcher[creature_type](
|
|
106
|
+
obj, px, py, width, height, tilemap
|
|
107
|
+
)
|
|
108
|
+
except (KeyError, ValueError):
|
|
109
|
+
LOG.exception(f"Failed to load '{obj.name}' ({obj.object_id}: {obj.type})")
|
|
110
|
+
# raise
|
|
111
|
+
return []
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from ..types.alignment import Alignment
|
|
6
|
+
from ..types.damage import Damage
|
|
7
|
+
from ..types.object import ObjectType
|
|
8
|
+
from .dynamic import Dynamic
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from ..maps.tilemap import Tilemap
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Projectile(Dynamic):
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
px: float,
|
|
18
|
+
py: float,
|
|
19
|
+
name: str = "Projectile",
|
|
20
|
+
*,
|
|
21
|
+
sprite_name: str = "",
|
|
22
|
+
tilemap: Tilemap = None,
|
|
23
|
+
dyn_id: int = 1000,
|
|
24
|
+
vx: float = 0.0,
|
|
25
|
+
vy: float = 0.0,
|
|
26
|
+
duration: float,
|
|
27
|
+
alignment: Alignment,
|
|
28
|
+
):
|
|
29
|
+
super().__init__(
|
|
30
|
+
px,
|
|
31
|
+
py,
|
|
32
|
+
name,
|
|
33
|
+
sprite_name=sprite_name,
|
|
34
|
+
tilemap=tilemap,
|
|
35
|
+
dyn_id=dyn_id,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
self.type = ObjectType.PROJECTILE
|
|
39
|
+
self.vx = vx
|
|
40
|
+
self.vy = vy
|
|
41
|
+
self.pz = 0.5
|
|
42
|
+
self.duration = duration
|
|
43
|
+
self.alignment = alignment
|
|
44
|
+
|
|
45
|
+
self.solid_vs_dyn = False
|
|
46
|
+
self.solid_vs_map = True
|
|
47
|
+
self.is_projectile = True # redundant
|
|
48
|
+
self.attackable = False
|
|
49
|
+
self.one_hit = False
|
|
50
|
+
self.inherit_pos = False
|
|
51
|
+
self.gravity = False
|
|
52
|
+
self.moves_on_collision = True
|
|
53
|
+
self.change_solid_vs_map_timer = 0
|
|
54
|
+
self.dtype = Damage.BODY
|
|
55
|
+
self.damage = 0
|
|
56
|
+
|
|
57
|
+
def update(self, elapsed_time: float, target: Dynamic = None):
|
|
58
|
+
self.duration -= elapsed_time
|
|
59
|
+
if self.duration <= 0.0:
|
|
60
|
+
self.kill()
|
|
61
|
+
|
|
62
|
+
if self.change_solid_vs_map_timer > 0:
|
|
63
|
+
self.change_solid_vs_map_timer -= elapsed_time
|
|
64
|
+
if self.change_solid_vs_map_timer <= 0:
|
|
65
|
+
self.solid_vs_map = not self.solid_vs_map
|
|
66
|
+
self.change_solid_vs_map_timer = 0
|
|
67
|
+
|
|
68
|
+
self.speed = self.attributes.speed
|
|
69
|
+
# if "body" not in self.name:
|
|
70
|
+
# print(self.name, self.pz)
|
|
71
|
+
self.sprite.update(
|
|
72
|
+
elapsed_time, self.facing_direction, self.graphic_state
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
def draw_self(self, ox: float, oy: float, camera_name: str = "display"):
|
|
76
|
+
if (
|
|
77
|
+
self.sprite.name is None
|
|
78
|
+
or self.sprite.name == ""
|
|
79
|
+
or self.redundant
|
|
80
|
+
):
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
|
|
84
|
+
|
|
85
|
+
def on_death(self) -> bool:
|
|
86
|
+
if self.spawn_on_death:
|
|
87
|
+
for do in self.spawn_on_death:
|
|
88
|
+
if do.type == ObjectType.PROJECTILE:
|
|
89
|
+
if self.inherit_pos:
|
|
90
|
+
do.px = self.px
|
|
91
|
+
do.py = self.py
|
|
92
|
+
self.engine.get_view().add_projectile(
|
|
93
|
+
do, self.tilemap.name
|
|
94
|
+
)
|
|
95
|
+
else:
|
|
96
|
+
self.engine.get_view().add_dynamic(do, self.tilemap.name)
|
|
97
|
+
|
|
98
|
+
return False
|
|
99
|
+
|
|
100
|
+
def cancel(self):
|
|
101
|
+
if self.spawn_on_death:
|
|
102
|
+
for do in self.spawn_on_death:
|
|
103
|
+
if do.type == ObjectType.PROJECTILE:
|
|
104
|
+
do.cancel() # Projectile will kill itself
|
|
105
|
+
else:
|
|
106
|
+
do.kill()
|
|
107
|
+
self.kill()
|
|
108
|
+
return True
|
|
109
|
+
|
|
110
|
+
def __str__(self):
|
|
111
|
+
return f"P({self.name}, {self.dyn_id})"
|