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,178 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from ...maps.tilemap import Tilemap
|
|
6
|
+
from ...types.damage import Damage
|
|
7
|
+
from ...types.direction import Direction
|
|
8
|
+
from ...types.graphic_state import GraphicState
|
|
9
|
+
from ...types.nature import Nature
|
|
10
|
+
from ...types.object import ObjectType
|
|
11
|
+
from ..animated_sprite import AnimatedSprite
|
|
12
|
+
from ..dynamic import Dynamic
|
|
13
|
+
from .teleport import Teleport
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Gate(Dynamic):
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
px: float,
|
|
20
|
+
py: float,
|
|
21
|
+
name: str = "Gate",
|
|
22
|
+
*,
|
|
23
|
+
sprite_name: str = "",
|
|
24
|
+
tilemap: Optional[Tilemap] = None,
|
|
25
|
+
dyn_id: int = 0,
|
|
26
|
+
graphic_state: GraphicState = GraphicState.STANDING,
|
|
27
|
+
facing_direction: Direction = Direction.SOUTH,
|
|
28
|
+
bombable: bool = False,
|
|
29
|
+
):
|
|
30
|
+
if graphic_state not in (
|
|
31
|
+
GraphicState.OPEN,
|
|
32
|
+
GraphicState.CLOSED,
|
|
33
|
+
GraphicState.LOCKED,
|
|
34
|
+
):
|
|
35
|
+
msg = (
|
|
36
|
+
f"graphic_state of Gate {name}{dyn_id} must be either 'open'"
|
|
37
|
+
f", 'closed', or 'locked', but it {graphic_state}"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
raise ValueError(msg)
|
|
41
|
+
|
|
42
|
+
super().__init__(
|
|
43
|
+
px,
|
|
44
|
+
py,
|
|
45
|
+
name,
|
|
46
|
+
tilemap=tilemap,
|
|
47
|
+
sprite_name=sprite_name,
|
|
48
|
+
dyn_id=dyn_id,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
self.type = ObjectType.GATE
|
|
52
|
+
|
|
53
|
+
self.graphic_state = graphic_state
|
|
54
|
+
self.facing_direction = facing_direction
|
|
55
|
+
self.open = self.graphic_state == GraphicState.OPEN
|
|
56
|
+
|
|
57
|
+
# self.closed_sprite_name = closed_sprite_name
|
|
58
|
+
# self.open_sprite_name = open_sprite_name
|
|
59
|
+
# self.closed_sprite_ox: float = closed_sprite_ox
|
|
60
|
+
# self.closed_sprite_oy: float = closed_sprite_oy
|
|
61
|
+
# self.open_sprite_ox: float = open_sprite_ox
|
|
62
|
+
# self.open_sprite_oy: float = open_sprite_oy
|
|
63
|
+
|
|
64
|
+
# self.open = open
|
|
65
|
+
self.bombable = bombable
|
|
66
|
+
self.requires_key = self.graphic_state == GraphicState.LOCKED
|
|
67
|
+
self.unlocked = False
|
|
68
|
+
self.solid_vs_map = False
|
|
69
|
+
self.layer = 0
|
|
70
|
+
self.hitbox_px = self.hitbox_py = 0.0
|
|
71
|
+
self.hitbox_width = self.hitbox_height = 1.0
|
|
72
|
+
# self._set_sprite_state()
|
|
73
|
+
|
|
74
|
+
def update(self, elapsed_time: float, target: Dynamic):
|
|
75
|
+
self.solid_vs_dyn = not self.open
|
|
76
|
+
self.graphic_state = (
|
|
77
|
+
GraphicState.OPEN
|
|
78
|
+
if self.open
|
|
79
|
+
else (
|
|
80
|
+
GraphicState.LOCKED
|
|
81
|
+
if self.requires_key
|
|
82
|
+
else GraphicState.CLOSED
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
self.sprite.update(
|
|
87
|
+
elapsed_time, self.facing_direction, self.graphic_state
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
def on_interaction(self, target: Dynamic, nature: Nature):
|
|
91
|
+
if nature == Nature.TALK:
|
|
92
|
+
if target.type == ObjectType.PLAYER:
|
|
93
|
+
if (
|
|
94
|
+
not self.open
|
|
95
|
+
and self.requires_key
|
|
96
|
+
and target.attributes.keys > 0
|
|
97
|
+
):
|
|
98
|
+
target.attributes.keys -= 1
|
|
99
|
+
self.open = True
|
|
100
|
+
self.state_changed = True
|
|
101
|
+
self.unlocked = True
|
|
102
|
+
return True
|
|
103
|
+
|
|
104
|
+
if nature == Nature.SIGNAL:
|
|
105
|
+
self.open = True
|
|
106
|
+
self.state_changed = True
|
|
107
|
+
return True
|
|
108
|
+
|
|
109
|
+
if nature == Nature.NO_SIGNAL and not self.unlocked:
|
|
110
|
+
self.open = False
|
|
111
|
+
self.state_changed = True
|
|
112
|
+
return True
|
|
113
|
+
|
|
114
|
+
if self.bombable and target.type == ObjectType.PROJECTILE:
|
|
115
|
+
if target.dtype == Damage.EXPLOSION:
|
|
116
|
+
self.open = True
|
|
117
|
+
self.state_changed = True
|
|
118
|
+
if target.one_hit:
|
|
119
|
+
target.kill()
|
|
120
|
+
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
def draw_self(self, ox: float, oy: float, camera_name: str = "display"):
|
|
124
|
+
self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
|
|
125
|
+
|
|
126
|
+
@staticmethod
|
|
127
|
+
def load_from_tiled_object(
|
|
128
|
+
obj, px: float, py: float, width: float, height: float, tilemap
|
|
129
|
+
) -> Gate:
|
|
130
|
+
gate = [
|
|
131
|
+
Gate(
|
|
132
|
+
px=px,
|
|
133
|
+
py=py,
|
|
134
|
+
name=obj.name,
|
|
135
|
+
sprite_name=obj.get_string("sprite_name"),
|
|
136
|
+
tilemap=tilemap,
|
|
137
|
+
dyn_id=obj.object_id,
|
|
138
|
+
graphic_state=GraphicState[
|
|
139
|
+
obj.get_string("graphic_state", "closed").upper()
|
|
140
|
+
],
|
|
141
|
+
facing_direction=Direction[
|
|
142
|
+
obj.get_string("facing_direction", "south").upper()
|
|
143
|
+
],
|
|
144
|
+
bombable=obj.get_bool("bombable"),
|
|
145
|
+
)
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
if obj.get_bool("has_teleport"):
|
|
149
|
+
if gate[0].facing_direction == Direction.NORTH:
|
|
150
|
+
py += 0.4
|
|
151
|
+
elif gate[0].facing_direction == Direction.SOUTH:
|
|
152
|
+
py -= 0.1
|
|
153
|
+
|
|
154
|
+
teleport = Teleport(
|
|
155
|
+
px,
|
|
156
|
+
py,
|
|
157
|
+
f"Teleport of {gate[0].name}",
|
|
158
|
+
sprite_name="",
|
|
159
|
+
tilemap=tilemap,
|
|
160
|
+
dyn_id=gate[0].dyn_id + 2000,
|
|
161
|
+
dst_map_name=obj.get_string("target_map"),
|
|
162
|
+
dst_px=obj.get_float("target_px"),
|
|
163
|
+
dst_py=obj.get_float("target_py"),
|
|
164
|
+
facing_direction=gate[0].facing_direction,
|
|
165
|
+
graphic_state=GraphicState.STANDING,
|
|
166
|
+
direction=gate[0].facing_direction,
|
|
167
|
+
invert_exit_direction=False,
|
|
168
|
+
relative=False,
|
|
169
|
+
sliding=False,
|
|
170
|
+
vertical=False,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
teleport.visible = False
|
|
174
|
+
teleport.sfx_on_trigger = "pass_door"
|
|
175
|
+
|
|
176
|
+
gate.append(teleport)
|
|
177
|
+
|
|
178
|
+
return gate
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from ...maps.tilemap import Tilemap
|
|
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 ..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
|
+
name: str = "LightSource",
|
|
20
|
+
*,
|
|
21
|
+
sprite_name: str = "",
|
|
22
|
+
tilemap: Optional[Tilemap] = None,
|
|
23
|
+
dyn_id: int = -1,
|
|
24
|
+
graphic_state: GraphicState = GraphicState.ON,
|
|
25
|
+
max_size: int = 32,
|
|
26
|
+
):
|
|
27
|
+
if graphic_state not in [GraphicState.OFF, GraphicState.ON]:
|
|
28
|
+
msg = (
|
|
29
|
+
f"graphic_state of LightSource {name}{dyn_id} must be either "
|
|
30
|
+
f"'off' or 'on', but it is {graphic_state}"
|
|
31
|
+
)
|
|
32
|
+
raise ValueError(msg)
|
|
33
|
+
|
|
34
|
+
super().__init__(
|
|
35
|
+
px,
|
|
36
|
+
py,
|
|
37
|
+
name,
|
|
38
|
+
sprite_name=sprite_name,
|
|
39
|
+
tilemap=tilemap,
|
|
40
|
+
dyn_id=dyn_id,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
self.type = ObjectType.LIGHT_SOURCE
|
|
44
|
+
self.graphic_state = graphic_state
|
|
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._state_changed = True
|
|
56
|
+
|
|
57
|
+
def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
|
|
58
|
+
if self._state_changed:
|
|
59
|
+
# self._set_sprite_state()
|
|
60
|
+
self._state_changed = False
|
|
61
|
+
|
|
62
|
+
if self.active:
|
|
63
|
+
if self._light is None:
|
|
64
|
+
self._light = Light(self, self._max_size)
|
|
65
|
+
self.engine.get_view().add_effect(
|
|
66
|
+
self._light, self.tilemap.name
|
|
67
|
+
)
|
|
68
|
+
else:
|
|
69
|
+
if self._light is not None:
|
|
70
|
+
self._light.kill()
|
|
71
|
+
self._light = None
|
|
72
|
+
|
|
73
|
+
self.graphic_state = (
|
|
74
|
+
GraphicState.ON if self.active else GraphicState.OFF
|
|
75
|
+
)
|
|
76
|
+
self.sprite.update(
|
|
77
|
+
elapsed_time, self.facing_direction, self.graphic_state
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def on_interaction(self, target: Dynamic, nature: Nature):
|
|
81
|
+
if nature == Nature.SIGNAL:
|
|
82
|
+
self.active = True
|
|
83
|
+
self._state_changed = True
|
|
84
|
+
return True
|
|
85
|
+
|
|
86
|
+
if nature == Nature.NO_SIGNAL:
|
|
87
|
+
self.active = False
|
|
88
|
+
self._state_changed = True
|
|
89
|
+
return True
|
|
90
|
+
|
|
91
|
+
if nature == Nature.TALK:
|
|
92
|
+
self.active = not self.active
|
|
93
|
+
self._state_changed = True
|
|
94
|
+
return True
|
|
95
|
+
|
|
96
|
+
def draw_self(self, ox: float, oy: float, camera_name: str = "display"):
|
|
97
|
+
self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
|
|
98
|
+
|
|
99
|
+
def on_death(self) -> bool:
|
|
100
|
+
self._light.kill()
|
|
101
|
+
return True
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def load_from_tiled_object(obj, px, py, width, height, tilemap):
|
|
105
|
+
light = LightSource(
|
|
106
|
+
px=px,
|
|
107
|
+
py=py,
|
|
108
|
+
name=obj.name,
|
|
109
|
+
sprite_name=obj.get_string("sprite_name"),
|
|
110
|
+
tilemap=tilemap,
|
|
111
|
+
dyn_id=obj.object_id,
|
|
112
|
+
graphic_state=GraphicState[
|
|
113
|
+
obj.get_string("graphic_state", "on").upper()
|
|
114
|
+
],
|
|
115
|
+
max_size=obj.get_int("max_size", 32),
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# light.sprite.width = int(width * LightSource.engine.rtc.tile_width)
|
|
119
|
+
# light.sprite.height = int(height * LightSource.engine.rtc.tile_height)
|
|
120
|
+
|
|
121
|
+
return [light]
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import List, Optional, Union
|
|
3
|
+
|
|
4
|
+
from ...maps.tilemap import Tilemap
|
|
5
|
+
from ...types.alignment import Alignment
|
|
6
|
+
from ...types.direction import Direction
|
|
7
|
+
from ...types.graphic_state import GraphicState
|
|
8
|
+
from ...types.nature import Nature
|
|
9
|
+
from ...types.object import ObjectType
|
|
10
|
+
from ..animated_sprite import AnimatedSprite
|
|
11
|
+
from ..dynamic import Dynamic
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class LogicFunction(Enum):
|
|
15
|
+
LOGIC_PASS = 0
|
|
16
|
+
LOGIC_NOT = 1
|
|
17
|
+
LOGIC_AND = 2
|
|
18
|
+
LOGIC_OR = 3
|
|
19
|
+
LOGIC_NAND = 4
|
|
20
|
+
LOGIC_NOR = 5
|
|
21
|
+
LOGIC_XOR = 6
|
|
22
|
+
LOGIC_IMPL = 7
|
|
23
|
+
LOGIC_EQUI = 8
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class LogicGate(Dynamic):
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
px: float,
|
|
30
|
+
py: float,
|
|
31
|
+
name: str = "Logic Gate",
|
|
32
|
+
*,
|
|
33
|
+
sprite_name: str = "",
|
|
34
|
+
tilemap: Optional[Tilemap] = None,
|
|
35
|
+
dyn_id: int = -1,
|
|
36
|
+
mode: LogicFunction = LogicFunction.LOGIC_PASS,
|
|
37
|
+
initial_signal: bool = False,
|
|
38
|
+
visible: bool = False,
|
|
39
|
+
):
|
|
40
|
+
super().__init__(
|
|
41
|
+
px,
|
|
42
|
+
py,
|
|
43
|
+
name,
|
|
44
|
+
sprite_name=sprite_name,
|
|
45
|
+
tilemap=tilemap,
|
|
46
|
+
dyn_id=dyn_id,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
self.type = ObjectType.LOGIC_GATE
|
|
50
|
+
self.alignment = Alignment.NEUTRAL
|
|
51
|
+
self.visible = visible
|
|
52
|
+
|
|
53
|
+
self.input_id1: int = -1
|
|
54
|
+
self.input_id2: int = -1
|
|
55
|
+
|
|
56
|
+
self.mode = mode
|
|
57
|
+
self.signal: bool = False
|
|
58
|
+
self.last_signal: bool = False
|
|
59
|
+
self.input1: bool = False
|
|
60
|
+
self.input2: bool = False
|
|
61
|
+
|
|
62
|
+
self.listener_ids: List[int] = []
|
|
63
|
+
self.listeners: List[Dynamic] = []
|
|
64
|
+
self.send_initial_signal: bool = initial_signal
|
|
65
|
+
self.state_changed: bool = False
|
|
66
|
+
|
|
67
|
+
def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
|
|
68
|
+
if self.mode == LogicFunction.LOGIC_NOT:
|
|
69
|
+
self.signal = not self.input1
|
|
70
|
+
elif self.mode == LogicFunction.LOGIC_AND:
|
|
71
|
+
self.signal = self.input1 and self.input2
|
|
72
|
+
elif self.mode == LogicFunction.LOGIC_OR:
|
|
73
|
+
self.signal = self.input1 or self.input2
|
|
74
|
+
else:
|
|
75
|
+
self.signal = self.input1
|
|
76
|
+
|
|
77
|
+
if self.last_signal != self.signal:
|
|
78
|
+
self.state_changed = True
|
|
79
|
+
else:
|
|
80
|
+
self.state_changed = False
|
|
81
|
+
|
|
82
|
+
if self.send_initial_signal or self.state_changed:
|
|
83
|
+
self.send_signal(self.signal)
|
|
84
|
+
self.send_initial_signal = False
|
|
85
|
+
|
|
86
|
+
self.last_signal = self.signal
|
|
87
|
+
|
|
88
|
+
self.graphic_state = (
|
|
89
|
+
GraphicState.ON if self.signal else GraphicState.OFF
|
|
90
|
+
)
|
|
91
|
+
self.sprite.update(
|
|
92
|
+
elapsed_time, self.facing_direction, self.graphic_state
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
def on_interaction(self, target: Dynamic, nature: Nature):
|
|
96
|
+
if nature == Nature.SIGNAL:
|
|
97
|
+
if target.dyn_id == self.input_id1:
|
|
98
|
+
self.input1 = True
|
|
99
|
+
elif target.dyn_id == self.input_id2:
|
|
100
|
+
self.input2 = True
|
|
101
|
+
else:
|
|
102
|
+
return False
|
|
103
|
+
return True
|
|
104
|
+
elif nature == Nature.NO_SIGNAL:
|
|
105
|
+
if target.dyn_id == self.input_id1:
|
|
106
|
+
self.input1 = False
|
|
107
|
+
elif target.dyn_id == self.input_id2:
|
|
108
|
+
self.input2 = False
|
|
109
|
+
else:
|
|
110
|
+
return False
|
|
111
|
+
return True
|
|
112
|
+
|
|
113
|
+
return False
|
|
114
|
+
|
|
115
|
+
def draw_self(self, ox: float, oy: float, camera_name: str = "display"):
|
|
116
|
+
if self.visible:
|
|
117
|
+
self.sprite.draw_self(self.px - ox, self.py - oy, camera_name)
|
|
118
|
+
|
|
119
|
+
def send_signal(self, nature: Union[Nature, bool]):
|
|
120
|
+
if isinstance(nature, bool):
|
|
121
|
+
nature = Nature.SIGNAL if nature else Nature.NO_SIGNAL
|
|
122
|
+
|
|
123
|
+
for listener in self.listeners:
|
|
124
|
+
listener.on_interaction(self, nature)
|
|
125
|
+
|
|
126
|
+
@staticmethod
|
|
127
|
+
def load_from_tiled_object(obj, px, py, width, height, tilemap):
|
|
128
|
+
logic = LogicGate(
|
|
129
|
+
px,
|
|
130
|
+
py,
|
|
131
|
+
obj.name,
|
|
132
|
+
sprite_name=obj.get_string("sprite_name"),
|
|
133
|
+
tilemap=tilemap,
|
|
134
|
+
dyn_id=obj.object_id,
|
|
135
|
+
mode=LogicFunction[obj.get_string("mode", "logic_pass").upper()],
|
|
136
|
+
initial_signal=obj.get_bool("initial_signal", False),
|
|
137
|
+
visible=obj.get_bool("visible", True),
|
|
138
|
+
)
|
|
139
|
+
logic.facing_direction = Direction[
|
|
140
|
+
obj.get_string("facing_direction", "south").upper()
|
|
141
|
+
]
|
|
142
|
+
logic.graphic_state = GraphicState[
|
|
143
|
+
obj.get_string("graphic_state", "closed").upper()
|
|
144
|
+
]
|
|
145
|
+
# logic.send_initial_signal =
|
|
146
|
+
# logic.sprite.width = int(width * LogicGate.engine.rtc.tile_width)
|
|
147
|
+
# logic.sprite.height = int(height * LogicGate.engine.rtc.tile_height)
|
|
148
|
+
|
|
149
|
+
ctr = 1
|
|
150
|
+
while True:
|
|
151
|
+
listener_id = obj.get_int(f"output{ctr}", -1)
|
|
152
|
+
if listener_id < 0:
|
|
153
|
+
break
|
|
154
|
+
logic.listener_ids.append(listener_id)
|
|
155
|
+
ctr += 1
|
|
156
|
+
|
|
157
|
+
return [logic]
|