mima-engine 0.1.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 (114) hide show
  1. mima/__init__.py +1 -0
  2. mima/backend/__init__.py +1 -0
  3. mima/backend/pygame_assets.py +345 -0
  4. mima/backend/pygame_audio.py +75 -0
  5. mima/backend/pygame_backend.py +399 -0
  6. mima/backend/pygame_events.py +430 -0
  7. mima/collision.py +237 -0
  8. mima/engine.py +197 -0
  9. mima/maps/__init__.py +0 -0
  10. mima/maps/template.py +41 -0
  11. mima/maps/tile.py +20 -0
  12. mima/maps/tile_animation.py +7 -0
  13. mima/maps/tile_info.py +10 -0
  14. mima/maps/tile_layer.py +52 -0
  15. mima/maps/tiled/__init__.py +0 -0
  16. mima/maps/tiled/tiled_layer.py +48 -0
  17. mima/maps/tiled/tiled_map.py +95 -0
  18. mima/maps/tiled/tiled_object.py +79 -0
  19. mima/maps/tiled/tiled_objectgroup.py +25 -0
  20. mima/maps/tiled/tiled_template.py +49 -0
  21. mima/maps/tiled/tiled_tile.py +90 -0
  22. mima/maps/tiled/tiled_tileset.py +45 -0
  23. mima/maps/tilemap.py +159 -0
  24. mima/maps/tileset.py +32 -0
  25. mima/maps/tileset_info.py +9 -0
  26. mima/maps/transition_map.py +148 -0
  27. mima/objects/__init__.py +0 -0
  28. mima/objects/animated_sprite.py +198 -0
  29. mima/objects/attribute_effect.py +26 -0
  30. mima/objects/attributes.py +123 -0
  31. mima/objects/creature.py +332 -0
  32. mima/objects/dynamic.py +182 -0
  33. mima/objects/effects/__init__.py +0 -0
  34. mima/objects/effects/colorize_screen.py +36 -0
  35. mima/objects/effects/light.py +107 -0
  36. mima/objects/effects/walking_on_grass.py +38 -0
  37. mima/objects/effects/walking_on_water.py +41 -0
  38. mima/objects/loader.py +103 -0
  39. mima/objects/projectile.py +86 -0
  40. mima/objects/sprite.py +110 -0
  41. mima/objects/world/__init__.py +0 -0
  42. mima/objects/world/color_gate.py +68 -0
  43. mima/objects/world/color_switch.py +105 -0
  44. mima/objects/world/container.py +171 -0
  45. mima/objects/world/floor_switch.py +111 -0
  46. mima/objects/world/gate.py +174 -0
  47. mima/objects/world/light_source.py +124 -0
  48. mima/objects/world/logic_gate.py +163 -0
  49. mima/objects/world/movable.py +338 -0
  50. mima/objects/world/oneway.py +168 -0
  51. mima/objects/world/pickup.py +88 -0
  52. mima/objects/world/switch.py +165 -0
  53. mima/objects/world/teleport.py +288 -0
  54. mima/scene_engine.py +79 -0
  55. mima/scripts/__init__.py +2 -0
  56. mima/scripts/command.py +24 -0
  57. mima/scripts/commands/__init__.py +0 -0
  58. mima/scripts/commands/add_quest.py +19 -0
  59. mima/scripts/commands/change_map.py +15 -0
  60. mima/scripts/commands/close_dialog.py +8 -0
  61. mima/scripts/commands/give_item.py +24 -0
  62. mima/scripts/commands/give_resource.py +51 -0
  63. mima/scripts/commands/move_map.py +152 -0
  64. mima/scripts/commands/move_to.py +49 -0
  65. mima/scripts/commands/oneway_move.py +57 -0
  66. mima/scripts/commands/parallel.py +53 -0
  67. mima/scripts/commands/play_sound.py +13 -0
  68. mima/scripts/commands/present_item.py +51 -0
  69. mima/scripts/commands/progress_quest.py +12 -0
  70. mima/scripts/commands/quit_game.py +8 -0
  71. mima/scripts/commands/save_game.py +13 -0
  72. mima/scripts/commands/screen_fade.py +65 -0
  73. mima/scripts/commands/serial.py +46 -0
  74. mima/scripts/commands/set_facing_direction.py +21 -0
  75. mima/scripts/commands/set_spawn_map.py +14 -0
  76. mima/scripts/commands/show_choices.py +43 -0
  77. mima/scripts/commands/show_dialog.py +11 -0
  78. mima/scripts/commands/take_coins.py +23 -0
  79. mima/scripts/script_processor.py +40 -0
  80. mima/states/__init__.py +0 -0
  81. mima/states/game_state.py +162 -0
  82. mima/states/quest.py +72 -0
  83. mima/types/__init__.py +0 -0
  84. mima/types/alignment.py +7 -0
  85. mima/types/blend.py +8 -0
  86. mima/types/damage.py +42 -0
  87. mima/types/direction.py +44 -0
  88. mima/types/gate_color.py +7 -0
  89. mima/types/graphic_state.py +22 -0
  90. mima/types/keys.py +16 -0
  91. mima/types/mode.py +15 -0
  92. mima/types/nature.py +12 -0
  93. mima/types/object.py +22 -0
  94. mima/types/start.py +7 -0
  95. mima/types/terrain.py +9 -0
  96. mima/types/weapon_slot.py +6 -0
  97. mima/usables/__init__.py +0 -0
  98. mima/usables/item.py +31 -0
  99. mima/usables/weapon.py +48 -0
  100. mima/util/__init__.py +1 -0
  101. mima/util/colors.py +45 -0
  102. mima/util/constants.py +47 -0
  103. mima/util/functions.py +13 -0
  104. mima/util/input_defaults.py +49 -0
  105. mima/util/logging.py +51 -0
  106. mima/util/property.py +8 -0
  107. mima/util/runtime_config.py +133 -0
  108. mima/view/__init__.py +0 -0
  109. mima/view/camera.py +51 -0
  110. mima/view/scene.py +350 -0
  111. mima_engine-0.1.0.dist-info/METADATA +14 -0
  112. mima_engine-0.1.0.dist-info/RECORD +114 -0
  113. mima_engine-0.1.0.dist-info/WHEEL +5 -0
  114. mima_engine-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Optional
4
+
5
+ from ..command import Command
6
+
7
+ if TYPE_CHECKING:
8
+ from ...objects.dynamic import Dynamic
9
+
10
+
11
+ class CommandGiveItem(Command):
12
+ def __init__(self, item_name: str, dynamic: Optional[Dynamic] = None):
13
+ super().__init__()
14
+
15
+ self._item_name: str = item_name
16
+
17
+ if dynamic is None:
18
+ dynamic = self.engine.player
19
+
20
+ self._dynamic: Dynamic = dynamic
21
+
22
+ def start(self):
23
+ self.engine.give_item(self._item_name)
24
+ self.completed = True
@@ -0,0 +1,51 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Dict, Optional
4
+
5
+ from ..command import Command
6
+
7
+ if TYPE_CHECKING:
8
+ from ...objects.dynamic import Dynamic
9
+
10
+
11
+ class CommandGiveResource(Command):
12
+ def __init__(self, dynamic: Optional[Dynamic] = None, **resources: Dict[str, int]):
13
+ super().__init__()
14
+
15
+ if dynamic is None:
16
+ dynamic = self.engine.player
17
+
18
+ self._dynamic: Dynamic = dynamic
19
+ self._health: int = resources.get("health", 0)
20
+ self._magic: int = resources.get("magic", 0)
21
+ self._stamina: int = resources.get("stamina", 0)
22
+ self._arrows: int = resources.get("arrows", 0)
23
+ self._bombs: int = resources.get("bombs", 0)
24
+ self._coins: int = resources.get("coins", 0)
25
+ self._keys: int = resources.get("keys", 0)
26
+
27
+ def start(self):
28
+ self._dynamic.attributes.health = min(
29
+ self._dynamic.attributes.health + self._health,
30
+ self._dynamic.attributes.health_max,
31
+ )
32
+ self._dynamic.attributes.magic = min(
33
+ self._dynamic.attributes.magic + self._magic,
34
+ self._dynamic.attributes.magic_max,
35
+ )
36
+ self._dynamic.attributes.stamina = min(
37
+ self._dynamic.attributes.stamina + self._stamina,
38
+ self._dynamic.attributes.stamina_max,
39
+ )
40
+ self._dynamic.attributes.arrows = min(
41
+ self._dynamic.attributes.arrows + self._arrows,
42
+ self._dynamic.attributes.arrows_max,
43
+ )
44
+ self._dynamic.attributes.bombs = min(
45
+ self._dynamic.attributes.bombs + self._bombs,
46
+ self._dynamic.attributes.bombs_max,
47
+ )
48
+ self._dynamic.attributes.coins += self._coins
49
+ self._dynamic.attributes.keys += self._keys
50
+
51
+ self.completed = True
@@ -0,0 +1,152 @@
1
+ from ...maps.transition_map import TransitionMap
2
+ from ...objects.dynamic import Dynamic
3
+ from ...util.constants import (
4
+ HEIGHT,
5
+ MOVE_MAP_DURATION,
6
+ TILE_HEIGHT,
7
+ TILE_WIDTH,
8
+ WIDTH,
9
+ )
10
+ from ..command import Command
11
+
12
+
13
+ class CommandMoveMap(Command):
14
+ def __init__(
15
+ self,
16
+ new_map_name: str,
17
+ obj: Dynamic,
18
+ target_px: float,
19
+ target_py: float,
20
+ vx: float,
21
+ vy: float,
22
+ ):
23
+ super().__init__()
24
+
25
+ self.src_map = self.engine.scene.tilemap
26
+ self.dst_map = self.engine.assets.get_map(new_map_name)
27
+ self.obj: Dynamic = obj
28
+ self.vx: float = vx
29
+ self.vy: float = vy
30
+ self.start_px: float = 0
31
+ self.start_py: float = 0
32
+ self.start_ox: float = 0
33
+ self.start_oy: float = 0
34
+ self.target_px: float = target_px
35
+ self.target_py: float = target_py
36
+ self.target_ox: float = 0
37
+ self.target_oy: float = 0
38
+ self.final_px: float = target_px
39
+ self.final_py: float = target_py
40
+
41
+ if self.vx == 0 and self.vy == 0:
42
+ # Error
43
+ self.completed = True
44
+ self.started = True
45
+
46
+ self.duration: float = MOVE_MAP_DURATION
47
+ self.time_so_far: float = 0.0
48
+
49
+ def start(self) -> None:
50
+ # Prevent circular import
51
+ # from ...maps.transition_map import TransitionMap
52
+
53
+ self.start_ox = self._get_offset_x(self.obj.px)
54
+ self.start_oy = self._get_offset_y(self.obj.py)
55
+ self.target_ox = self._get_offset_x(self.target_px)
56
+ self.target_oy = self._get_offset_y(self.target_py)
57
+ self.start_px = self.obj.px
58
+ self.start_py = self.obj.py
59
+
60
+ # print(
61
+ # f"start_pos=({self.start_px:.1f}, {self.start_py:.1f}), "
62
+ # f"tar_pos=({self.target_px:.1f}, {self.target_py:.1f}), "
63
+ # f"start_off=({self.start_ox:.1f}, {self.start_oy:.1f}), "
64
+ # f"tar_off=({self.target_ox:.1f}, {self.target_oy:.1f})"
65
+ # )
66
+
67
+ if self.vx != 0:
68
+ if self.vx < 0:
69
+ self.target_px -= self.target_ox
70
+ else:
71
+ self.target_px += self.start_ox
72
+ self.target_py = self.start_py
73
+
74
+ elif self.vy != 0:
75
+ self.target_px = self.start_px
76
+ if self.vy < 0:
77
+ self.target_py -= self.target_oy + 1
78
+ else:
79
+ self.target_py += self.start_oy + 1
80
+
81
+ self.obj.solid_vs_dyn = False
82
+ self.obj.solid_vs_map = False
83
+ self.obj.vx = self.obj.vy = 0
84
+ self.engine.teleport_triggered = True
85
+ self.engine.scene.tilemap = TransitionMap(
86
+ self.src_map, self.dst_map, self.vx, self.vy
87
+ )
88
+ self.engine.scene.delete_map_dynamics()
89
+
90
+ def update(self, elapsed_time):
91
+ self.time_so_far += elapsed_time
92
+ rela_time = self.time_so_far / self.duration
93
+ if rela_time > 1.0:
94
+ rela_time = 1.0
95
+
96
+ self.obj.px = (
97
+ self.target_px - self.start_px
98
+ ) * rela_time + self.start_px
99
+ self.obj.py = (
100
+ self.target_py - self.start_py
101
+ ) * rela_time + self.start_py
102
+
103
+ ox = self._get_offset_x(self.obj.px)
104
+ oy = self._get_offset_y(self.obj.py)
105
+ self.obj.extra_ox = ox - self.start_ox
106
+ self.obj.extra_oy = oy - self.start_oy
107
+
108
+ if self.time_so_far >= self.duration:
109
+ self.completed = True
110
+ else:
111
+ self.engine.teleport_triggered = True
112
+
113
+ # print(f"obj_pos=({self.obj.px:.1f}, {self.obj.py:.1f})")
114
+
115
+ def finalize(self):
116
+ if self.vy != 0:
117
+ self.obj.px = self.target_px
118
+ if self.vy > 0:
119
+ self.obj.py = self.target_py - self.start_oy - 1
120
+ else:
121
+ self.obj.py = self.target_py + self.target_oy + 1
122
+
123
+ self.obj.vx = self.obj.vy = 0
124
+ self.obj.solid_vs_dyn = True
125
+ self.obj.solid_vs_map = True
126
+ self.obj.extra_ox = self.obj.extra_oy = 0
127
+ self.engine.scene.change_map(
128
+ self.dst_map.name, self.final_px, self.final_py
129
+ )
130
+
131
+ def _get_offset_x(self, px: float) -> float:
132
+ visible_tiles = WIDTH / TILE_WIDTH
133
+ offset = px - visible_tiles / 2.0
134
+
135
+ if offset < 0:
136
+ offset = 0
137
+ if offset > self.src_map.width - visible_tiles:
138
+ offset = self.src_map.width - visible_tiles
139
+
140
+ return offset
141
+
142
+ def _get_offset_y(self, py: float) -> float:
143
+ visible_tiles = HEIGHT / TILE_HEIGHT - 1
144
+ offset = py - visible_tiles / 2.0
145
+
146
+ if offset < 0:
147
+ offset = 0
148
+ if offset > self.src_map.height - visible_tiles:
149
+ offset = self.src_map.height - visible_tiles
150
+
151
+ offset -= 1
152
+ return offset
@@ -0,0 +1,49 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from ...scripts.command import Command
6
+
7
+ if TYPE_CHECKING:
8
+ from ...objects.dynamic import Dynamic
9
+
10
+
11
+ class CommandMoveTo(Command):
12
+ def __init__(
13
+ self,
14
+ obj: Dynamic,
15
+ target_px: float,
16
+ target_py: float,
17
+ duration: float = 0.0,
18
+ ):
19
+ super().__init__()
20
+
21
+ self.obj: Dynamic = obj
22
+ self.start_px: float = 0.0
23
+ self.start_py: float = 0.0
24
+ self.target_px: float = target_px
25
+ self.target_py: float = target_py
26
+
27
+ self.duration: float = max(duration, 0.001)
28
+ self.time_so_far: float = 0.0
29
+
30
+ def start(self):
31
+ self.start_px = self.obj.px
32
+ self.start_py = self.obj.py
33
+
34
+ def update(self, elapsed_time: float):
35
+ self.time_so_far += elapsed_time
36
+ relatime = min(1.0, self.time_so_far / self.duration)
37
+
38
+ self.obj.px = (self.target_px - self.start_px) * relatime + self.start_px
39
+ self.obj.py = (self.target_py - self.start_py) * relatime + self.start_py
40
+ self.obj.vx = (self.target_px - self.start_px) / self.duration
41
+ self.obj.vy = (self.target_py - self.start_py) / self.duration
42
+
43
+ if self.time_so_far >= self.duration:
44
+ self.completed = True
45
+
46
+ def finalize(self):
47
+ self.obj.px = self.target_px
48
+ self.obj.py = self.target_py
49
+ self.obj.vx = self.obj.vy = 0.0
@@ -0,0 +1,57 @@
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ from typing import TYPE_CHECKING
5
+
6
+ from ...scripts.command import Command
7
+ from ...util.constants import ONEWAY_SPEED_BOOST
8
+
9
+ if TYPE_CHECKING:
10
+ from ...objects.dynamic import Dynamic
11
+
12
+
13
+ class CommandOnewayMove(Command):
14
+ def __init__(self, obj: Dynamic, vx: float, vy: float):
15
+ super().__init__()
16
+
17
+ self.obj: Dynamic = obj
18
+ self.vx: float = vx
19
+ self.vy: float = vy
20
+ self.start_px: float = 0.0
21
+ self.start_py: float = 0.0
22
+ self.target_px: float = 0.0
23
+ self.target_py: float = 0.0
24
+ self.distance: float = 0.0
25
+
26
+ def start(self):
27
+ self.obj.solid_vs_map = False
28
+ self.obj.solid_vs_dyn = False
29
+ self.obj.vx = self.obj.vy = 0.0
30
+ self.obj.vz = 10.0
31
+
32
+ self.start_px = self.obj.px
33
+ self.start_py = self.obj.py
34
+ self.target_px = self.obj.px + self.vx
35
+ self.target_py = self.obj.py + self.vy
36
+
37
+ dx = self.target_px - self.start_px
38
+ dy = self.target_py - self.start_py
39
+ self.distance = math.sqrt(dx * dx + dy * dy)
40
+
41
+ def update(self, elapsed_time):
42
+ self.obj.px += self.vx * elapsed_time * ONEWAY_SPEED_BOOST
43
+ self.obj.py += self.vy * elapsed_time * ONEWAY_SPEED_BOOST
44
+
45
+ dx = self.obj.px - self.start_px
46
+ dy = self.obj.py - self.start_py
47
+ distance = math.sqrt(dx * dx + dy * dy)
48
+
49
+ if distance >= self.distance:
50
+ self.completed = True
51
+
52
+ def finalize(self):
53
+ self.obj.px = self.target_px
54
+ self.obj.py = self.target_py
55
+ self.obj.vx = self.obj.vy = 0.0
56
+ self.obj.solid_vs_dyn = True
57
+ self.obj.solid_vs_map = True
@@ -0,0 +1,53 @@
1
+ from typing import List
2
+ from ..command import Command
3
+
4
+
5
+ class CommandParallel(Command):
6
+ ALL_COMPLETED: int = 0
7
+ ANY_COMPLETED: int = 1
8
+ FIRST_COMPLETED: int = 2
9
+
10
+ def __init__(self, cmds: List[Command], completed_when: int = ALL_COMPLETED):
11
+ super().__init__()
12
+ self._cmds: List[Command] = cmds
13
+ self._completed_when: int = completed_when
14
+
15
+ def start(self):
16
+ for cmd in self._cmds:
17
+ cmd.start()
18
+
19
+ def update(self, delta_time):
20
+ for cmd in self._cmds:
21
+ cmd.update(delta_time)
22
+
23
+ if self._completed_when == self.ALL_COMPLETED:
24
+ self._check_for_all()
25
+ elif self._completed_when == self.ANY_COMPLETED:
26
+ self._check_for_any()
27
+ elif self._completed_when == self.FIRST_COMPLETED:
28
+ self._check_for_first()
29
+ else:
30
+ raise ValueError(
31
+ f"Unknown value {self._completed_when} for " "attribute _completed_when"
32
+ )
33
+
34
+ def finalize(self):
35
+ for cmd in self._cmds:
36
+ cmd.finalize()
37
+
38
+ def _check_for_all(self):
39
+ completed = True
40
+ for cmd in self._cmds:
41
+ completed = completed and cmd.completed
42
+
43
+ self.completed = completed
44
+
45
+ def _check_for_any(self):
46
+ completed = False
47
+ for cmd in self._cmds:
48
+ completed = completed or cmd.completed
49
+
50
+ self.completed = completed
51
+
52
+ def _check_for_first(self):
53
+ self.completed = self._cmds[0].completed
@@ -0,0 +1,13 @@
1
+ from ..command import Command
2
+
3
+
4
+ class CommandPlaySound(Command):
5
+ def __init__(self, sound: str, delay: float = 0.0):
6
+ super().__init__()
7
+
8
+ self._sound_to_play: str = sound
9
+ self._delay: float = delay
10
+
11
+ def start(self):
12
+ self.engine.audio.play_sound(self._sound_to_play, self._delay)
13
+ self.completed = True
@@ -0,0 +1,51 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Optional
4
+
5
+ from ...objects.projectile import Projectile
6
+ from ...scripts.command import Command
7
+ from ...types.graphic_state import GraphicState
8
+
9
+ if TYPE_CHECKING:
10
+ from ...objects.dynamic import Dynamic
11
+
12
+
13
+ class CommandPresentItem(Command):
14
+ def __init__(self, item_name: str, dynamic: Optional[Dynamic] = None):
15
+ super().__init__()
16
+
17
+ if dynamic is None:
18
+ dynamic = self.engine.player
19
+
20
+ self._dynamic: Dynamic = dynamic
21
+ self._item_name: str = item_name
22
+ self._item_sprite: Optional[Projectile] = None
23
+
24
+ def start(self):
25
+ item = self.engine.get_item(self._item_name)
26
+ self._item_sprite = Projectile(
27
+ self._dynamic.px,
28
+ self._dynamic.py - 1,
29
+ 0,
30
+ 0,
31
+ 3600,
32
+ self._dynamic.alignment,
33
+ )
34
+ self._item_sprite.layer = 2
35
+ self._item_sprite.sprite.name = item.sprite_name
36
+ self._item_sprite.sprite.ox = item.sprite_ox
37
+ self._item_sprite.sprite.oy = item.sprite_oy
38
+ self._item_sprite.sprite.width = item.sprite_width
39
+ self._item_sprite.sprite.height = item.sprite_height
40
+ self._item_sprite.solid_vs_dyn = False
41
+ self._item_sprite.solid_vs_map = False
42
+ self._item_sprite.one_hit = False
43
+ self._item_sprite.damage = 0
44
+
45
+ self.engine.scene.add_projectile(self._item_sprite)
46
+ self._dynamic.lock_graphic_state(GraphicState.CELEBRATING)
47
+ self.completed = True
48
+
49
+ def finalize(self):
50
+ self._item_sprite.kill()
51
+ self._dynamic.unlock_graphic_state()
@@ -0,0 +1,12 @@
1
+ from ..command import Command
2
+
3
+
4
+ class CommandProgressQuest(Command):
5
+ def __init__(self, quest_name: str, new_state: int):
6
+ super().__init__()
7
+ self._quest_name: str = quest_name
8
+ self._new_state: int = new_state
9
+
10
+ def start(self):
11
+ self.engine.progress_quest(self._quest_name, self._new_state)
12
+ self.completed = True
@@ -0,0 +1,8 @@
1
+ from ..command import Command
2
+
3
+
4
+ class CommandQuitGame(Command):
5
+ def start(self):
6
+ self.engine.game_state.save_to_disk(autosave=True)
7
+ self.engine.backend.terminate = True
8
+ self.completed = True
@@ -0,0 +1,13 @@
1
+ from ...scripts.command import Command
2
+
3
+
4
+ class CommandSaveGame(Command):
5
+ def start(self):
6
+ # print(self.engine.game_state._state["player"])
7
+ # print(self.engine.items)
8
+ for quest in self.engine.quests:
9
+ quest.save_state()
10
+ self.engine.game_state.save_to_disk()
11
+ self.completed = True
12
+
13
+ # print(self.engine.game_state._state["player"])
@@ -0,0 +1,65 @@
1
+ from typing import Optional
2
+
3
+ from ...objects.effects.colorize_screen import ColorizeScreen
4
+ from ..command import Command
5
+ from ...util.colors import BLACK,Color
6
+
7
+
8
+ class CommandScreenFade(Command):
9
+ def __init__(
10
+ self,
11
+ duration: float = 0.5,
12
+ color: Optional[Color] = None,
13
+ fadein: bool = False,
14
+ ):
15
+ super().__init__()
16
+
17
+ self.duration: float = duration
18
+ if color is None:
19
+ color = self.engine.rtc.colors["gb_dark"]
20
+
21
+ self.color: Color = color
22
+ self.fadein: bool = fadein
23
+ self.time_so_far: float = 0.0
24
+ self._start: int = 0
25
+ self._end: int = 255
26
+ self._iter: int = 15
27
+
28
+ if fadein:
29
+ self._start = 255
30
+ self._end = 0
31
+ self._iter = -self._iter
32
+
33
+ # self._alpha = chain([i for i in range(self._start, self._end, self._iter)])
34
+
35
+ self._effect = ColorizeScreen()
36
+ # self.duration -= 0.1
37
+ self._effect.alpha = self._start
38
+
39
+ def start(self):
40
+ self.engine.scene.add_effect(self._effect)
41
+ self.engine.player.vx = 0
42
+ self.engine.player.vy = 0
43
+
44
+ def update(self, elapsed_time: float):
45
+ self.time_so_far += elapsed_time
46
+
47
+ progress = self.time_so_far / self.duration
48
+
49
+ alpha = progress * 256
50
+ if self.fadein:
51
+ alpha = 255 - alpha
52
+
53
+ self._effect.alpha = min(255, max(0, alpha))
54
+ # print(self, self._effect.alpha)
55
+
56
+ self.engine.player.vx = 0
57
+ self.engine.player.vy = 0
58
+
59
+ if self.time_so_far >= self.duration:
60
+ self._effect.alpha = self._end
61
+ self.completed = True
62
+
63
+ def finalize(self):
64
+ self.completed = True
65
+ self._effect.kill()
@@ -0,0 +1,46 @@
1
+ from typing import List, Union
2
+ import logging
3
+ from ..command import Command
4
+
5
+ LOG = logging.getLogger(__name__)
6
+
7
+ class CommandSerial(Command):
8
+ START_AND_UPDATE: int = 0
9
+ START_WITHOUT_UPDATE: int = 1
10
+
11
+ def __init__(self, cmds: List[Command], update_when: Union[int, List[int]] = START_AND_UPDATE):
12
+ super().__init__()
13
+ self._cmds: List[Command] = cmds
14
+ self._current: int = 0
15
+ self._update_when: List[int]
16
+
17
+ if not isinstance(update_when, list):
18
+ self._update_when = [update_when for _ in range(len(self._cmds)-1)]
19
+ else:
20
+ self._update_when = update_when
21
+
22
+ if len(self._update_when) < len(self._cmds):
23
+ LOG.warning(
24
+ "Unsufficient information for 'update_when' of serial command:"
25
+ f"cmds={self._cmds}, update_when={self._update_when}. Using "
26
+ "default value!"
27
+ )
28
+
29
+ def start(self):
30
+ self._cmds[self._current].start()
31
+
32
+ def update(self, delta_time):
33
+ if not self._cmds[self._current].completed:
34
+ self._cmds[self._current].update(delta_time)
35
+ else:
36
+ self._current += 1
37
+ if self._current == len(self._cmds):
38
+ self.completed = True
39
+ else:
40
+ self._cmds[self._current].start()
41
+ if self._update_when[self._current-1] == self.START_AND_UPDATE:
42
+ self._cmds[self._current].update(delta_time)
43
+
44
+ def finalize(self):
45
+ for cmd in self._cmds:
46
+ cmd.finalize()
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Optional
4
+
5
+ from ...types.direction import Direction
6
+ from ..command import Command
7
+
8
+ if TYPE_CHECKING:
9
+ from ...objects.dynamic import Dynamic
10
+
11
+
12
+ class CommandSetFacingDirection(Command):
13
+ def __init__(self, dynamic: Dynamic, facing_direction: Direction):
14
+ super().__init__()
15
+
16
+ self._dynamic: Dynamic = dynamic
17
+ self._new_direction: Direction = facing_direction
18
+
19
+ def start(self):
20
+ self._dynamic.facing_direction = self._new_direction
21
+ self.completed = True
@@ -0,0 +1,14 @@
1
+ from ...scripts.command import Command
2
+
3
+
4
+ class CommandSetSavePosition(Command):
5
+ def __init__(self, map_name: str, px: float, py: float):
6
+ self._map_name = map_name
7
+ self._px = px
8
+ self._py = py
9
+
10
+ def start(self):
11
+ self.engine.player_state.save_map = self._map_name
12
+ self.engine.player_state.save_px = self._px
13
+ self.engine.player_state.save_py = self._py
14
+ self.completed = True
@@ -0,0 +1,43 @@
1
+ from typing import List
2
+ from ...scripts.command import Command
3
+ from ...types.keys import Key as K
4
+
5
+
6
+ class CommandShowChoices(Command):
7
+ def __init__(
8
+ self,
9
+ options: List[str],
10
+ replies: List[Command],
11
+ default_option: int = 0,
12
+ ):
13
+ super().__init__()
14
+
15
+ self.uninterruptible = True
16
+ self._options: List[str] = options
17
+ self._replies: List[Command] = replies
18
+ self._default_option: int = default_option
19
+
20
+ self._cursor_pos: int = 0
21
+
22
+ def update(self, elapsed_time: float):
23
+ if self.engine.keys.new_key_release(K.UP):
24
+ self._cursor_pos = (self._cursor_pos - 1) % len(self._options)
25
+ elif self.engine.keys.new_key_release(K.DOWN):
26
+ self._cursor_pos = (self._cursor_pos + 1) % len(self._options)
27
+ elif self.engine.keys.new_key_press(K.A):
28
+ self.completed = True
29
+ elif self.engine.keys.new_key_release(K.B):
30
+ self._cursor_pos = self._default_option
31
+ self.completed = True
32
+
33
+ lines = []
34
+ for idx, opt in enumerate(self._options):
35
+ if idx == self._cursor_pos:
36
+ lines.append(f"> {opt}")
37
+ else:
38
+ lines.append(f" {opt}")
39
+
40
+ self.engine.scene.show_dialog(lines)
41
+
42
+ def finalize(self):
43
+ self.engine.script.add_command(self._replies[self._cursor_pos])