feat(gauntlet): shrink arena per phase 20x20 -> 18x18 -> 7x7; sticky cells block movement
CI / Export Linux (push) Failing after 4s
CI / Export Windows (push) Failing after 36s
CI / Export Android (push) Failing after 38s
Test Suite / Unit Tests (GUT) (push) Failing after 26s
Test Suite / Integration Tests (push) Failing after 29s
Test Suite / Code Style Check (push) Failing after 38s
CI / Create Release (push) Has been skipped
Test Suite / Security Scan (push) Failing after 51s
CI / Export Linux (push) Failing after 4s
CI / Export Windows (push) Failing after 36s
CI / Export Android (push) Failing after 38s
Test Suite / Unit Tests (GUT) (push) Failing after 26s
Test Suite / Integration Tests (push) Failing after 29s
Test Suite / Code Style Check (push) Failing after 38s
CI / Create Release (push) Has been skipped
Test Suite / Security Scan (push) Failing after 51s
This commit is contained in:
@@ -340,9 +340,12 @@ func _start_phase(phase: Phase) -> void:
|
|||||||
var phase_name = _phase_to_string(phase)
|
var phase_name = _phase_to_string(phase)
|
||||||
print("[Gauntlet] Phase changed to: ", phase_name)
|
print("[Gauntlet] Phase changed to: ", phase_name)
|
||||||
|
|
||||||
if _can_rpc():
|
if _can_rpc() and multiplayer.is_server():
|
||||||
rpc("sync_phase", int(phase), phase_name)
|
rpc("sync_phase", int(phase), phase_name)
|
||||||
|
|
||||||
|
# Update phase explicitly with setup_arena
|
||||||
|
_shrink_arena()
|
||||||
|
|
||||||
emit_signal("phase_changed", int(phase), phase_name)
|
emit_signal("phase_changed", int(phase), phase_name)
|
||||||
|
|
||||||
func _phase_to_string(phase: Phase) -> String:
|
func _phase_to_string(phase: Phase) -> String:
|
||||||
@@ -361,6 +364,14 @@ func sync_phase(phase_index: int, phase_name: String) -> void:
|
|||||||
if not is_active:
|
if not is_active:
|
||||||
activate_client_side()
|
activate_client_side()
|
||||||
current_phase = phase_index as Phase
|
current_phase = phase_index as Phase
|
||||||
|
if not multiplayer.is_server():
|
||||||
|
var bounds = get_arena_bounds()
|
||||||
|
for x in range(ARENA_COLUMNS):
|
||||||
|
for z in range(ARENA_ROWS):
|
||||||
|
var pos = Vector2i(x, z)
|
||||||
|
if pos.x <= bounds.min or pos.x >= bounds.max or pos.y <= bounds.min or pos.y >= bounds.max:
|
||||||
|
if not sticky_cells.has(pos):
|
||||||
|
sticky_cells[pos] = true
|
||||||
_update_hud_phase(phase_name)
|
_update_hud_phase(phase_name)
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -419,11 +430,12 @@ func _apply_arena_setup() -> void:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Boundary walls: perimeter (row 0, row 19, col 0, col 19)
|
# Boundary walls: perimeter (row 0, row 19, col 0, col 19)
|
||||||
if x == 0 or x == ARENA_COLUMNS - 1 or z == 0 or z == ARENA_ROWS - 1:
|
if pos.x <= 0 or pos.x >= 19 or pos.y <= 0 or pos.y >= 19:
|
||||||
# Also make border walls visually walkable floors instead of red blocks
|
# Also make border walls visually walkable floors instead of red blocks
|
||||||
gridmap.set_cell_item(Vector3i(x, 0, z), TILE_WALKABLE)
|
gridmap.set_cell_item(Vector3i(x, 0, z), TILE_WALKABLE)
|
||||||
gridmap.set_cell_item(Vector3i(x, 1, z), -1)
|
gridmap.set_cell_item(Vector3i(x, 1, z), -1)
|
||||||
gridmap.set_cell_item(Vector3i(x, 2, z), -1)
|
gridmap.set_cell_item(Vector3i(x, 2, z), TILE_STICKY)
|
||||||
|
sticky_cells[pos] = true
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Interior: walkable floor
|
# Interior: walkable floor
|
||||||
@@ -1065,9 +1077,12 @@ func is_cleansed_cell(pos: Vector2i) -> bool:
|
|||||||
|
|
||||||
func cell_state(pos: Vector2i) -> CellState:
|
func cell_state(pos: Vector2i) -> CellState:
|
||||||
"""Logical state of a playable cell (v2 ground-growth model)."""
|
"""Logical state of a playable cell (v2 ground-growth model)."""
|
||||||
|
var b = get_arena_bounds()
|
||||||
|
if pos.x <= b.min or pos.x >= b.max or pos.y <= b.min or pos.y >= b.max:
|
||||||
|
return CellState.STICKY
|
||||||
if _is_npc_zone(pos) or _is_boundary(pos):
|
if _is_npc_zone(pos) or _is_boundary(pos):
|
||||||
return CellState.BLOCKED
|
return CellState.BLOCKED
|
||||||
if sticky_cells.has(pos):
|
if is_sticky_cell(pos):
|
||||||
return CellState.STICKY
|
return CellState.STICKY
|
||||||
if cleansed_cells.has(pos):
|
if cleansed_cells.has(pos):
|
||||||
return CellState.CLEANSED
|
return CellState.CLEANSED
|
||||||
@@ -1091,8 +1106,37 @@ func _tick_cleansed_cells(delta: float) -> void:
|
|||||||
for pos in expired:
|
for pos in expired:
|
||||||
cleansed_cells.erase(pos)
|
cleansed_cells.erase(pos)
|
||||||
|
|
||||||
|
func get_arena_bounds() -> Dictionary:
|
||||||
|
match current_phase:
|
||||||
|
Phase.OPEN_ARENA:
|
||||||
|
return {"min": 0, "max": 19} # 20x20
|
||||||
|
Phase.ROUTE_PRESSURE:
|
||||||
|
return {"min": 1, "max": 18} # 18x18
|
||||||
|
Phase.SURVIVAL_ENDGAME:
|
||||||
|
return {"min": 6, "max": 12} # 7x7
|
||||||
|
return {"min": 0, "max": 19}
|
||||||
|
|
||||||
|
func _shrink_arena() -> void:
|
||||||
|
if not multiplayer.is_server(): return
|
||||||
|
var b = get_arena_bounds()
|
||||||
|
var new_sticky = []
|
||||||
|
for x in range(ARENA_COLUMNS):
|
||||||
|
for z in range(ARENA_ROWS):
|
||||||
|
var pos = Vector2i(x, z)
|
||||||
|
if _is_npc_zone(pos) or _is_boundary(pos):
|
||||||
|
continue
|
||||||
|
if pos.x <= b.min or pos.x >= b.max or pos.y <= b.min or pos.y >= b.max:
|
||||||
|
if not sticky_cells.has(pos):
|
||||||
|
new_sticky.append(pos)
|
||||||
|
|
||||||
|
if new_sticky.size() > 0:
|
||||||
|
if _can_rpc() and multiplayer.is_server():
|
||||||
|
rpc("sync_growth_apply", new_sticky)
|
||||||
|
else:
|
||||||
|
sync_growth_apply(new_sticky)
|
||||||
|
|
||||||
func _is_boundary(pos: Vector2i) -> bool:
|
func _is_boundary(pos: Vector2i) -> bool:
|
||||||
return pos.x == 0 or pos.x == ARENA_COLUMNS - 1 or pos.y == 0 or pos.y == ARENA_ROWS - 1
|
return pos.x <= 0 or pos.x >= ARENA_COLUMNS - 1 or pos.y <= 0 or pos.y >= ARENA_ROWS - 1
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Coverage tracking (v2 target: 70-75%, down from v1's 80%)
|
# Coverage tracking (v2 target: 70-75%, down from v1's 80%)
|
||||||
@@ -1103,12 +1147,15 @@ const COVERAGE_TARGET_MAX: float = 0.75
|
|||||||
|
|
||||||
func playable_cell_count() -> int:
|
func playable_cell_count() -> int:
|
||||||
"""Number of cells that can ever become sticky (interior, minus NPC zone)."""
|
"""Number of cells that can ever become sticky (interior, minus NPC zone)."""
|
||||||
|
var b = get_arena_bounds()
|
||||||
var count := 0
|
var count := 0
|
||||||
for x in range(ARENA_COLUMNS):
|
for x in range(ARENA_COLUMNS):
|
||||||
for z in range(ARENA_ROWS):
|
for z in range(ARENA_ROWS):
|
||||||
var pos := Vector2i(x, z)
|
var pos := Vector2i(x, z)
|
||||||
if _is_boundary(pos) or _is_npc_zone(pos):
|
if _is_boundary(pos) or _is_npc_zone(pos):
|
||||||
continue
|
continue
|
||||||
|
if pos.x <= b.min or pos.x >= b.max or pos.y <= b.min or pos.y >= b.max:
|
||||||
|
continue
|
||||||
count += 1
|
count += 1
|
||||||
return count
|
return count
|
||||||
|
|
||||||
@@ -1132,6 +1179,9 @@ const FORCED_TRAP_WINDOW: float = 30.0 # final seconds where trapping is allowed
|
|||||||
|
|
||||||
func _is_cell_passable(pos: Vector2i, extra_sticky: Dictionary = {}) -> bool:
|
func _is_cell_passable(pos: Vector2i, extra_sticky: Dictionary = {}) -> bool:
|
||||||
"""Can a player stand on / move through this cell, given a hypothetical sticky set?"""
|
"""Can a player stand on / move through this cell, given a hypothetical sticky set?"""
|
||||||
|
var b = get_arena_bounds()
|
||||||
|
if pos.x <= b.min or pos.x >= b.max or pos.y <= b.min or pos.y >= b.max:
|
||||||
|
return false
|
||||||
if _is_boundary(pos) or _is_npc_zone(pos):
|
if _is_boundary(pos) or _is_npc_zone(pos):
|
||||||
return false
|
return false
|
||||||
if sticky_cells.has(pos) or extra_sticky.has(pos):
|
if sticky_cells.has(pos) or extra_sticky.has(pos):
|
||||||
@@ -1390,15 +1440,21 @@ func _bubble_score_unfair_trap(pos: Vector2i) -> float:
|
|||||||
func _bubble_blast_cells(center: Vector2i) -> Array:
|
func _bubble_blast_cells(center: Vector2i) -> Array:
|
||||||
"""The 3x3 (radius 1) sticky cells a bubble at `center` would create,
|
"""The 3x3 (radius 1) sticky cells a bubble at `center` would create,
|
||||||
clipped to passable/playable cells."""
|
clipped to passable/playable cells."""
|
||||||
|
var b = get_arena_bounds()
|
||||||
var cells: Array = []
|
var cells: Array = []
|
||||||
for dx in range(-BUBBLE_EXPLOSION_RADIUS, BUBBLE_EXPLOSION_RADIUS + 1):
|
for dx in range(-BUBBLE_EXPLOSION_RADIUS, BUBBLE_EXPLOSION_RADIUS + 1):
|
||||||
for dz in range(-BUBBLE_EXPLOSION_RADIUS, BUBBLE_EXPLOSION_RADIUS + 1):
|
for dz in range(-BUBBLE_EXPLOSION_RADIUS, BUBBLE_EXPLOSION_RADIUS + 1):
|
||||||
var c := center + Vector2i(dx, dz)
|
var c := center + Vector2i(dx, dz)
|
||||||
if _is_boundary(c) or _is_npc_zone(c):
|
if _is_boundary(c) or _is_npc_zone(c):
|
||||||
continue
|
continue
|
||||||
|
if c.x <= b.min or c.x >= b.max or c.y <= b.min or c.y >= b.max:
|
||||||
|
continue
|
||||||
cells.append(c)
|
cells.append(c)
|
||||||
return cells
|
return cells
|
||||||
|
|
||||||
|
func _bubble_footprint(center: Vector2i) -> Array:
|
||||||
|
return _bubble_blast_cells(center)
|
||||||
|
|
||||||
func _any_cleanser_holder_near(pos: Vector2i) -> bool:
|
func _any_cleanser_holder_near(pos: Vector2i) -> bool:
|
||||||
"""True if a player holding a Cleanser charge is within the camping region."""
|
"""True if a player holding a Cleanser charge is within the camping region."""
|
||||||
for player in get_tree().get_nodes_in_group("Players"):
|
for player in get_tree().get_nodes_in_group("Players"):
|
||||||
|
|||||||
@@ -165,9 +165,8 @@ func simple_move_to(grid_position: Vector2i) -> bool:
|
|||||||
gm.use_cleanser_cell(pid)
|
gm.use_cleanser_cell(pid)
|
||||||
print("[Move] Cleanser cleared sticky cell at %s (%d cells left)" % [grid_position, gm.cleanser_cells_left.get(pid, 0)])
|
print("[Move] Cleanser cleared sticky cell at %s (%d cells left)" % [grid_position, gm.cleanser_cells_left.get(pid, 0)])
|
||||||
else:
|
else:
|
||||||
print("[Move] Player stepping into sticky cell at %s — slowed" % grid_position)
|
print("[Move] Failed: Blocked by Gauntlet Sticky cell at %s" % grid_position)
|
||||||
if player.is_multiplayer_authority() or multiplayer.is_server():
|
return false
|
||||||
gm.apply_sticky_slow(player)
|
|
||||||
|
|
||||||
rotate_towards_target(grid_position)
|
rotate_towards_target(grid_position)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user