mima-engine 0.2.3__py3-none-any.whl → 0.2.5__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.

@@ -0,0 +1,132 @@
1
+ import time
2
+
3
+ import pygame
4
+
5
+ from ..types.keys import Key as K
6
+ from ..util.constants import DOUBLE_TAP_SPEED
7
+ from ..util.input_defaults import ALT_TOUCHSCREEN_MAP, BUTTONS
8
+
9
+
10
+ class TouchControlSchemeB:
11
+
12
+ def __init__(self):
13
+
14
+ self.move_start_pos = pygame.Vector2()
15
+ self.move_pos = pygame.Vector2()
16
+ self.move_sy = 0.0
17
+ self.move_px = 0.0
18
+ self.move_py = 0.0
19
+ self._left_finger_tap_pos = 0.0
20
+ self._right_finger_tap_pos = 0.0
21
+
22
+ self._last_left_tap = 0.0
23
+ self._last_right_tap = 0.0
24
+ self._keys_active = {k: False for k in K}
25
+ self._state = {}
26
+ for key, conf in ALT_TOUCHSCREEN_MAP.items():
27
+ px, py = conf["pos"]
28
+ w, h = conf["size"]
29
+ self._state[key] = {
30
+ "rpx": px,
31
+ "rpy": py,
32
+ "rwidth": w,
33
+ "rheight": h,
34
+ "active": False,
35
+ }
36
+
37
+ def handle_touch(self, event, width=1.0, height=1.0):
38
+ set_keys = []
39
+ unset_keys = []
40
+
41
+ tap_pos = pygame.Vector2(event.x * width, event.y * height)
42
+ keys_active = {k: False for k in K}
43
+ # print(f"{event.x:.2f}, {event.y:.2f}", end="")
44
+ for key, conf in ALT_TOUCHSCREEN_MAP.items():
45
+ px, py = conf["pos"]
46
+ w, h = conf["size"]
47
+ area = [[px, py], [px + w, py + h]]
48
+
49
+ if (
50
+ area[0][0] <= event.x < area[1][0]
51
+ and area[0][1] <= event.y < area[1][1]
52
+ ):
53
+ if key == K.P1_UP:
54
+ if event.type == pygame.FINGERDOWN:
55
+ self.move_start_pos = pygame.Vector2(tap_pos)
56
+ self.move_pos = pygame.Vector2(tap_pos)
57
+ self._state[key]["rsx"] = event.x
58
+ self._state[key]["rsy"] = event.y
59
+ self._state[key]["rpx"] = event.x
60
+ self._state[key]["rpy"] = event.y
61
+ elif event.type == pygame.FINGERMOTION:
62
+ self.move_pos = tap_pos
63
+ self._state[key]["rpx"] = event.x
64
+ self._state[key]["rpy"] = event.y
65
+
66
+ vd = self.move_pos - self.move_start_pos
67
+ if abs(vd.x) > 2 * abs(vd.y):
68
+ # Horizontal
69
+ if vd.x > 5.0:
70
+ keys_active[K.P1_RIGHT] = True
71
+ # print("..>", end="")
72
+ elif vd.x < -5.0:
73
+ keys_active[K.P1_LEFT] = True
74
+ # print("..<", end="")
75
+ elif abs(vd.x) * 2 < abs(vd.y):
76
+ # Vertical
77
+ if vd.y > 5.0:
78
+ keys_active[K.P1_DOWN] = True
79
+ # print("..v", end="")
80
+ elif vd.y < -5.0:
81
+ keys_active[K.P1_UP] = True
82
+ # print("..^", end="")
83
+ elif abs(vd.x) * 1.05 > abs(vd.y) or abs(
84
+ vd.x
85
+ ) < 1.05 * abs(vd.y):
86
+ # Diagonal
87
+ if vd.x < 0:
88
+ keys_active[K.P1_LEFT] = True
89
+ # print("..<", end="")
90
+ elif vd.x > 0:
91
+ keys_active[K.P1_RIGHT] = True
92
+ # print("..>", end="")
93
+ if vd.y < 0:
94
+ keys_active[K.P1_UP] = True
95
+ # print("..^", end="")
96
+ elif vd.y > 0:
97
+ keys_active[K.P1_DOWN] = True
98
+ # print("..v", end="")
99
+ # elif event.type == pygame.FINGERUP:
100
+ # unset_keys.append(K.P1_RIGHT)
101
+ # unset_keys.append(K.P1_LEFT)
102
+ # unset_keys.append(K.P1_UP)
103
+ # unset_keys.append(K.P1_DOWN)
104
+ else:
105
+ if event.type == pygame.FINGERDOWN:
106
+ keys_active[key] = True
107
+ # print(f"..{key.name}", end="")
108
+ if event.type == pygame.FINGERMOTION:
109
+ keys_active[key] = True
110
+ # print(f"..{key.name}", end="")
111
+ # print()
112
+ for k, val in keys_active.items():
113
+ if val:
114
+ set_keys.append(k)
115
+ # self._state.setdefault(k, {})["active"] = True
116
+ if k in self._state:
117
+ self._state[k]["active"] = True
118
+ if k in [K.P1_LEFT, K.P1_RIGHT, K.P1_DOWN]:
119
+ self._state[K.P1_UP]["active"] = True
120
+ else:
121
+ unset_keys.append(k)
122
+ if k in self._state:
123
+ self._state[k]["active"] = False
124
+ return set_keys, unset_keys
125
+
126
+ def get_touch_state(self):
127
+ state = {}
128
+ for key, conf in self._state.items():
129
+ nkey = K(key.value - 12)
130
+ state[nkey] = conf
131
+
132
+ return state
mima/core/collision.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import math
4
+ from itertools import product
4
5
  from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Tuple
5
6
 
6
7
  from ..maps.tilemap import Tilemap
@@ -35,7 +36,9 @@ def check_object_to_map_collision(
35
36
 
36
37
  collided_with_map = False
37
38
  if obj.solid_vs_map:
38
- if collision_with_map(tilemap, left, right, top, bottom, layer, collision):
39
+ if collision_with_map(
40
+ tilemap, left, right, top, bottom, layer, collision
41
+ ):
39
42
  # On rare occasions, the object might be pushed towards
40
43
  # the wall, i.e. old and new pos are equal
41
44
  # Decide depending on the decimal part of the position
@@ -66,7 +69,9 @@ def check_object_to_map_collision(
66
69
  top = new_py + obj.hitbox_py
67
70
  bottom = top + obj.hitbox_height
68
71
 
69
- if collision_with_map(tilemap, left, right, top, bottom, layer, collision):
72
+ if collision_with_map(
73
+ tilemap, left, right, top, bottom, layer, collision
74
+ ):
70
75
  # See comment above
71
76
  if new_py == obj.py:
72
77
  decimal_dif = new_py - int(new_py)
@@ -244,34 +249,50 @@ def add_to_collision_chunk(
244
249
  # collision_chunks[chidx].insert(0, obj)
245
250
  # else:
246
251
  # collision_chunks[chidx].append(obj)
247
-
248
- chid = _test_chunk_position(
249
- collision_chunks, obj, obj.px, obj.py, chunk_size, chunks_per_row
250
- )
251
- chid_right = _test_chunk_position(
252
- collision_chunks, obj, obj.px + 1, obj.py, chunk_size, chunks_per_row
253
- )
254
-
255
- chid_bottom = _test_chunk_position(
256
- collision_chunks, obj, obj.px, obj.py + 1, chunk_size, chunks_per_row
257
- )
258
-
259
- chunk_ids.append(chid)
260
- if chid != chid_right:
261
- chunk_ids.append(chid_right)
262
- if chid != chid_bottom:
263
- chunk_ids.append(chid_bottom)
264
- if chid != chid_right and chid != chid_bottom:
252
+ centerx = obj.px + (obj.hitbox_px + obj.hitbox_width) / 2
253
+ centery = obj.py + (obj.hitbox_py + obj.hitbox_height) / 2
254
+ # chid = _test_chunk_position(
255
+ # collision_chunks, obj, centerx, centery, chunk_size, chunks_per_row
256
+ # )
257
+ offsets = [[0, 0]] + [
258
+ list(p) for p in product([-1, 0, 1], repeat=2) if p != (0, 0)
259
+ ]
260
+ for x, y in offsets:
265
261
  chunk_ids.append(
266
262
  _test_chunk_position(
267
263
  collision_chunks,
268
264
  obj,
269
- obj.px + 1,
270
- obj.py + 1,
265
+ centerx + x,
266
+ centery + y,
271
267
  chunk_size,
272
268
  chunks_per_row,
273
269
  )
274
270
  )
271
+ chunk_ids = list(dict.fromkeys(chunk_ids))
272
+ # chid_right = _test_chunk_position(
273
+ # collision_chunks, obj, obj.px + 1, obj.py, chunk_size, chunks_per_row
274
+ # )
275
+
276
+ # chid_bottom = _test_chunk_position(
277
+ # collision_chunks, obj, obj.px, obj.py + 1, chunk_size, chunks_per_row
278
+ # )
279
+
280
+ # chunk_ids.append(chid)
281
+ # if chid != chid_right:
282
+ # chunk_ids.append(chid_right)
283
+ # if chid != chid_bottom:
284
+ # chunk_ids.append(chid_bottom)
285
+ # if chid != chid_right and chid != chid_bottom:
286
+ # chunk_ids.append(
287
+ # _test_chunk_position(
288
+ # collision_chunks,
289
+ # obj,
290
+ # obj.px + 1,
291
+ # obj.py + 1,
292
+ # chunk_size,
293
+ # chunks_per_row,
294
+ # )
295
+ # )
275
296
 
276
297
  for chid in obj.chunks:
277
298
  if (
@@ -283,7 +304,9 @@ def add_to_collision_chunk(
283
304
  return chunk_ids
284
305
 
285
306
 
286
- def _test_chunk_position(collision_chunks, obj, px, py, chunk_size, chunks_per_row):
307
+ def _test_chunk_position(
308
+ collision_chunks, obj, px, py, chunk_size, chunks_per_row
309
+ ):
287
310
  chidx = _chunk_index(px, py, chunk_size, chunks_per_row)
288
311
  collision_chunks.setdefault(chidx, [])
289
312
 
mima/core/engine.py CHANGED
@@ -26,13 +26,9 @@ from ..usables.weapon import Weapon
26
26
  from ..util import RuntimeConfig
27
27
  from ..util.logging import install_trace_logger
28
28
  from ..view.camera import Camera
29
-
30
- # from .view.game_mode import GameMode
31
29
  from ..view.mima_view import MimaView
32
30
  from .database import Database
33
31
 
34
- # from .view.scene import Scene
35
-
36
32
  if TYPE_CHECKING:
37
33
  from .states.game_state import GameState
38
34
 
@@ -51,7 +47,9 @@ class MimaEngine(ABC):
51
47
  self.rtc = RuntimeConfig(config_path, default_config)
52
48
  install_trace_logger()
53
49
 
54
- self.backend: PygameBackend = PygameBackend(self.rtc, init_file, platform)
50
+ self.backend: PygameBackend = PygameBackend(
51
+ self.rtc, init_file, platform
52
+ )
55
53
  self.db: Database
56
54
  self._caption: str = caption
57
55
  self.seconds_total: float = 0.0
@@ -60,6 +58,9 @@ class MimaEngine(ABC):
60
58
  self.elapsed_time: float = 0.00022
61
59
  self._app_time: float = 0.0
62
60
 
61
+ self.enable_touch_controls: bool = False
62
+ self.show_touch_controls: bool = False
63
+
63
64
  self.mode: Mode = Mode.LOADING
64
65
  self.gate_color: GateColor = GateColor.RED
65
66
  self.n_gate_colors = 2
@@ -67,9 +68,6 @@ class MimaEngine(ABC):
67
68
  self.memory: Memory = Memory()
68
69
  self.all_games: Dict[str, GameState] = {}
69
70
  self.current_game: str = ""
70
- # self.player: Creature
71
- # self.quests: List[Quest] = []
72
- # self._items: Dict[str, Item] = {}
73
71
  self.cameras: List[str] = []
74
72
 
75
73
  def construct(
@@ -80,6 +78,7 @@ class MimaEngine(ABC):
80
78
  fullscreen: bool = False,
81
79
  target_fps: int = 60,
82
80
  resizable: bool = False,
81
+ no_scaled_flag: bool = False,
83
82
  kb_map=None,
84
83
  ):
85
84
  """Initialize backend and create a window."""
@@ -108,7 +107,16 @@ class MimaEngine(ABC):
108
107
  joy_to_player=self.rtc.get_joy_to_player(),
109
108
  )
110
109
  self.backend.construct(
111
- width, height, pixel_size, fullscreen, target_fps, resizable
110
+ width,
111
+ height,
112
+ pixel_size,
113
+ fullscreen,
114
+ target_fps,
115
+ resizable,
116
+ no_scaled_flag,
117
+ )
118
+ self.backend.user_input.enable_touch_controls = (
119
+ self.enable_touch_controls
112
120
  )
113
121
 
114
122
  return True
@@ -126,7 +134,8 @@ class MimaEngine(ABC):
126
134
  if self.on_user_create():
127
135
  while self.backend.keep_running():
128
136
  self.backend.set_caption(
129
- f"{self._caption} ({self.game_fps:.2f}/" f"{self.app_fps:.2f} fps)"
137
+ f"{self._caption} ({self.game_fps:.2f}/"
138
+ f"{self.app_fps:.2f} fps)"
130
139
  )
131
140
  self.backend.process_events()
132
141
 
@@ -160,7 +169,10 @@ class MimaEngine(ABC):
160
169
  app_frames = 0
161
170
  app_seconds -= 1.0
162
171
 
163
- print(f"App/Game Frames total: {app_frames_total}/" f"{game_frames_total}")
172
+ print(
173
+ f"App/Game Frames total: {app_frames_total}/"
174
+ f"{game_frames_total}"
175
+ )
164
176
  print(f"Seconds total: {self.seconds_total:.3f}")
165
177
  print(
166
178
  "Average App/Game FPS: "
@@ -276,7 +288,9 @@ class MimaEngine(ABC):
276
288
  def set_player(self, creature: Creature, player: Player = Player.P1):
277
289
  self.memory.player[player] = creature
278
290
 
279
- def trigger_teleport(self, active: bool = True, player: Player = Player.P1):
291
+ def trigger_teleport(
292
+ self, active: bool = True, player: Player = Player.P1
293
+ ):
280
294
  self.memory.teleport_active[player] = active
281
295
 
282
296
  def is_teleport_active(self, player: Player = Player.P1):
@@ -288,7 +302,9 @@ class MimaEngine(ABC):
288
302
  def is_dialog_active(self, player: Player = Player.P1):
289
303
  return self.memory.dialog_active[player]
290
304
 
291
- def trigger_script(self, active: bool = True, player: Player = Player.P1) -> None:
305
+ def trigger_script(
306
+ self, active: bool = True, player: Player = Player.P1
307
+ ) -> None:
292
308
  self.memory.script_active[player] = active
293
309
 
294
310
  def is_script_active(self, player: Player = Player.P1) -> bool:
@@ -337,7 +353,10 @@ class MimaEngine(ABC):
337
353
 
338
354
  @dialog_active.setter
339
355
  def dialog_active(self, val):
340
- print("dialog_active is deprecated; use " "'trigger_dialog(active)' instead.")
356
+ print(
357
+ "dialog_active is deprecated; use "
358
+ "'trigger_dialog(active)' instead."
359
+ )
341
360
  self.memory.dialog_active = val
342
361
 
343
362
  @property
mima/core/mode_engine.py CHANGED
@@ -22,7 +22,9 @@ class MimaModeEngine(MimaEngine):
22
22
  platform="PC",
23
23
  caption: str = "MimaEngine",
24
24
  ):
25
- super().__init__(init_file, config_path, default_config, platform, caption)
25
+ super().__init__(
26
+ init_file, config_path, default_config, platform, caption
27
+ )
26
28
 
27
29
  self.modes: Dict[Mode, MimaMode] = {}
28
30
  self.mode: Optional[MimaMode] = None
@@ -31,6 +33,7 @@ class MimaModeEngine(MimaEngine):
31
33
 
32
34
  self.draw_chunks: bool = False
33
35
  self.draw_chunk_info: bool = False
36
+ self.draw_dyn_ids: bool = False
34
37
  self.disable_filter: bool = False
35
38
  self._timer = 1.0
36
39
 
@@ -67,7 +70,9 @@ class MimaModeEngine(MimaEngine):
67
70
  self.mode.load()
68
71
 
69
72
  def return_mode(self):
70
- LOG.debug("Returning to previous mode. Stack: %s", str(self.mode_stack))
73
+ LOG.debug(
74
+ "Returning to previous mode. Stack: %s", str(self.mode_stack)
75
+ )
71
76
  self.mode_stack.pop()
72
77
  self.mode = self.modes[self.mode_stack[-1]]
73
78
  self.mode.load()
mima/objects/creature.py CHANGED
@@ -136,6 +136,9 @@ class Creature(Dynamic):
136
136
  if self.attributes.health <= 0:
137
137
  self.change_graphic_state(GraphicState.DEAD)
138
138
 
139
+ if self.can_act():
140
+ self.behavior(elapsed_time, target)
141
+
139
142
  if self.vx < -0.01:
140
143
  self.facing_direction = Direction.WEST
141
144
  if self.vx > 0.01:
@@ -147,9 +150,6 @@ class Creature(Dynamic):
147
150
 
148
151
  self.speed = self.attributes.speed
149
152
 
150
- if self.can_act():
151
- self.behavior(elapsed_time, target)
152
-
153
153
  self.sprite.update(
154
154
  elapsed_time, self.facing_direction, self.graphic_state
155
155
  )
@@ -298,6 +298,12 @@ class Creature(Dynamic):
298
298
 
299
299
  self.projectiles = []
300
300
 
301
+ def on_enter_map(self):
302
+ pass
303
+
304
+ def on_exit_map(self):
305
+ pass
306
+
301
307
  def on_death(self):
302
308
  if self.spawn_on_death:
303
309
  for do in self.spawn_on_death:
@@ -21,7 +21,12 @@ class DynamicDebugBox(Projectile):
21
21
  ids=None,
22
22
  ) -> None:
23
23
  super().__init__(
24
- 0, 0, 0, 0, 0, Alignment.NEUTRAL, follow.tilemap, "DynamicDebugBox"
24
+ 0,
25
+ 0,
26
+ "DynamicDebugBox",
27
+ duration=0.0,
28
+ alignment=Alignment.NEUTRAL,
29
+ tilemap=follow.tilemap,
25
30
  )
26
31
  self.layer = 2
27
32
  self.sprite = None
@@ -76,7 +81,11 @@ class DynamicDebugBox(Projectile):
76
81
  class StaticDebugBox(Projectile):
77
82
  def __init__(self, px, py, width, height, color, n_frames=1, ids=None):
78
83
  super().__init__(
79
- px, py, 0, 0, 0, Alignment.NEUTRAL, None, "StaticDebugBox"
84
+ px,
85
+ py,
86
+ "StaticDebugBox",
87
+ duration=0.0,
88
+ alignment=Alignment.NEUTRAL,
80
89
  )
81
90
  self.layer = 2
82
91
  self._color = color
@@ -138,7 +138,7 @@ class Container(Dynamic):
138
138
  CommandParallel(
139
139
  [
140
140
  CommandShowDialog(
141
- [f"You received {self.item_name}"],
141
+ [f"You received {self.item.name}"],
142
142
  ),
143
143
  CommandPresentItem(self.item_name, target),
144
144
  CommandGiveItem(self.item_name, target),
@@ -35,6 +35,7 @@ class Oneway(Dynamic):
35
35
  dyn_id=dyn_id,
36
36
  )
37
37
  self.type = ObjectType.ONEWAY
38
+ self.layer = 0
38
39
  self.sprite.width = int(width * self.engine.rtc.tile_width)
39
40
  self.sprite.height = int(height * self.engine.rtc.tile_height)
40
41
 
@@ -46,24 +47,26 @@ class Oneway(Dynamic):
46
47
  self.height: float = height
47
48
  self.jump_vx: float = 0.0
48
49
  self.jump_vy: float = 0.0
50
+ self.jump_direction = Direction.from_velocity(jump_vx, jump_vy)
49
51
  self.activation_delay: float = ONEWAY_ACTIVATION_DELAY
50
52
  self.triggered: bool = False
53
+ self.is_active: bool = False
51
54
  self.cooldown: float = 0.0
52
55
  self.target = None
53
56
 
54
57
  if jump_vx < 0:
55
58
  self.jump_vx = jump_vx - 1
56
- self.hitbox_px += 0.1
59
+ # self.hitbox_px += 0.1
57
60
  elif jump_vx > 0:
58
61
  self.jump_vx = jump_vx + 1
59
- self.hitbox_px -= 0.1
62
+ # self.hitbox_px -= 0.1
60
63
 
61
64
  if jump_vy < 0:
62
65
  self.jump_vy = jump_vy - 1
63
- self.hitbox_py += 0.1
66
+ # self.hitbox_py += 0.1
64
67
  elif jump_vy > 0:
65
68
  self.jump_vy = jump_vy + 1
66
- self.hitbox_py -= 0.1
69
+ # self.hitbox_py -= 0.1
67
70
 
68
71
  def update(self, elapsed_time, target=None):
69
72
  self.sprite.update(
@@ -90,9 +93,15 @@ class Oneway(Dynamic):
90
93
  # Activation countdown reached 0 and the jump is initiated.
91
94
  if self.timer <= 0.0 and self.target is not None:
92
95
  self.engine.script.add_command(
93
- CommandOnewayMove(self.target, self.jump_vx, self.jump_vy)
96
+ CommandOnewayMove(
97
+ self.target,
98
+ self.jump_vx,
99
+ self.jump_vy,
100
+ target.get_player(),
101
+ )
94
102
  )
95
103
  self.cooldown = 2.0
104
+ self.is_active
96
105
 
97
106
  # Reset the triggered flag so it has to be activated again
98
107
  # by interaction
@@ -100,11 +109,25 @@ class Oneway(Dynamic):
100
109
  self.target = None
101
110
 
102
111
  def on_interaction(self, target, nature=Nature.WALK):
103
- if target.type == ObjectType.PLAYER and nature == Nature.WALK:
112
+ if (
113
+ target.type == ObjectType.PLAYER
114
+ and nature == Nature.WALK
115
+ and self.cooldown <= 0.0
116
+ ):
104
117
  # No interaction when target is higher than the oneway
105
118
  if target.pz > 0:
106
119
  return False
107
120
 
121
+ if self.jump_direction != target.facing_direction:
122
+ return False
123
+
124
+ tcenterx = target.px + (target.hitbox_px + target.hitbox_width) / 2
125
+ tbottomy = target.py + target.hitbox_py + target.hitbox_height
126
+ ttopy = target.py + target.hitbox_py
127
+ tleftx = target.px + target.hitbox_px
128
+ trightx = tleftx + target.hitbox_width
129
+
130
+ # print(tcenterx, tbottomy)
108
131
  # We have to check that target is not placed "more" in the
109
132
  # target direction than the oneway
110
133
  if (
@@ -119,7 +142,7 @@ class Oneway(Dynamic):
119
142
  and target.py <= self.py + self.height - target.hitbox_py
120
143
  ):
121
144
  return False
122
- if self.jump_vy > 0 and target.py >= self.py:
145
+ if self.jump_vy > 0 and tbottomy >= self.py: # FIXME
123
146
  return False
124
147
 
125
148
  if self.jump_vx == 0:
@@ -133,12 +156,15 @@ class Oneway(Dynamic):
133
156
  return False
134
157
  if target.py + 1.0 <= self.py:
135
158
  return False
136
-
137
159
  self.triggered = True
138
160
  self.target = target
139
161
  if self.timer <= 0.0:
140
162
  self.timer = self.activation_delay
163
+ # return False
141
164
 
165
+ # print(
166
+ # f"activated {self.timer:.3f}, {self.px, self.py}, {target.px, target.py}, {target.sprite.width, target.sprite.height}"
167
+ # )
142
168
  return True
143
169
 
144
170
  return False
@@ -39,6 +39,7 @@ class Pickup(Dynamic):
39
39
 
40
40
  self.collected = False
41
41
  self.solid_vs_dyn = False
42
+ self.moves_on_collision = True
42
43
  # self.sprite = AnimatedSprite(
43
44
  # self.item.tileset_name,
44
45
  # self.item.image_name,
@@ -82,6 +83,8 @@ class Pickup(Dynamic):
82
83
  return
83
84
 
84
85
  if self.pz != 0:
86
+
87
+ # print("Draw item circle")
85
88
  self.engine.backend.fill_circle(
86
89
  (self.px - ox + 0.5) * self.sprite.width,
87
90
  (self.py - oy + 0.7) * self.sprite.height,
@@ -90,7 +93,10 @@ class Pickup(Dynamic):
90
93
  camera_name,
91
94
  )
92
95
  self.sprite.draw_self(
93
- self.px - ox, self.py - oy, camera_name, draw_to_ui=draw_to_ui
96
+ self.px - ox,
97
+ self.py - oy - self.pz,
98
+ camera_name,
99
+ draw_to_ui=draw_to_ui,
94
100
  )
95
101
  # self.engine.backend.draw_partial_sprite(
96
102
  # (self.px - ox) * self.item.sprite_width,
@@ -129,7 +135,7 @@ class Pickup(Dynamic):
129
135
  else:
130
136
  eff = WalkingOnWater(self)
131
137
  self.effects.append(eff)
132
- self.engine.scene.add_effect(eff)
138
+ self.engine.get_view().add_effect(eff, self.tilemap.name)
133
139
  # else:
134
140
  # self.attributes.speed_mod = 1.0
135
141
 
@@ -46,10 +46,15 @@ class Switch(Dynamic):
46
46
  self.listener_ids: List[int] = []
47
47
  self.listeners: List[Dynamic] = []
48
48
  self.send_initial_signal = initial_signal
49
+ self.cooldown = 0.0
50
+ self.cooldown_reset = 0.8
49
51
 
50
52
  # self._gs_map = {False: GraphicState.OPEN, True: GraphicState.CLOSED}
51
53
 
52
54
  def update(self, elapsed_time: float, target: Optional[Dynamic] = None):
55
+ if self.cooldown > 0.0:
56
+ self.cooldown -= elapsed_time
57
+
53
58
  if self.send_initial_signal:
54
59
  self.send_signal(self.signal)
55
60
  self.send_initial_signal = False
@@ -71,25 +76,36 @@ class Switch(Dynamic):
71
76
  def on_interaction(self, target: Dynamic, nature: Nature):
72
77
  # if target.is_player().value > 0:
73
78
  # print(f"{target.is_player()} talked to me({self.name})")
79
+ if self.cooldown > 0.0:
80
+ return False
81
+
74
82
  if (
75
83
  nature == Nature.TALK
76
84
  and target.type == ObjectType.PLAYER
77
85
  and self.visible
78
86
  ):
79
87
  self.state_changed = True
80
- self.engine.audio.play_sound("switch")
88
+ self.engine.audio.play_sound("switch", 0.2)
89
+ self.cooldown = self.cooldown_reset
90
+ print("Player talked")
81
91
 
82
92
  elif nature == Nature.WALK and target.type == ObjectType.PROJECTILE:
83
93
  if self.signal:
84
94
  # Projectiles from the right will activate the switch
85
95
  if target.px > self.px and target.vx < 0:
86
96
  self.state_changed = True
97
+ if "body" not in target.name:
98
+ self.engine.audio.play_sound("switch", 0.2)
99
+ self.cooldown = self.cooldown_reset
87
100
  else:
88
101
  # Projectiles from the left will (de)activate the switch
89
- if target.px <= self.px and target.vx > 0:
102
+ if (
103
+ target.px <= self.px and target.vx > 0
104
+ ): # Sword does not activate because vx=0
90
105
  self.state_changed = True
91
- if "body" not in target.name:
92
- self.engine.audio.play_sound("switch")
106
+ if "body" not in target.name:
107
+ self.engine.audio.play_sound("switch", 0.2)
108
+ self.cooldown = self.cooldown_reset
93
109
 
94
110
  elif nature == Nature.SIGNAL:
95
111
  self.visible = False