feat: implement Candy Cannon mechanics, CI/CD pipelines, and version 2.3.7 updates
This commit is contained in:
@@ -86,6 +86,8 @@ var trapped_players: Dictionary = {} # player_id → true
|
||||
|
||||
var main_scene: Node = null
|
||||
var gridmap: Node = null
|
||||
var candy_cannon_scene: PackedScene = preload("res://scenes/candy_cannon.tscn")
|
||||
var cannon_instance: Node3D = null
|
||||
|
||||
# HUD
|
||||
var hud_layer: CanvasLayer
|
||||
@@ -250,6 +252,14 @@ func _apply_arena_setup() -> void:
|
||||
gridmap.update_grid_data()
|
||||
gridmap.initialize_astar()
|
||||
|
||||
if not cannon_instance and main_scene:
|
||||
cannon_instance = candy_cannon_scene.instantiate()
|
||||
cannon_instance.name = "CandyCannon"
|
||||
var cx = NPC_CENTER.x * gridmap.cell_size.x + gridmap.cell_size.x / 2.0
|
||||
var cz = NPC_CENTER.y * gridmap.cell_size.z + gridmap.cell_size.z / 2.0
|
||||
cannon_instance.position = Vector3(cx, 0, cz)
|
||||
main_scene.add_child(cannon_instance)
|
||||
|
||||
print("[Gauntlet] Arena setup complete. Center NPC at (%d,%d), size %dx%d" % [
|
||||
NPC_CENTER.x, NPC_CENTER.y, NPC_SIZE, NPC_SIZE
|
||||
])
|
||||
@@ -336,6 +346,13 @@ func _fire_volley() -> void:
|
||||
# Telegraph phase — show warning
|
||||
if _can_rpc():
|
||||
rpc("sync_telegraph", targets)
|
||||
|
||||
# Shoot projectiles visually
|
||||
if cannon_instance and cannon_instance.has_method("spawn_projectile_rpc") and cannon_instance.can_rpc():
|
||||
var cs = gridmap.cell_size
|
||||
for target in targets:
|
||||
var target_pos = Vector3(target.x * cs.x + cs.x / 2.0, 0, target.y * cs.z + cs.z / 2.0)
|
||||
cannon_instance.rpc("spawn_projectile_rpc", target_pos, telegraph_time)
|
||||
|
||||
# Wait telegraph duration, then apply impact
|
||||
await get_tree().create_timer(telegraph_time).timeout
|
||||
@@ -443,24 +460,34 @@ func _check_all_players_trapped() -> void:
|
||||
var all_players = get_tree().get_nodes_in_group("Players")
|
||||
for player in all_players:
|
||||
var pos = player.current_position if player.get("current_position") else Vector2i(-1, -1)
|
||||
if is_sticky_cell(pos) and not trapped_players.has(player.get("peer_id", -1)):
|
||||
if is_sticky_cell(pos) and not trapped_players.has(player.get("peer_id") if "peer_id" in player else -1):
|
||||
_trap_player(player)
|
||||
|
||||
func _trap_player(player: Node) -> void:
|
||||
var pid = player.get("peer_id", -1)
|
||||
var pid = player.get("peer_id") if "peer_id" in player else -1
|
||||
if pid == -1: return
|
||||
trapped_players[pid] = true
|
||||
print("[Gauntlet] Player %d TRAPPED at %s" % [pid, str(player.current_position)])
|
||||
emit_signal("player_trapped", pid)
|
||||
|
||||
# TODO: Apply movement lockout, score penalty, visual feedback
|
||||
# For now, just mark as trapped — will be expanded in Task #4
|
||||
# Apply visual feedback and notify
|
||||
if player.has_method("apply_stagger"):
|
||||
if _can_rpc():
|
||||
player.rpc("apply_stagger", 999.0) # Basically infinite until cleansed
|
||||
else:
|
||||
player.apply_stagger(999.0)
|
||||
|
||||
NotificationManager.send_message(player, "Stuck in Candy!", NotificationManager.MessageType.WARNING)
|
||||
|
||||
func clear_sticky_cell(pos: Vector2i) -> void:
|
||||
"""Used by Cleanser power-up to remove a sticky cell."""
|
||||
sticky_cells.erase(pos)
|
||||
if gridmap:
|
||||
gridmap.set_cell_item(Vector3i(pos.x, 2, pos.y), -1)
|
||||
|
||||
# Sync removal to clients
|
||||
if main_scene and _can_rpc():
|
||||
main_scene.rpc("sync_grid_item", pos.x, 2, pos.y, -1)
|
||||
|
||||
# =============================================================================
|
||||
# HUD
|
||||
|
||||
Reference in New Issue
Block a user