118 lines
4.9 KiB
GDScript
118 lines
4.9 KiB
GDScript
extends GutTest
|
|
|
|
# =============================================================================
|
|
# Test: Gauntlet Cleanser Power-Up (v2) [Gauntlet #072]
|
|
# Covers grant cadence (every 2 missions, max 1), 5-cell immunity lifecycle,
|
|
# sticky clearing, stun-blocked activation, and the safe-stop early termination.
|
|
# Runs headless; uses a GridMap mock so clear_sticky_cell can run locally.
|
|
# =============================================================================
|
|
|
|
const GauntletManager = preload("res://scripts/managers/gauntlet_manager.gd")
|
|
const GridMapMock = preload("res://tests/helpers/gridmap_mock.gd")
|
|
const MainMock = preload("res://tests/helpers/main_mock.gd")
|
|
var manager
|
|
var main_mock: Node
|
|
var gridmap_mock: Node
|
|
|
|
func before_each():
|
|
main_mock = MainMock.new()
|
|
add_child(main_mock)
|
|
gridmap_mock = GridMapMock.new()
|
|
gridmap_mock.name = "EnhancedGridMap"
|
|
main_mock.add_child(gridmap_mock)
|
|
manager = GauntletManager.new()
|
|
main_mock.add_child(manager)
|
|
manager.initialize(main_mock, gridmap_mock)
|
|
manager.current_phase = 0
|
|
|
|
func after_each():
|
|
if main_mock:
|
|
main_mock.queue_free()
|
|
|
|
func _without_peer(fn: Callable) -> void:
|
|
var saved = multiplayer.multiplayer_peer
|
|
multiplayer.multiplayer_peer = null
|
|
fn.call()
|
|
multiplayer.multiplayer_peer = saved
|
|
|
|
# =============================================================================
|
|
# Grant cadence: every 2 missions, inventory max 1
|
|
# =============================================================================
|
|
|
|
func test_no_cleanser_after_one_mission():
|
|
manager._on_goal_count_updated(7, 1)
|
|
assert_eq(manager.player_cleansers.get(7, 0), 0, "No cleanser after 1 mission")
|
|
|
|
func test_cleanser_granted_after_two_missions():
|
|
manager._on_goal_count_updated(7, 1)
|
|
manager._on_goal_count_updated(7, 2)
|
|
assert_eq(manager.player_cleansers.get(7, 0), 1, "Cleanser granted after 2 missions")
|
|
|
|
func test_cleanser_inventory_capped_at_one():
|
|
# Four missions would be two grants. The new rule allows them to stack.
|
|
for i in range(4):
|
|
manager.player_mission_completions[7] = i + 1
|
|
manager._on_goal_count_updated(7, i + 1)
|
|
assert_eq(manager.player_cleansers.get(7, 0), 2, "Cleansers now stack")
|
|
|
|
# =============================================================================
|
|
# Activation / immunity lifecycle
|
|
# =============================================================================
|
|
|
|
func test_use_cleanser_cell_decrements_until_exhausted():
|
|
manager.cleanser_active[3] = true
|
|
manager.cleanser_cells_left[3] = manager.CLEANSER_MAX_CELLS
|
|
# First 4 uses keep it active...
|
|
for i in range(manager.CLEANSER_MAX_CELLS - 1):
|
|
assert_true(manager.use_cleanser_cell(3), "Still active on use %d" % (i + 1))
|
|
# ...the 5th use exhausts it.
|
|
assert_false(manager.use_cleanser_cell(3), "Exhausted after 5th cell")
|
|
assert_false(manager.is_cleanser_active(3), "Deactivated after 5th cell")
|
|
|
|
func test_use_cleanser_cell_when_inactive_returns_false():
|
|
assert_false(manager.use_cleanser_cell(99), "Inactive cleanser use returns false")
|
|
|
|
func test_deactivate_clears_state():
|
|
manager.cleanser_active[5] = true
|
|
manager.cleanser_cells_left[5] = 3
|
|
manager.deactivate_cleanser(5)
|
|
assert_false(manager.is_cleanser_active(5), "Deactivated")
|
|
assert_false(manager.cleanser_cells_left.has(5), "Cells-left cleared")
|
|
|
|
# =============================================================================
|
|
# Sticky clearing
|
|
# =============================================================================
|
|
|
|
func test_clear_sticky_cell_removes_and_protects():
|
|
manager.sticky_cells[Vector2i(4, 4)] = true
|
|
_without_peer(func():
|
|
manager.clear_sticky_cell(Vector2i(4, 4))
|
|
)
|
|
assert_false(manager.is_sticky_cell(Vector2i(4, 4)), "Sticky removed")
|
|
assert_true(manager.is_cleansed_cell(Vector2i(4, 4)), "Cleared cell gets regrowth protection")
|
|
# Layer-2 overlay cleared (mock records -1 = erased).
|
|
assert_eq(gridmap_mock.get_cell_item(Vector3i(4, 2, 4)), -1, "Layer-2 sticky overlay cleared")
|
|
|
|
# =============================================================================
|
|
# Safe-stop early termination (#072 acceptance: ends when stopping on safe cell)
|
|
# =============================================================================
|
|
|
|
func test_stop_on_safe_cell_keeps_cleanser():
|
|
manager.cleanser_active[8] = true
|
|
manager.cleanser_cells_left[8] = 3
|
|
|
|
manager.notify_movement_stopped(8, Vector2i(5, 5)) # safe cell
|
|
assert_true(manager.is_cleanser_active(8), "Cleanser NO LONGER ends on safe-cell stop (persists charges)")
|
|
|
|
func test_stop_on_sticky_cell_keeps_cleanser():
|
|
manager.sticky_cells[Vector2i(6, 6)] = true
|
|
manager.cleanser_active[8] = true
|
|
manager.cleanser_cells_left[8] = 3
|
|
manager.notify_movement_stopped(8, Vector2i(6, 6)) # still on sticky
|
|
assert_true(manager.is_cleanser_active(8), "Cleanser persists while still on sticky")
|
|
|
|
func test_notify_stop_noop_without_cleanser():
|
|
# Should not crash or change anything when the player has no cleanser.
|
|
manager.notify_movement_stopped(123, Vector2i(5, 5))
|
|
assert_false(manager.is_cleanser_active(123), "No cleanser → no-op")
|