Debug scatter command, and put pawn movement on the game clock #96
No reviewers
Labels
No labels
assets
bug
duplicate
enhancement
help wanted
invalid
question
testing
ui
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
liamjd/UntitledColonyBuilder!96
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "95-debug-scatter-command"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #95
Adds the
Xdebug command: every idle pawn walks to a random reachable tile. This is milestone #4's proof that navigation works in the real game, replacing #81's right-click move order — scaffolding for a mechanic the design docs rule out, which would have needed selection, input arbitration and unreachable feedback before a pawn took a step.It proves more of the stack than #80's probe could. That probe drives
PawnViewby hand at a fixed delta on a stamped grid; this exercisesPawns.move_to(), the real frame loop, generated terrain and several pawns at once.The bug it immediately exposed
PawnViewwalked on the raw frame delta. Opening the main menu pausedGameClockand the pawns carried on walking — andGameClock.speedwas ignored by everything in the project, so a speed control would have left pawns at 1×. Same root cause, so it is fixed once.GameClock.delta_for(real_delta)now owns the conversion from real to simulated time, andPawnViewasks it rather than the engine. Its doc comment states the rule for future callers: nothing simulating should read the engine's delta directly.Why not
get_tree().paused. Only four things consume delta, and the split is not "paused vs not" but simulation vs presentation: the clock must always run, the camera should keep working while paused so the player can look around, and onlyPawnViewis simulation. Tree pause would freeze the camera unless nearly everything were annotated as an exception.Why not the
ticksignal. Pause and speed would come free, but at 10 ticks/sec the motion is visibly stepped. Movement is the presentation of a simulated quantity, so it wants smooth interpolation driven by simulated time.delta_for()mirrorsadvance()'s guards, so a negative delta or a negative speed returns zero rather than walking a pawn backwards along its path.Also fixed:
GameClock.reset()nowhas a getter returning_nowand no setter, soreset()wrote the backing field while_nowkept its value — the clock did not reset. Nothing calls it yet, which is why it had not bitten; it would have failed on the first map regeneration or second colony.A test that was passing for the wrong reason
Raising the base pawn speed to 2.0 broke
test_the_record_follows_the_view_across_the_map, which hard-coded_process(2.0)on an unstated assumption of 1 tile/second. At 2.0 the pawn completed the whole 4-tile path inside that one call, so "mid-path" was no longer true.The defect was the test's, not the speed change: its intent is "part-way along a walk, the record tracks the capsule", which has nothing to do with the default speed. A helper now expresses the delta in tiles, so it means the same thing at any speed.
test_stopping_a_pawn_idles_it_and_drops_the_pathhad the same brittleness and is fixed alongside. It still passed at 2.0, but at 4.0 the pawn would have arrived beforestop()was called and the test would have gone green for the wrong reason — silent, and worse than the failure that was actually hit.Verification
343 tests, 342 passing, 1 pre-existing pending (
test_task_tree, tracked as #85). Up 11 tests and 19 asserts.delta_for()— passthrough at 1×, scaling at 3×, zero while paused, zero at 0×, zero for a negative delta or speed, and that it is a pure query: 100 calls emit no ticks and do not movenow. That last one matters, because it is called every frame by every mover and an implementation that banked into the accumulator would make the tick rate depend on how many pawns exist.MOVINGwith a path; a pawn already walking keeps the exact path it had; both from the same call, so an implementation that scattered everyone fails even though it passes the first test; a mapless registry is a quiet no-op; an empty registry is safe.The destination is deliberately unasserted — it is random by design, and
random_walkable_position()draws from the main landmass so anything it returns is routable.Both pawn test scripts now pin
GameClock.pausedinbefore_each. It is global mutable state on an autoload, and one script leaving it set would break unrelated tests in ways that look like movement bugs.Left undone
The
find_path()-returns-empty branch ofmove_to()is still unit-test-only.random_walkable_position()only returns tiles on the main landmass, so scatter cannot produce an unreachable destination. Forcing it in-game needs a separate island or a target beyonddestination_snap_radius, and neither justifies a bespoke debug affordance. Worth revisiting with #83, where a placed building cutting an in-flight path makes blocked routes ordinary.#92 (smoothing the vertical step between terraces) is untouched and still open.
🤖 Generated with Claude Code
https://claude.ai/code/session_012V5CmAgcjna6fBrgZebqjZ