feat: implement core player entity with state management, network synchronization, and bot logic.
This commit is contained in:
+60
-4
@@ -751,7 +751,7 @@ func _apply_tint_recursive(node: Node, color: Color):
|
||||
|
||||
var immunity_timer: float = 0.0
|
||||
var tekton_carry_timer: float = 0.0
|
||||
const MAX_TEKTON_CARRY_TIME: float = 3.0
|
||||
const MAX_TEKTON_CARRY_TIME: float = 4.0
|
||||
|
||||
|
||||
@rpc("any_peer", "call_local")
|
||||
@@ -2139,12 +2139,58 @@ func grab_tekton():
|
||||
if not is_multiplayer_authority() or is_carrying_tekton or is_frozen or is_stop_frozen:
|
||||
return
|
||||
|
||||
# Find nearby Tekton
|
||||
# 1. Check for nearby carrier to snatch from
|
||||
var carrier = _find_nearby_carrier()
|
||||
if carrier:
|
||||
snatch_tekton(carrier)
|
||||
return
|
||||
|
||||
# 2. Find nearby roaming Tekton
|
||||
var tekton = _find_nearby_tekton()
|
||||
if tekton:
|
||||
if is_multiplayer_authority() and can_rpc():
|
||||
rpc("sync_grab_tekton", tekton.get_path())
|
||||
|
||||
func snatch_tekton(target_carrier: Node3D):
|
||||
if not is_multiplayer_authority() or not target_carrier.is_carrying_tekton:
|
||||
return
|
||||
|
||||
var tekton = target_carrier.carried_tekton
|
||||
if tekton:
|
||||
if is_multiplayer_authority() and can_rpc():
|
||||
rpc("sync_snatch_tekton", target_carrier.get_path(), tekton.get_path())
|
||||
|
||||
@rpc("any_peer", "call_local", "reliable")
|
||||
func sync_snatch_tekton(carrier_path: NodePath, tekton_path: NodePath):
|
||||
var carrier = get_node_or_null(carrier_path)
|
||||
var tekton = get_node_or_null(tekton_path)
|
||||
if carrier and tekton:
|
||||
# Security: ensure multiple people don't think they are carrying it
|
||||
# Transfer logic
|
||||
carrier.is_carrying_tekton = false
|
||||
carrier.carried_tekton = null
|
||||
|
||||
self.is_carrying_tekton = true
|
||||
self.carried_tekton = tekton
|
||||
tekton.set_carried(true, self)
|
||||
|
||||
# Reset my carry timer (3s rule starts fresh)
|
||||
tekton_carry_timer = 0.0
|
||||
|
||||
# Visual/Logic side effects
|
||||
if is_attack_mode:
|
||||
is_attack_mode = false
|
||||
|
||||
SfxManager.play("pick_up_tekton_roaming")
|
||||
play_pickup_animation()
|
||||
|
||||
# Visual feedback for the victim
|
||||
if carrier.has_method("sync_bump"):
|
||||
# Bump away from the snatcher
|
||||
carrier.sync_bump(current_position, true)
|
||||
|
||||
print("[Player %s] SNATCHED Tekton from %s" % [name, carrier.name])
|
||||
|
||||
@rpc("any_peer", "call_local", "reliable")
|
||||
func sync_grab_tekton(tekton_path: NodePath):
|
||||
var tekton = get_node_or_null(tekton_path)
|
||||
@@ -2409,8 +2455,6 @@ func _find_nearby_tekton() -> Node3D: # Find closest Tekton
|
||||
if t.get("is_recovering"): continue # Cannot grab recovering/shrunk Tekton
|
||||
if t.get("is_static_turret"): continue # Cannot grab/knock static turret
|
||||
|
||||
# Check adjacency (or same tile)
|
||||
# Assuming is_adjacent_or_same is a helper function that checks if two Vector2i are adjacent or the same.
|
||||
# For example: (pos1 - pos2).length_squared() <= 2 (for adjacent or same tile)
|
||||
var dist_grid = (t.current_position - current_position).length()
|
||||
if dist_grid <= 1.5: # Adjacent (1.0 or 1.41) or same tile (0.0)
|
||||
@@ -2419,3 +2463,15 @@ func _find_nearby_tekton() -> Node3D: # Find closest Tekton
|
||||
min_dist = dist
|
||||
closest_tekton = t
|
||||
return closest_tekton
|
||||
|
||||
func _find_nearby_carrier() -> Node3D:
|
||||
"""Find a nearby player who is carrying a Tekton."""
|
||||
var players = get_tree().get_nodes_in_group("Players")
|
||||
for p in players:
|
||||
if p == self: continue
|
||||
if p.is_carrying_tekton:
|
||||
# Check adjacency or same tile
|
||||
var dist = Vector2(p.current_position.x, p.current_position.y).distance_to(Vector2(current_position.x, current_position.y))
|
||||
if dist <= 1.5:
|
||||
return p
|
||||
return null
|
||||
|
||||
Reference in New Issue
Block a user