Team 4 Rooms and Dungeons Test Plan
Overview
This test plan covers the Team 4 branches for Sprint 3. Testing is divided into automated unit tests and manual gameplay tests.
Automated Unit Test Plan
General Bug Fixes — small_general_bugs
RunTimerTest
The pause/resume cases were added on this branch. The remaining cases provide existing timer regression coverage.
| Test |
Purpose |
Expected Result |
totalTimeDoesNotAdvanceBeforeRunStarts |
Update a timer before starting a run. |
Total time remains zero. |
startRunBeginsAccumulatingTotalTime |
Advance a running timer through several frames. |
Total time accumulates the supplied deltas. |
startRunIsANoOpWhileAlreadyRunning |
Start an already running timer. |
Previously accumulated time is not reset. |
dungeonTimeIsZeroWhenNoDungeonActive |
Advance a run without entering a dungeon. |
The dungeon ID is null and both dungeon clocks remain zero. |
startDungeonTracksTimeRelativeToRunStart |
Enter a dungeon after the run has already begun. |
Dungeon time counts only from dungeon entry. |
startDungeonSwitchesAndSavesPreviousDungeonWhileAlreadyRunning |
Switch between active dungeons. |
The previous dungeon's elapsed time is saved and the new dungeon becomes current. |
stopDungeonClearsDungeonStateButRunKeepsGoing |
Leave a dungeon and continue the run. |
No dungeon remains active; total run time continues increasing. |
stopRunFreezesBothTotalAndDungeonTime |
Stop the run and advance the clock. |
Total and dungeon time remain unchanged. |
dungeonSyncedTimeUsesWholeSecondBoundariesOfTheRunClock |
Enter between whole-second boundaries. |
The displayed dungeon clock aligns with whole seconds of the run clock. |
clampsAbnormallyLargeDeltaSpikes |
Supply a three-second frame delta. |
Only 0.25 seconds are accumulated for that frame. |
formatTimeIncludesHundredths |
Format elapsed time with fractional seconds. |
Results include minutes, seconds and hundredths. |
formatTimeWithNoMilliSecDropsFraction |
Format time without fractions. |
Fractional seconds are dropped rather than rounded up. |
pauseStopsTimeFromAdvancing |
Pause after five seconds and supply further updates. |
Total time remains five seconds. |
resumeContinuesFromWhereItLeftOff |
Pause, resume, then advance another three seconds. |
Total time continues from five to eight seconds, excluding the paused interval. |
AchievementsFactoryTest.Gold
These tests cover the updated rule that the first gold reading establishes a baseline; subsequent progress is measured relative to it.
| Test |
Purpose |
Expected Result |
update_firstReadingAlone_establishesBaselineWithoutUnlocking |
Start with a gold total equal to the achievement target. |
The first reading establishes the baseline; progress is zero and the achievement stays locked. |
update_earningGoldAfterBaseline_tracksTheDelta |
Establish a baseline of 50 and then report 90 gold. |
Progress becomes 40. |
update_goldReachesTargetAboveBaseline_unlocks |
Reach the target relative to the baseline. |
The achievement unlocks. |
update_goldAboveTargetAboveBaseline_unlocks |
Exceed the target relative to the baseline. |
The achievement unlocks. |
update_startingWithExistingGold_onlyCountsFurtherEarnings |
Start with 50 gold and earn another 100. |
Starting gold does not count; unlocking occurs at a total of 150. |
update_nullGoldTotal_staysLockedWithoutThrowing |
Supply a null gold reading. |
The reading is ignored without an exception. |
update_nullReadingBeforeBaseline_doesNotEstablishABaseline |
Supply null before the first valid total. |
The valid total establishes the baseline. |
update_goldReachesTargetOverSeveralUpdates_unlocksOnceTargetIsReached |
Report several increasing totals. |
The achievement stays locked until earned progress reaches the target. |
Run the entire AchievementsFactoryTest, including its unchanged Build, DungeonClear, DungeonReached, EnemyKillCount, KillStreak, SpeedRun and EnemySet nested suites. These check type validation, initial state, matching dungeon events, filtered kill counts, streak resets, timing limits, distinct enemy types and independent achievement instances. They do not establish that achievement progress survives a save/load round trip.
Dungeon Layouts and Tiles — tileSetAppearance
ObstacleFactoryTest — directional-wall version
| Test |
Purpose |
Expected Result |
rockIsRenderedStaticObstacleWithBoxCollider |
Create a rock and its physics fixture. |
It has a renderer, a static body, the obstacle layer and a four-vertex collider. |
barrelIsRenderedStaticObstacleWithBoxCollider |
Create a barrel and its fixture. |
It has a renderer, a static body, the obstacle layer and a four-vertex collider. |
swordIsRenderedStaticObstacleWithBoxCollider |
Create the added sword obstacle. |
It has a renderer, a static body, the obstacle layer and a four-vertex collider. |
wallIsStaticObstacleWithEightVertexColliderCase1 |
Create an UP wall. |
A static obstacle with eight collider vertices is created. |
wallIsStaticObstacleWithEightVertexColliderCase2 |
Create a LEFT wall. |
A static obstacle with eight collider vertices is created. |
wallIsStaticObstacleWithEightVertexColliderCase3 |
Create a RIGHT wall. |
A static obstacle with eight collider vertices is created. |
wallIsStaticObstacleWithEightVertexColliderCase4 |
Create a DOWN wall. |
A static obstacle with eight collider vertices is created. |
wallIsStaticObstacleWithEightVertexColliderCase5 |
Create a DOWN_RIGHT corner. |
A static obstacle with eight collider vertices is created. |
wallIsStaticObstacleWithEightVertexColliderCase6 |
Create a DOWN_LEFT corner. |
A static obstacle with eight collider vertices is created. |
wallIsStaticObstacleWithEightVertexColliderCase7 |
Create an UP_RIGHT corner. |
A static obstacle with eight collider vertices is created. |
wallIsStaticObstacleWithEightVertexColliderCase8 |
Create an UP_LEFT corner. |
A static obstacle with eight collider vertices is created. |
wallIsStaticObstacleWithEightVertexColliderCase9 |
Supply no wall directions. |
The factory returns null. |
shortWallColliderIsHalfTileAndBottomAligned |
Inspect a DOWN wall's collider bounds. |
Width and height are half the entity scale; the collider is horizontally centred and bottom-aligned. |
tallWallColliderIsHalfTileAndBottomAligned |
Inspect an UP wall's collider bounds. |
Width is half the entity scale, but height is the full entity height; the collider is centred and bottom-aligned. |
tileColliderHasNoSquareCorners |
Inspect the bevelled wall vertices. |
No vertex lies at a square corner of the collider's bounding box. |
wallIsStaticObstacleWithGivenScale |
Create an invisible wall sized 3 by 2. |
It is a static obstacle with the requested scale and no texture renderer. |
constructorThrows |
Attempt to instantiate the factory through reflection. |
Construction throws IllegalStateException. |
The tall-wall test's name still says “HalfTile”, but its assertion requires full collider height. These tests verify fixture geometry and component wiring, not visual tilesheet selection.
RoomManagerTest
This class was updated for changed room coordinates/arrival offsets and adapted to minimap integration. It is shared regression coverage, not a dedicated minimap test.
| Test |
Purpose |
Expected Result |
shouldFollowPairedDoorsAndRememberClearedRooms |
Move from dungeonOneEntrance to dungeonOneSide and back. |
Disposal is deferred until update; old rooms are disposed; the cleared entrance is rebuilt as cleared. In the reviewed tile-layout snapshot, the mocked arrival positions are (25, 63) and (52, 50). |
shouldScaleRoomOnStart |
Start a room through the lightweight test constructor. |
The enemy manager receives scale(0). |
Arrival coordinates above are assertions in a mocked tile-to-world setup, not a claim about screen pixels or real-world spawn coordinates.
GameAreaTest
| Test |
Purpose |
Expected Result |
shouldSpawnEntities |
Register an entity through a game area, then dispose the area. |
The entity is created and subsequently disposed. |
This existing lifecycle test was adapted to the TerrainBuilder rename. It does not directly exercise JSON terrain generation.
FinalBossStageTwoFireIntegrationTest
The tile branch adds six wall-collision regressions and adjusts the existing static-wall impact expectation to account for fireball radius.
| Test |
Purpose |
Expected Result |
realStaticWallStopsAFastFireballBeforeThePlayerBehindIt |
Send a fast fireball toward a real static wall with the player behind it. |
The fireball is consumed at the radius-adjusted impact position and the player remains unharmed. |
fireballCannotPassBetweenAdjacentRoomSideWallTiles |
Aim through the gap between actual side-wall fixtures. |
The fireball stops before crossing the wall; the player behind it is unharmed. |
fireballCannotPassBetweenAdjacentRoomTopWallTiles |
Aim through the gap between actual top-wall fixtures. |
The fireball stops at the wall without damaging the player behind it. |
fireballEdgeStopsAtAWallEvenWhenItsCentreMisses |
Graze a wall with the fireball's radius. |
The edge collision consumes the fireball and creates one impact. |
fireballOutsideARoundedWallCornerIsNotBlockedByItsExpandedBoundingBox |
Pass near a corner without actually overlapping it. |
The fireball continues and no false impact is created. |
stationaryFireballAlreadyOverlappingAWallIsConsumed |
Place a stationary fireball overlapping a wall. |
It is consumed and creates one impact at its position. |
dynamicBodiesDoNotShieldThePlayerFromFireballs |
Put a dynamic body between the fireball and player. |
The body does not act as a blocking wall; the player takes damage. |
Run the rest of this integration class as regression coverage:
| Existing test(s) |
Purpose |
Expected Result |
transformationDoesNotFireOrConsumeTheInitialFiringDelay |
Advance through the transformation and initial attack delay. |
No premature volley is emitted. |
crossingIntoPauseMovesExistingBallsWithoutFiringAnotherVolley |
Cross the boss's firing/rest boundary. |
Existing fireballs move during the attack pause; new firing waits for the next attack period. This is not a game-menu pause test. |
normalAttacksAreBlockedAndAnIceHitAtSixtyPercentClearsAllFire |
Try normal damage, then qualifying ice damage. |
Normal damage is blocked; the stage transition clears all fire. |
playerDeathClearsProjectilesBeforeAnotherShotCanHit; lethalFireballClearsTheRemainingVolleyDuringTheDamageCallback |
Kill the player before or during volley processing. |
Remaining hazards are cleared without extra damage callbacks. |
bossDeathClearsFireImmediatelyAndDoesNotRespawnIt; disposalClearsFireAndPreventsLaterUpdatesFromAttacking; losingTheArenaRemovesFireRatherThanLeavingInvisibleHazards |
End or invalidate the encounter. |
Fire is cleared and cannot continue attacking. |
staticSensorsDoNotShieldThePlayerFromFireballs |
Put a static sensor in the shot's path. |
Sensors do not block fireball damage. |
bossInsideARealWallCannotSpawnAVolleyThroughItsSurface; wallsBetweenTheBossAndItsEmissionRingCannotBeSkippedDuringSpawn |
Spawn volleys near enclosing walls. |
Volley spawning cannot bypass walls. |
changingBossScaleChangesTheRadiusOfItsNextVolley |
Resize the boss before a new volley. |
The new emission radius follows the boss's scale. |
playerPhysicsPositionIsRefreshedBeforeSweepingThePlayersMovement |
Move the physics body before the entity position refresh. |
Swept collision uses the current physics position and detects the hit. |
fourHalfDamageHitsConsumeEveryShotAndImpactButRemoveOnlyTwoHealth; halfDamageRemainderSurvivesNewVolleysAndTheFiringPause |
Apply fractional-damage hits over multiple volleys. |
Shots are consumed individually and fractional health damage accumulates correctly. |
restartingTheEncounterDiscardsThePreviousHalfDamage; leavingTheStageClearsPendingHalfDamageAndPreventsAnyQueuedHit |
Restart or leave the encounter with a pending damage remainder. |
Old fractional damage does not leak into the next encounter or stage. |
localZeroDamageNeitherAddsHalfDamageNorDiscardsAnEarlierEffectiveHalf; invulnerabilityNeitherAddsHalfDamageNorDiscardsAnEarlierEffectiveHalf; concealmentNeitherAddsHalfDamageNorDiscardsAnEarlierEffectiveHalf |
Block hits after accumulating partial damage. |
Blocked hits neither contribute damage nor erase valid earlier fractions. |
timedShieldPreservesEarlierHealthRemainderWithoutLeakingItsOwnHalfOnExpiry; absorbShieldLosesOnePointPerPairAndItsRemainingHalfExpiresWithTheShield; consumableShieldNeitherAddsHalfDamageNorDiscardsEarlierEffectiveHalfOnExpiry |
Apply fractional hits through different shield lifecycles. |
Shield damage/remainders remain separate from health damage and expire appropriately. |
aHalfDamageLethalHitClearsTheRestOfItsVolleySynchronously; synchronousDisposalOnAWholeDamageTickDoesNotProcessTheRestOfTheVolley |
Trigger death or disposal while processing a hit. |
The remaining volley is not processed after cleanup. |
positiveIntegerDamageStillAppliesFullyOnEveryHit |
Use whole-number fireball damage. |
Every effective hit applies its full configured damage. |
Minimap — team4/minimap
MinimapTest
| Test |
Purpose |
Expected Result |
correctlyDeterminesRoomType |
Classify cleared, starting, unknown and null room IDs. |
They resolve to CLEARED, HOME, DEFAULT and DEFAULT respectively. |
shouldClearTablesWhenRebuilding |
Rebuild the minimap for a room change. |
Old left/right room icons are cleared. |
attachesOnlyLeftRooms |
Supply two exits whose side is LEFT. |
Two destination icons are attached to the left table and none to the right. |
attachesOnlyRightRooms |
Supply two exits whose side is RIGHT. |
Two destination icons are attached to the right table and none to the left. |
attachesListenerOnCreate |
Create the minimap with mocked rendering/assets. |
It registers a listener for RoomChanged. |
shouldRebuildAndSetRoomOnRoomChange |
Send a new room configuration. |
The current room is updated and both side tables are cleared for rebuilding. |
ShapeActorTest
| Test |
Purpose |
Expected Result |
shouldStartAndFinishShapeRendering |
Draw a shape actor. |
The renderer begins and ends a shape-rendering pass. |
shouldSetShapeColor |
Draw a white shape. |
The configured colour is passed to the renderer. |
shouldSetRendererToBatchProjectionMatrix |
Draw with a supplied batch projection. |
The shape renderer receives the same projection matrix. |
shouldDrawShapeFillOption |
Draw outlined and filled shapes. |
They select ShapeType.Line and ShapeType.Filled respectively. |
Room Debug Commands — room-debug-command
No automated test files were added or changed by this branch's feature commits. The existing RoomManagerTest checks ordinary room transitions, but does not directly test command parsing, debugSwitchRoom() or its arrival fallbacks. Test these manually below and treat dedicated command tests as a coverage gap.
Wall-Clipping Fix — task/199-wall-clip
ObstacleFactoryTest — original tile version
| Test |
Purpose |
Expected Result |
rockIsRenderedStaticObstacleWithBoxCollider |
Construct a rock fixture. |
It is rendered and uses a static, four-vertex obstacle collider. |
barrelIsRenderedStaticObstacleWithBoxCollider |
Construct a barrel fixture. |
It is rendered and uses a static, four-vertex obstacle collider. |
tileIsStaticObstacleWithEightVertexCollider |
Construct the original tile obstacle. |
It has a static body on the obstacle layer and eight collider vertices. |
tileColliderIsHalfTileAndBottomAligned |
Measure the tile's collider. |
It is half-width and half-height, horizontally centred and bottom-aligned. |
tileColliderHasNoSquareCorners |
Inspect every collider vertex. |
Square bounding-box corners have been bevelled away. |
wallIsStaticObstacleWithGivenScale |
Create an invisible wall. |
The requested size is retained and no renderer is attached. |
constructorThrows |
Attempt factory construction. |
The utility-class constructor throws IllegalStateException. |
On the integrated version, use the directional-wall tests listed under tileSetAppearance. Do not expect the removed createTile() test names to exist there. Collider geometry assertions do not prove that a moving player never snags; that requires the manual movement tests below.
Repeated Contact Damage and Balancing — team4/touch-attack-fix
TouchAttackComponentTest
Most repeat tests use 100 target health, 10 attack damage and a one-second interval. These are test-fixture values, not the balanced enemy values in the game configuration.
| Test |
Purpose |
Expected Result |
shouldAttack |
Start contact with a matching target layer. |
An immediate hit applies damage. |
shouldNotAttackOtherLayer |
Start contact with a non-target layer. |
Health is unchanged. |
shouldNotAttackWithoutCombatComponent |
Touch an entity without combat stats. |
No exception is thrown. |
repeatsOnlyAfterIntervalAndStopsOnExit |
Start contact, advance half/whole intervals, leave and re-enter. |
Damage occurs immediately and after one second, stops on exit and occurs immediately on re-entry. |
existingConstructorsRemainEntryOnly |
Use either original constructor and continue updating. |
Only the initial contact hit occurs. |
multipleFixturesShareOneCooldownUntilLastExit |
Touch two fixtures of one target and remove them individually. |
No duplicate entry hit; repetition continues until the last fixture leaves. |
targetsHaveIndependentCooldownsAndLongFramesDoNotBurst |
Touch targets at different times and then supply a long frame. |
Timers remain independent; at most one repeat hit per target occurs in an update. |
frozenTargetStillTakesRepeatedDamage |
Freeze the victim while maintaining contact. |
Both initial and repeated damage still apply. |
frozenAttackerResumesAfterThawingWithoutNewContact |
Freeze the attacker, maintain contact, then remove freeze. |
Damage is blocked while frozen and resumes without re-entry. |
concealedTargetCanBeHitAfterRevealWithoutReentering |
Conceal the victim, maintain contact, then remove concealment. |
Damage is blocked while concealed and resumes after reveal. |
deadOrDisposedAttackerStopsRepeating |
Kill or dispose the attacking component. |
Later updates and post-disposal contact events cause no additional damage. |
rejectsInvalidRepeatIntervals |
Supply zero, negative, infinite or NaN intervals. |
Construction throws IllegalArgumentException. |
SplitComponentTest
| Test |
Purpose |
Expected Result |
shouldNotSpawnChildrenBeforeEntityServiceUpdate |
Trigger a hit reaction and death before the service update. |
No child event is emitted immediately. |
shouldScaleChildHealthAndAttackWithTheParent |
Scale a parent, kill it and process the deferred split. |
The tested parent has 60 maximum health and 3 attack; each child has 45 health/maximum health and 1 attack. |
shouldSplitCrabAfterFourNormalHits |
Deal four 10-damage hits to an unscaled Crab. |
It starts at 40 health/2 attack and splits only after the lethal fourth hit, on the next entity-service update. Two children have 30 health/1 attack and cannot split again. |
shouldSplitMedusaAfterFourNormalHits |
Repeat the same sequence with Medusa. |
The same parent/child health, attack and deferred-splitting rules apply. |
shouldCreateChildrenWithoutSplitComponent |
Process a lethal split. |
Neither child has SplitComponent. |
shouldSplitOnlyOnce |
Trigger repeated hit reactions around death and updates. |
Exactly two child events are emitted in total. |
shouldDisposeOriginalOnEntityServiceUpdate |
Kill the parent and process the deferred work. |
The parent is not unregistered immediately and is unregistered once during the service update. |
ChaseEnemyTest
| Test |
Purpose |
Expected Result |
shouldHaveChaseEnemyAnimations |
Build Crab and Medusa. |
Both have default, movement, chase and death animations. |
testChaseEnemyKnockbackOnPlayerCollision |
Trigger contact with a player at 20 health. |
Health falls to 18 and one hit-reaction event is emitted. The test does not measure the physical knockback impulse. |
testChaseEnemyDoesNotKnockbackOnNonPlayerCollision |
Trigger contact with an NPC-layer entity. |
No hit-reaction event is emitted on the player. |
shouldUseConfiguredHealthAndAttack |
Build an unscaled chase enemy. |
Health/maximum health are 40 and base attack is 2. |
shouldStartDefaultAnimationImmediately |
Build a non-splitting child-form enemy. |
Its default animation is already selected. |
Manual Gameplay Test Plan
The rows below are proposed checks, not claims of completed testing. For combined-feature cases, use the integrated revision containing all six branches. Debug jumps help reach a room but do not replace testing normal dungeon progression.
General Bug Fixes
| Test |
Steps |
Expected Result |
| Inventory pause |
Start a run, note the timers, open inventory, wait, then close it. |
Run/dungeon timers do not advance while paused and resume without counting the pause. |
| Exit-dialog pause |
Open the exit/save dialog during gameplay; wait and cancel. |
Gameplay and timers pause while the dialog is open and resume on cancellation. |
| Overlapping pause flows |
Open inventory and the exit dialog in supported sequences; close/cancel one while the other remains open. |
Gameplay/timers do not resume until all active pause UI is dismissed. Record any early resume as a regression. |
| Timer restore |
Spend time in a dungeon, save/exit, reload and re-enter the dungeon. |
Total and dungeon elapsed time continue from saved values rather than resetting. |
| Dungeon Four timer |
Enter Dungeon Four and compare its timer label and elapsed time with other dungeons. |
Dungeon Four is represented correctly and its elapsed time updates. |
| Gold achievement |
Start with existing gold, note the configured achievement target, and collect further gold. |
Progress follows the post-baseline increase and unlocks at the target. |
| Achievement persistence |
Make partial progress and unlock an achievement; save, restart and load. |
Progress and unlocked state are restored without duplicate unlock notifications. |
| Screen background |
Transition between gameplay, menus and the death screen. |
Removing the previous background-colour override does not leave an unintended colour or stale frame. |
| Natural final-boss ending |
Complete the final boss through normal gameplay. |
The ending reaches the win screen once and the run timer stops. |
| Debug final-boss ending |
Use room goto finalBossRoom, then room clear; repeat clear during the ending if possible. |
The peaceful ending shortcut completes without duplicate transitions, lingering attacks or a crash. |
| Completed-run save handling |
Finish a run, return to the menu and inspect available load behaviour. |
Victory does not write the just-completed run as a new resumable save. Check any older save separately; this plan does not assume victory deletes it. |
Dungeon Layouts and Tiles
| Test |
Steps |
Expected Result |
| Selection layout |
Start a new game and inspect the selection room. |
Bookshelves, floor and player spawn match the revised layout without overlap or clipping. |
| Dungeon themes |
Visit Dungeons One through Four through normal progression or their configured debug IDs. |
Each room uses the theme configured for it; tiles load without missing textures or visible slicing errors. |
| Layout and void boundaries |
Walk the accessible floors and inspect boundaries beside void tiles. |
Directional wall faces/corners align with the floor layout and prevent leaving walkable space. |
| Tile variation |
Reload rooms several times and inspect floor/bookshelf variants. |
Random visual variants remain correctly aligned and do not change collision or block intended paths. |
| Obstacles |
Inspect and collide with rocks, barrels and sword obstacles. |
Sprites are complete, correctly placed and have appropriate blocking behaviour. |
| Paired-door placement |
Clear rooms and travel through doors in both directions. |
The player arrives inside the destination room, clear of the wall/bookshelf, and cleared rooms remain cleared. |
| Dungeon Three/Four layouts |
Visit every configured room, including each boss room. |
Enemies, exits and paths remain reachable; layouts support normal progression. |
| Themed chase enemies |
Visit rooms configured with each chase-enemy skin. |
The expected skin appears with movement, chase and death animations. |
| Cerberus wall chain |
Enter its revised boss arena and observe the chain while Cerberus moves/attacks. |
The chain attachment aligns with the intended wall in the updated layout. |
| Final-boss arena |
Enter finalBossRoom and move around its accessible perimeter. |
Boss placement, arena bounds, walls and player spawn align with the layout. |
| Stage Two fireball walls |
Reach Stage Two and observe fireballs striking side/top walls and tile seams. |
Fireballs stop at walls rather than passing through seams; near-corner shots are not visibly blocked too early. |
| Stage Two ice hint |
Reach Stage Two, collect ice magic and hold J; then leave the stage. |
A readable hint explains pickup and use, the action works, and the hint does not remain over later stages. |
Minimap
| Test |
Steps |
Expected Result |
| Initial display |
Start a new game and inspect the top-right HUD. |
One minimap appears with the player-head icon in its centre. |
| Exit placement |
Visit rooms with left and right exits and compare with rooms.json. |
Destination icons appear on the corresponding side, with one icon per represented exit. |
| Room transition |
Travel repeatedly between rooms with different exits. |
The map updates to the current room and old icons do not accumulate. |
| Cleared-room styling |
Clear a room, leave it and inspect its icon from an adjacent room. |
The destination is shown as cleared (grey) rather than default white. |
| Home styling |
Inspect an exit returning to the selection room. |
The selection/home destination uses brown styling. |
| Missing/unsupported side |
In a disposable test configuration, supply a null side and then an unsupported side. |
Null falls back to the right; unsupported values are skipped and logged, matching the implementation. |
| Rendering lifecycle |
Switch rooms repeatedly, exit gameplay and start another run. |
No duplicate minimaps, disposed-renderer errors or broken shape drawing appear. |
| Window resizing |
Resize the game window while the minimap is visible. |
Placement remains readable and does not obscure essential HUD elements. |
Room Debug Commands
| Test |
Steps |
Expected Result |
| Valid room jump |
Enter room goto dungeonOneEntrance, then room goto dungeonTwoEntrance. |
Each command schedules a safe transition and loads the requested room. |
| Return to selection |
Enter room goto selection. |
The selection room loads without requiring a nearby exit. |
| Invalid room |
Enter room goto doesNotExist. |
The command returns failure and leaves the current room unchanged. |
| Missing arguments |
Enter room, then room goto, then room unknown. |
Invalid commands fail without exceptions or unintended transitions. |
| First-exit arrival |
Jump to a room with configured exits. |
Arrival is based on its first exit, with normal room-arrival handling applied. |
| Entry-point fallback |
Use a disposable test room with no exits and at least one entry point. |
Arrival uses the first entry point. |
| Last-resort fallback |
Use a disposable test room with neither exits nor entry points. |
The fallback position is (5, 5) in room-position configuration units. Verify it is walkable; the implementation does not guarantee this. |
| Debug clear regression |
Enter an ordinary combat room and run room clear. |
Living enemies clear and ordinary exits unlock; split children do not leave the room incorrectly marked clear. |
| Repeated jumps |
Jump repeatedly between occupied rooms, including while projectiles exist. |
Old rooms clean up without physics crashes; camera and minimap follow the new room. |
“Bounds checking” in the branch history should not be treated as proof of walkable spawn validation: the code checks arguments/room existence and provides arrival fallbacks, but the fixed fallback can still be inside a wall.
Wall-Clipping Fix
| Test |
Steps |
Expected Result |
| Straight wall seams |
Hold movement along long horizontal and vertical tiled walls. |
The player slides along the boundary without catching on internal seams. |
| Diagonal corners |
Move diagonally into and around wall corners from every side. |
Bevelled corners reduce snagging without letting the player pass through walls. |
| Short/tall walls |
Walk beside bottom wall faces, tall top faces and diagonal corner pieces. |
Collision remains aligned with the visible geometry and does not leave traversable gaps. |
| Enemy movement |
Let enemies pursue the player along walls and around obstacles. |
They remain inside the room and do not repeatedly snag at tile joins. |
| Other obstacles |
Walk into rocks, barrels and invisible boundary walls. |
Existing blocking behaviour is preserved. |
Repeated Contact Damage and Balancing
| Test |
Steps |
Expected Result |
| Crab sustained contact |
In an unscaled room, remain in contact with a Crab for several seconds. |
An immediate hit is followed by roughly one hit per second while contact persists. Unmodified parent attack is 2. |
| Medusa sustained contact |
Repeat with Medusa. |
The same repeated-contact behaviour applies. |
| Separation/re-entry |
Leave contact before the next tick, wait, then touch again. |
No damage occurs while separated; re-entry causes an immediate hit. The interval is not a global invulnerability window. |
| Frozen player |
Trigger a freeze trap while either enemy remains touching the player. |
Contact damage continues during player freeze. |
| Frozen enemy |
Freeze the touching enemy and wait for thawing. |
It cannot attack while frozen; damage resumes after thawing without requiring new contact. |
| Invisibility |
Become invisible while touching an enemy and remain nearby until visible again. |
Contact damage is blocked while concealed and resumes afterward. |
| Multiple enemies |
Maintain contact with two enemies where practical. |
Each enemy retains its own repeat timing; simultaneous attackers are not globally merged into one hit. |
| Death/disposal |
Kill a touching enemy or leave its room. |
That enemy cannot continue dealing contact damage afterward. |
| Parent/child balance |
Use an unmodified 10-damage attack on unscaled Crab and Medusa parents. |
Each parent starts at 40 health and splits after four hits into two children with 30 health and 1 attack each. Children do not split again. |
| Child contact damage |
Stay in contact with a split child. |
The child also repeats damage while touching, using its own attack value. |
| Scaled enemies |
Repeat in a room where enemy scaling is active. |
Parent/child values follow the implemented scaling; do not expect the unscaled 40/30 health values universally. |
| Player starting health |
Start a fresh run without loading an older save. |
Base starting health is 120 before other modifiers. |
| Weapon/projectile regression |
Attack with the existing weapons and observe ordinary projectiles. |
They retain their existing collision-entry damage behaviour, without inheriting enemy-style periodic contact damage. |
Areas Not Covered by Automated Tests
room goto parsing, invalid inputs, scheduled execution and all three arrival-selection paths have no dedicated tests in the debug-command branch.
RunTimerTest directly verifies timer pause/resume but not inventory/exit-dialog wiring, overlapping pause UI, restored-dungeon timing or the Dungeon Four display.
- Gold achievement tests verify baseline/delta logic, not save/load persistence, restored baselines or spending/re-earning behaviour. Add save-round-trip coverage before treating persistence as proven.
- The new win-screen transition and final-boss debug-ending shortcut have no dedicated regression tests added by
small_general_bugs.
- Tilesheet appearance, random texture selection, complete JSON terrain generation, Cerberus chain alignment and Stage Two hint readability require visual/manual checks.
- Directional-wall tests cover individual direction cases and an empty set, not every multi-direction combination or both visual themes.
- Collider shape tests do not simulate a player sliding along tiled walls under normal movement, knockback or dash velocities.
- Minimap tests mock drawing and do not verify exact colours/placement, null-side fallback, unsupported sides, repeated renderer disposal or full room-manager-to-HUD event delivery.
- Contact tests trigger collision events directly. They do not prove real Box2D event sequencing, physical knockback, pause/time-scale interactions or factory-created children's repeated damage end to end.
- Starting player health of 120 is a configuration change without a dedicated new assertion in the reviewed contact-fix tests.
- No pass/fail result, team review or manual gameplay execution is claimed by this document.
AI Declaration
This plan was generated with LLM assistance (Codex), using the supplied example, the six branch histories, test assertions and related game code. Team review and execution results should be recorded after they occur.