feat: introduce core player logic with manager integration and power-up inventory UI.

This commit is contained in:
Yogi Wiguna
2026-03-04 15:56:03 +08:00
parent a78acd12b8
commit 8f03cc15c5
5 changed files with 123 additions and 174 deletions
+32 -48
View File
@@ -24,6 +24,7 @@ func initialize(p_player: Node3D, p_gridmap: Node):
signal movement_finished
var movement_queue: Array[Vector2i] = [] # Queue of target grid positions
var current_move_direction: Vector2i = Vector2i.ZERO
var last_move_direction: Vector2i = Vector2i(0, 1) # Default forward (towards +Z)
func _process(delta):
if player:
@@ -137,6 +138,8 @@ func simple_move_to(grid_position: Vector2i) -> bool:
path.pop_front()
current_move_direction = grid_position - player.current_position
if current_move_direction != Vector2i.ZERO:
last_move_direction = current_move_direction
if player.is_multiplayer_authority():
# Authority starts their own tween locally
@@ -174,54 +177,39 @@ func try_push(target_pos: Vector2i, direction: Vector2i) -> bool:
NotificationManager.send_message(player, "Cannot Attack in Safe Zone!", NotificationManager.MessageType.WARNING)
return false
# 1. Drop Victim's Tiles
if other_player.has_method("drop_all_tiles"):
if _can_rpc():
other_player.rpc("drop_all_tiles") # Sync drop
# 1. 3-Floor Knockback towards Starting Line (X=0)
var push_direction = Vector2i(-1, 0) # Backwards
var pushed_to_pos = target_pos
var push_path = []
# 2. Spawn PowerUps around Victim
# We delegate this to the attacker's SpecialTilesManager to handle the spawning authority
if player.special_tiles_manager and player.special_tiles_manager.has_method("spawn_powerups_around"):
player.special_tiles_manager.spawn_powerups_around(other_player.current_position)
# 3. Knockback / Stagger
# Push them away
var pushed_to_pos = target_pos + direction
# IMPROVED: Check if destination is valid and walkable to prevent being stuck on 'blocks'
var is_dest_valid = _can_push_to(pushed_to_pos)
# DEFLECTION LOGIC: If direct path is blocked, try diagonal deflection
if not is_dest_valid:
var alts = []
if direction.x != 0 and direction.y == 0: # Horizontal push -> try diagonal North/South
alts = [pushed_to_pos + Vector2i(0, 1), pushed_to_pos + Vector2i(0, -1)]
elif direction.y != 0 and direction.x == 0: # Vertical push -> try diagonal East/West
alts = [pushed_to_pos + Vector2i(1, 0), pushed_to_pos + Vector2i(-1, 0)]
elif direction.x != 0 and direction.y != 0: # Diagonal push -> try horizontal/vertical components
alts = [pushed_to_pos - Vector2i(direction.x, 0), pushed_to_pos - Vector2i(0, direction.y)]
# Try to push up to 3 tiles back, building the path as we go
for i in range(3):
var next_back = pushed_to_pos + push_direction
if _can_push_to(next_back):
pushed_to_pos = next_back
push_path.append(Vector2(pushed_to_pos.x, pushed_to_pos.y))
else:
break # Blocked by wall or edge
for alt in alts:
if _can_push_to(alt):
pushed_to_pos = alt
is_dest_valid = true
break
if is_dest_valid:
# Valid push
var push_path = [Vector2(pushed_to_pos.x, pushed_to_pos.y)]
if push_path.size() > 0:
# Valid push movement
if _can_rpc():
other_player.rpc("start_movement_along_path", push_path, false)
# Pass 'true' for 'force' parameter to interrupt active movements
other_player.rpc("start_movement_along_path", push_path, false, true)
# Authority Check: If we are already the authority for the victim (e.g. Host hitting a Bot),
# the 'call_remote' RPC above won't execute locally. We MUST call it manually.
if other_player.is_multiplayer_authority():
other_player.start_movement_along_path(push_path, false, true)
other_player.target_position = pushed_to_pos # Logical update
# Apply stun/freeze effect as requested (same as wall stagger)
if _can_rpc():
other_player.rpc("apply_stagger", 1.5)
# 2. Apply freeze/stun effect (blue tint)
if _can_rpc():
other_player.rpc("apply_stagger", 1.5)
else:
# Wall/Blocked -> Stagger in place (Only if no alternatives found)
if _can_rpc():
other_player.rpc("apply_stagger", 1.5)
# Handle local execution (e.g. offline or host-only logic)
other_player.apply_stagger(1.5)
# 4. Consume Boost (Full) - One hit per charge
if player.powerup_manager:
@@ -246,12 +234,8 @@ func try_push(target_pos: Vector2i, direction: Vector2i) -> bool:
else:
NotificationManager.send_message(player, "Successful Attack!", NotificationManager.MessageType.GOAL)
# 5. Attack Mode Persistence
# logic moved to consume_boost: checks if <= 0 then disables.
# So we do NOT force disable here.
# player.is_attack_mode = false
return true
# 5. Block the attacker from moving into the victim's space to prevent overlapping
return false
func set_speed_multiplier(multiplier: float):
speed_multiplier = multiplier