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,171 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import List, Optional
4
+
5
+ from ...scripts.commands.give_item import CommandGiveItem
6
+ from ...scripts.commands.give_resource import CommandGiveResource
7
+ from ...scripts.commands.parallel import CommandParallel
8
+ from ...scripts.commands.present_item import CommandPresentItem
9
+ from ...scripts.commands.show_dialog import CommandShowDialog
10
+ from ...types.direction import Direction
11
+ from ...types.graphic_state import GraphicState
12
+ from ...types.nature import Nature
13
+ from ...types.object import ObjectType
14
+ from ..animated_sprite import AnimatedSprite
15
+ from ..dynamic import Dynamic
16
+
17
+
18
+ class Container(Dynamic):
19
+ def __init__(
20
+ self,
21
+ px: float,
22
+ py: float,
23
+ tileset_name: str,
24
+ image_name: str,
25
+ sprite_name: str,
26
+ graphic_state: GraphicState,
27
+ facing_direction: Direction,
28
+ item_name: str,
29
+ dyn_id: int = -1,
30
+ name: str = "Container",
31
+ ):
32
+ assert graphic_state in [
33
+ GraphicState.OPEN,
34
+ GraphicState.CLOSED,
35
+ ], (
36
+ f"graphic_state of Container {name}{dyn_id} must be either 'open'"
37
+ f" or 'closed', but it {graphic_state}"
38
+ )
39
+ super().__init__(name, px, py, dyn_id)
40
+
41
+ self.sprite = AnimatedSprite(
42
+ tileset_name,
43
+ image_name,
44
+ sprite_name,
45
+ graphic_state,
46
+ facing_direction,
47
+ )
48
+
49
+ self.type = ObjectType.CONTAINER
50
+ self.graphic_state = graphic_state
51
+ self.facing_direction = facing_direction
52
+ self.closed: bool = self.graphic_state != GraphicState.OPEN
53
+
54
+ self.item_name: str = item_name
55
+ self.solid_vs_dyn: bool = True
56
+ self.solid_vs_map: bool = True
57
+ self.visible: bool = True
58
+
59
+ self.is_resource: bool = False
60
+ self.amount: int = 1
61
+
62
+ # self.sprite = AnimatedSprite("simple_sheet", "simple_sheet", "chest01")
63
+ self._gs_map = {False: GraphicState.OPEN, True: GraphicState.CLOSED}
64
+
65
+ def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
66
+ if self.visible:
67
+ self.solid_vs_dyn = True
68
+ else:
69
+ self.solid_vs_dyn = False
70
+
71
+ self.graphic_state = (
72
+ GraphicState.CLOSED if self.closed else GraphicState.OPEN
73
+ )
74
+
75
+ self.sprite.update(
76
+ elapsed_time, self.facing_direction, self.graphic_state
77
+ )
78
+
79
+ def draw_self(self, ox: float, oy: float):
80
+ if not self.visible:
81
+ return
82
+
83
+ self.sprite.draw_self(self.px - ox, self.py - oy)
84
+
85
+ def on_interaction(self, target: Dynamic, nature: Nature):
86
+ if nature == Nature.SIGNAL:
87
+ self.visible = True
88
+ return True
89
+
90
+ if nature == Nature.NO_SIGNAL:
91
+ self.visible = False
92
+ return True
93
+
94
+ if not self.visible:
95
+ return False
96
+
97
+ if nature == Nature.TALK:
98
+ if self.closed:
99
+ if self.is_resource:
100
+ text = "You received "
101
+ if self.amount > 1:
102
+ text += f"{self.amount} {self.item_name}s!"
103
+ elif self.amount == 1:
104
+ text += f"one {self.item_name}!"
105
+ else:
106
+ text += "nothing. The chest was empty!"
107
+
108
+ if self.item_name == "Coin":
109
+ cgr = CommandGiveResource(target, coins=self.amount)
110
+ elif self.item_name == "Bomb Refill":
111
+ cgr = CommandGiveResource(target, bombs=self.amount)
112
+ elif self.item_name == "Arrow Refill":
113
+ cgr = CommandGiveResource(target, arrows=self.amount)
114
+ elif self.item_name == "Key":
115
+ cgr = CommandGiveResource(target, keys=self.amount)
116
+ else:
117
+ print(f"Invalid resource type: {self.item_name}")
118
+ return False
119
+
120
+ self.engine.script.add_command(
121
+ CommandParallel(
122
+ [
123
+ CommandShowDialog([text]),
124
+ CommandPresentItem(self.item_name, target),
125
+ cgr,
126
+ ],
127
+ CommandParallel.FIRST_COMPLETED,
128
+ )
129
+ )
130
+
131
+ else:
132
+ self.engine.script.add_command(
133
+ CommandParallel(
134
+ [
135
+ CommandShowDialog(
136
+ [f"You received {self.item_name}"],
137
+ ),
138
+ CommandPresentItem(self.item_name, target),
139
+ CommandGiveItem(self.item_name, target),
140
+ ],
141
+ CommandParallel.FIRST_COMPLETED,
142
+ )
143
+ )
144
+ self.closed = False
145
+ self.state_changed = True
146
+ return True
147
+
148
+ return False
149
+
150
+ @staticmethod
151
+ def load_from_tiled_object(obj, px, py, width, height) -> List[Container]:
152
+ container = Container(
153
+ px=px,
154
+ py=py,
155
+ tileset_name=obj.get_string("tileset_name"),
156
+ image_name=obj.get_string("tileset_name"),
157
+ sprite_name=obj.get_string("sprite_name"),
158
+ graphic_state=GraphicState[
159
+ obj.get_string("graphic_state", "closed").upper()
160
+ ],
161
+ facing_direction=Direction[
162
+ obj.get_string("facing_direction", "south").upper()
163
+ ],
164
+ item_name=obj.get_string("item_name"),
165
+ dyn_id=obj.object_id,
166
+ name=obj.name,
167
+ )
168
+ container.is_resource = obj.get_bool("is_resource", False)
169
+ container.amount = obj.get_int("amount", 1)
170
+
171
+ return [container]
@@ -0,0 +1,111 @@
1
+ from ...types.direction import Direction
2
+ from ...types.graphic_state import GraphicState
3
+ from ...types.nature import Nature
4
+ from ...types.object import ObjectType
5
+ from ...util.constants import TILE_HEIGHT, TILE_WIDTH
6
+ from ..dynamic import Dynamic
7
+ from .switch import Switch
8
+
9
+
10
+ class FloorSwitch(Switch):
11
+ def __init__(
12
+ self,
13
+ px: float,
14
+ py: float,
15
+ tileset_name: str,
16
+ image_name: str,
17
+ sprite_name: str,
18
+ facing_direction: Direction,
19
+ graphic_state: GraphicState,
20
+ initial_signal=True,
21
+ dyn_id=-1,
22
+ name="Floor Switch",
23
+ ):
24
+ super().__init__(
25
+ px,
26
+ py,
27
+ tileset_name,
28
+ image_name,
29
+ sprite_name,
30
+ facing_direction,
31
+ graphic_state,
32
+ initial_signal,
33
+ dyn_id,
34
+ name,
35
+ )
36
+ self.layer = 0
37
+
38
+ self.type = ObjectType.FLOOR_SWITCH
39
+ self.interacted = False
40
+ self.interacted_before = False
41
+ self.solid_vs_dyn = False
42
+
43
+ def update(self, elapsed_time: float, target: Dynamic):
44
+ if self.send_initial_signal:
45
+ self.send_signal(self.signal)
46
+ self.send_initial_signal = False
47
+ self.state_changed = False
48
+ if not self.interacted:
49
+ if self.interacted_before:
50
+ self.state_changed = True
51
+ self.interacted_before = False
52
+
53
+ else:
54
+ if not self.interacted_before:
55
+ self.state_changed = True
56
+ self.interacted_before = True
57
+
58
+ self.interacted = False
59
+
60
+ if self.state_changed:
61
+ self.signal = not self.signal
62
+ self.send_signal(self.signal)
63
+
64
+ self.graphic_state = (
65
+ GraphicState.CLOSED if self.signal else GraphicState.OPEN
66
+ )
67
+ self.sprite.update(
68
+ elapsed_time, self.facing_direction, self.graphic_state
69
+ )
70
+
71
+ def on_interaction(self, target: Dynamic, nature: Nature):
72
+ if nature == Nature.WALK and not target.type == ObjectType.PROJECTILE:
73
+ if target.type == ObjectType.MOVABLE:
74
+ if not target.visible:
75
+ return False
76
+ self.interacted = True
77
+ return True
78
+
79
+ return False
80
+
81
+ @staticmethod
82
+ def load_from_tiled_object(obj, px, py, width, height):
83
+ fswitch = FloorSwitch(
84
+ px=px,
85
+ py=py,
86
+ tileset_name=obj.get_string("tileset_name"),
87
+ image_name=obj.get_string("tileset_name"),
88
+ sprite_name=obj.get_string("sprite_name"),
89
+ graphic_state=GraphicState[
90
+ obj.get_string("graphic_state", "closed").upper()
91
+ ],
92
+ facing_direction=Direction[
93
+ obj.get_string("facing_direction", "south").upper()
94
+ ],
95
+ initial_signal=obj.get_bool("initial_signal", True),
96
+ dyn_id=obj.object_id,
97
+ name=obj.name,
98
+ )
99
+ fswitch.sprite.width = int(width * TILE_WIDTH)
100
+ fswitch.sprite.height = int(height * TILE_HEIGHT)
101
+
102
+ ctr = 1
103
+ while True:
104
+ key = f"output{ctr}"
105
+ listener_id = obj.get_int(key, -1)
106
+ if listener_id < 0:
107
+ break
108
+ fswitch.listener_ids.append(listener_id)
109
+ ctr += 1
110
+
111
+ return [fswitch]
@@ -0,0 +1,174 @@
1
+ from __future__ import annotations
2
+
3
+ from ...types.damage import Damage
4
+ from ...types.direction import Direction
5
+ from ...types.graphic_state import GraphicState
6
+ from ...types.nature import Nature
7
+ from ...types.object import ObjectType
8
+ from ..animated_sprite import AnimatedSprite
9
+ from ..dynamic import Dynamic
10
+ from .teleport import Teleport
11
+
12
+
13
+ class Gate(Dynamic):
14
+ def __init__(
15
+ self,
16
+ px: float,
17
+ py: float,
18
+ tileset_name: str,
19
+ image_name: str,
20
+ sprite_name: str,
21
+ graphic_state: GraphicState,
22
+ facing_direction: Direction,
23
+ bombable: bool = False,
24
+ dyn_id: int = -1,
25
+ name: str = "Gate",
26
+ ):
27
+ assert graphic_state in [
28
+ GraphicState.OPEN,
29
+ GraphicState.CLOSED,
30
+ GraphicState.LOCKED,
31
+ ], (
32
+ f"graphic_state of Gate {name}{dyn_id} must be either 'open'"
33
+ f", 'closed', or 'locked', but it {graphic_state}"
34
+ )
35
+
36
+ super().__init__(name, px, py, dyn_id)
37
+
38
+ self.sprite = AnimatedSprite(
39
+ tileset_name,
40
+ image_name,
41
+ sprite_name,
42
+ graphic_state,
43
+ facing_direction,
44
+ )
45
+ self.type = ObjectType.GATE
46
+
47
+ self.graphic_state = graphic_state
48
+ self.facing_direction = facing_direction
49
+ self.open = self.graphic_state == GraphicState.OPEN
50
+
51
+ # self.closed_sprite_name = closed_sprite_name
52
+ # self.open_sprite_name = open_sprite_name
53
+ # self.closed_sprite_ox: float = closed_sprite_ox
54
+ # self.closed_sprite_oy: float = closed_sprite_oy
55
+ # self.open_sprite_ox: float = open_sprite_ox
56
+ # self.open_sprite_oy: float = open_sprite_oy
57
+
58
+ # self.open = open
59
+ self.bombable = bombable
60
+ self.requires_key = self.graphic_state == GraphicState.LOCKED
61
+ self.unlocked = False
62
+ self.solid_vs_map = False
63
+ self.layer = 0
64
+ self.hitbox_px = self.hitbox_py = 0.0
65
+ self.hitbox_width = self.hitbox_height = 1.0
66
+ # self._set_sprite_state()
67
+
68
+ def update(self, elapsed_time: float, target: Dynamic):
69
+ self.solid_vs_dyn = not self.open
70
+ self.graphic_state = (
71
+ GraphicState.OPEN
72
+ if self.open
73
+ else (
74
+ GraphicState.LOCKED
75
+ if self.requires_key
76
+ else GraphicState.CLOSED
77
+ )
78
+ )
79
+
80
+ self.sprite.update(
81
+ elapsed_time, self.facing_direction, self.graphic_state
82
+ )
83
+
84
+ def on_interaction(self, target: Dynamic, nature: Nature):
85
+ if nature == Nature.TALK:
86
+ if target.type == ObjectType.PLAYER:
87
+ if (
88
+ not self.open
89
+ and self.requires_key
90
+ and target.attributes.keys > 0
91
+ ):
92
+ target.attributes.keys -= 1
93
+ self.open = True
94
+ self.state_changed = True
95
+ self.unlocked = True
96
+ return True
97
+
98
+ if nature == Nature.SIGNAL:
99
+ self.open = True
100
+ self.state_changed = True
101
+ return True
102
+
103
+ if nature == Nature.NO_SIGNAL and not self.unlocked:
104
+ self.open = False
105
+ self.state_changed = True
106
+ return True
107
+
108
+ if self.bombable and target.type == ObjectType.PROJECTILE:
109
+ if target.dtype == Damage.EXPLOSION:
110
+ self.open = True
111
+ self.state_changed = True
112
+ if target.one_hit:
113
+ target.kill()
114
+
115
+ return False
116
+
117
+ def draw_self(self, ox: float, oy: float):
118
+ self.sprite.draw_self(self.px - ox, self.py - oy)
119
+
120
+ @staticmethod
121
+ def load_from_tiled_object(
122
+ obj, px: float, py: float, width: float, height: float
123
+ ) -> Gate:
124
+ gate = [
125
+ Gate(
126
+ px=px,
127
+ py=py,
128
+ tileset_name=obj.get_string("tileset_name"),
129
+ image_name=obj.get_string("tileset_name"),
130
+ sprite_name=obj.get_string("sprite_name"),
131
+ graphic_state=GraphicState[
132
+ obj.get_string("graphic_state", "closed").upper()
133
+ ],
134
+ facing_direction=Direction[
135
+ obj.get_string("facing_direction", "south").upper()
136
+ ],
137
+ bombable=obj.get_bool("bombable"),
138
+ dyn_id=obj.object_id,
139
+ name=obj.name,
140
+ )
141
+ ]
142
+
143
+ if obj.get_bool("has_teleport"):
144
+ if gate[0].facing_direction == Direction.NORTH:
145
+ py += 0.4
146
+ elif gate[0].facing_direction == Direction.SOUTH:
147
+ py -= 0.1
148
+
149
+ teleport = Teleport(
150
+ px=px,
151
+ py=py,
152
+ tileset_name="",
153
+ image_name="",
154
+ sprite_name="",
155
+ dst_map_name=obj.get_string("target_map"),
156
+ dst_px=obj.get_float("target_px"),
157
+ dst_py=obj.get_float("target_py"),
158
+ facing_direction=gate[0].facing_direction,
159
+ graphic_state=GraphicState.STANDING,
160
+ direction=gate[0].facing_direction,
161
+ invert_exit_direction=False,
162
+ relative=False,
163
+ sliding=False,
164
+ vertical=False,
165
+ dyn_id=gate[0].dyn_id + 2000,
166
+ name=f"Teleport of {gate[0].name}",
167
+ )
168
+
169
+ teleport.visible = False
170
+ teleport.sfx_on_trigger = "pass_door"
171
+
172
+ gate.append(teleport)
173
+
174
+ return gate
@@ -0,0 +1,124 @@
1
+ from typing import Optional
2
+
3
+ from ...types.direction import Direction
4
+ from ...types.graphic_state import GraphicState
5
+ from ...types.nature import Nature
6
+ from ...types.object import ObjectType
7
+ from ...util.constants import TILE_HEIGHT, TILE_WIDTH
8
+ from ..animated_sprite import AnimatedSprite
9
+ from ..dynamic import Dynamic
10
+ from ..effects.light import Light
11
+ from ..projectile import Projectile
12
+
13
+
14
+ class LightSource(Dynamic):
15
+ def __init__(
16
+ self,
17
+ px: float,
18
+ py: float,
19
+ tileset_name: str,
20
+ image_name: str,
21
+ sprite_name: str,
22
+ graphic_state: GraphicState,
23
+ facing_direction: Direction,
24
+ max_size: int,
25
+ dyn_id: int = -1,
26
+ name: str = "LightSource",
27
+ ):
28
+ assert graphic_state in [GraphicState.OFF, GraphicState.ON], (
29
+ f"graphic_state of LightSource {name}{dyn_id} must be either "
30
+ f"'off' or 'on', but it {graphic_state}"
31
+ )
32
+ super().__init__(name, px, py, dyn_id)
33
+
34
+ self.sprite = AnimatedSprite(
35
+ tileset_name,
36
+ image_name,
37
+ sprite_name,
38
+ graphic_state,
39
+ facing_direction,
40
+ )
41
+
42
+ self.type = ObjectType.LIGHT_SOURCE
43
+ self.graphic_state = graphic_state
44
+ self.facing_direction = facing_direction
45
+ self._max_size = max_size
46
+ self.active = self.graphic_state == GraphicState.ON
47
+ self._light: Optional[Projectile] = None
48
+
49
+ self.hitbox_px = 0.0
50
+ self.hitbox_py = 0.0
51
+ self.hitbox_width = 1.0
52
+ self.hitbox_height = 1.0
53
+ self.solid_vs_dyn = True
54
+ self.solid_vs_map = False
55
+ self.onscreen_collision_skippable = True
56
+ self._state_changed = True
57
+
58
+ def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
59
+ if self._state_changed:
60
+ # self._set_sprite_state()
61
+ self._state_changed = False
62
+
63
+ if self.active:
64
+ if self._light is None:
65
+ self._light = Light(self, self._max_size)
66
+ self.engine.scene.add_effect(self._light)
67
+ else:
68
+ if self._light is not None:
69
+ self._light.kill()
70
+ self._light = None
71
+
72
+ self.graphic_state = (
73
+ GraphicState.ON if self.active else GraphicState.OFF
74
+ )
75
+ self.sprite.update(
76
+ elapsed_time, self.facing_direction, self.graphic_state
77
+ )
78
+
79
+ def on_interaction(self, target: Dynamic, nature: Nature):
80
+ if nature == Nature.SIGNAL:
81
+ self.active = True
82
+ self._state_changed = True
83
+ return True
84
+
85
+ if nature == Nature.NO_SIGNAL:
86
+ self.active = False
87
+ self._state_changed = True
88
+ return True
89
+
90
+ if nature == Nature.TALK:
91
+ self.active = not self.active
92
+ self._state_changed = True
93
+ return True
94
+
95
+ def draw_self(self, ox: float, oy: float):
96
+ self.sprite.draw_self(self.px - ox, self.py - oy)
97
+
98
+ def on_death(self) -> bool:
99
+ self._light.kill()
100
+ return True
101
+
102
+ @staticmethod
103
+ def load_from_tiled_object(obj, px, py, width, height):
104
+ light = LightSource(
105
+ px=px,
106
+ py=py,
107
+ tileset_name=obj.get_string("tileset_name"),
108
+ image_name=obj.get_string("tileset_name"),
109
+ sprite_name=obj.get_string("sprite_name"),
110
+ graphic_state=GraphicState[
111
+ obj.get_string("graphic_state", "closed").upper()
112
+ ],
113
+ facing_direction=Direction[
114
+ obj.get_string("facing_direction", "south").upper()
115
+ ],
116
+ max_size=obj.get_int("max_size", 32),
117
+ dyn_id=obj.object_id,
118
+ name=obj.name,
119
+ )
120
+
121
+ light.sprite.width = int(width * TILE_WIDTH)
122
+ light.sprite.height = int(height * TILE_HEIGHT)
123
+
124
+ return [light]