Skip to content

Fix stall placement on enemies - #163

Merged
candour merged 2 commits into
mainfrom
fix-stall-placement-on-enemies-7100298176518883205
May 17, 2026
Merged

Fix stall placement on enemies#163
candour merged 2 commits into
mainfrom
fix-stall-placement-on-enemies-7100298176518883205

Conversation

@candour

@candour candour commented May 17, 2026

Copy link
Copy Markdown
Owner

This change fixes a bug in Hawker Rush where stalls could be placed on top of moving customers, leading to visual clipping and potential gameplay issues. I've implemented a check in the placement logic to ensure that a tile is not occupied by an enemy or about to be occupied by one before allowing a stall to be built there. I've also included unit tests to verify this behavior and updated the project's fix log.


PR created automatically by Jules for task 7100298176518883205 started by @candour

Summary by CodeRabbit

  • Bug Fixes

    • Prevented placing stalls on tiles currently occupied by enemies
    • Prevented placing stalls on tiles that are an enemy's immediate next movement target
    • Improved placement validation to avoid visual/physics conflicts when enemies are nearby
  • Tests

    • Added tests covering enemy-aware stall placement scenarios to ensure the above fixes

Review Change Stack

- Added proximity check in `MainViewModel.onCellClick` to prevent building stalls on tiles occupied by enemies or tiles that are their next immediate target.
- Ensured `lastSoldStall` is only cleared if placement is valid.
- Added `StallPlacementEnemyTest.kt` to verify the fix.
- Updated `fixes.md` with FIX-012.

Co-authored-by: candour <4670475+candour@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai

coderabbitai Bot commented May 17, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d32c9b84-669b-4a9b-8919-e918fdf59a1d

📥 Commits

Reviewing files that changed from the base of the PR and between 73dbda3 and 8dd9307.

📒 Files selected for processing (1)
  • app/src/main/java/com/messark/hawker/MainViewModel.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/main/java/com/messark/hawker/MainViewModel.kt

📝 Walkthrough

Walkthrough

This PR adds enemy proximity validation to stall placement logic in MainViewModel. When a player clicks a hex tile to place a stall, the code now checks whether any active enemy occupies that coordinate or targets it as their immediate next path step. If either condition is true, placement is blocked. Tests verify both blocking scenarios and the bugfix is documented.

Changes

Enemy Placement Validation

Layer / File(s) Summary
Enemy proximity guard implementation
app/src/main/java/com/messark/hawker/MainViewModel.kt
onCellClick stall placement adds an early-return guard that blocks placement if any enemy's current rounded position or next path coordinate equals the target. The lastSoldStall reset moves inside the placement-success block to only reset after passing the proximity check.
Placement blocking tests and bugfix documentation
app/src/test/java/com/messark/hawker/StallPlacementEnemyTest.kt, fixes.md
New test class StallPlacementEnemyTest configures a StandardTestDispatcher and verifies two negative scenarios: stall placement is rejected when an enemy occupies the target tile, and when the tile is the enemy's next path target. Bugfix FIX-012 documents the validation change.

🎯 2 (Simple) | ⏱️ ~12 minutes

  • Possibly related PRs:
    • candour/towerpower#154: Modifies MainViewModel state around stall sell/undo and relates to handling of undo-related variables adjusted elsewhere in MainViewModel.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix stall placement on enemies' directly and concisely summarizes the main change: preventing stalls from being placed on or in front of enemies.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-stall-placement-on-enemies-7100298176518883205

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown

Build Successful! 🚀

Download APK

Note: This link will be removed when the PR is closed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
app/src/main/java/com/messark/hawker/MainViewModel.kt (1)

1073-1076: ⚡ Quick win

Consider excluding grabbed enemies from proximity check.

Grabbed enemies (held by Tray Return Uncle stalls) have isGrabbed = true and aren't actively moving toward their next path target. Including them in the proximity check could block placement on tiles they'll never reach while grabbed. Consider adding && !enemy.isGrabbed to the check.

🎯 Suggested refinement
             // Prevent building on or immediately in front of enemies
-            val isEnemyNear = currentState.enemies.any { enemy ->
+            val isEnemyNear = currentState.enemies.any { enemy ->
+                if (enemy.isGrabbed) return@any false
                 val currentTarget = enemy.path.getOrNull(enemy.currentPathIndex + 1)
                 GridUtils.hexRound(enemy.position.q, enemy.position.r) == coord || currentTarget == coord
             }
app/src/test/java/com/messark/hawker/StallPlacementEnemyTest.kt (1)

56-62: 💤 Low value

Consider setting currentPathIndex = 2 for consistency.

The enemy's position is (2f, 0f) which corresponds to index 2 in the path, but currentPathIndex defaults to 0. While this doesn't affect the test's correctness (it still validates that placement is blocked when an enemy occupies a tile), setting currentPathIndex = 2 would make the test data more realistic and consistent with how enemy state works during actual gameplay.

✨ Suggested improvement
         val enemy = Enemy(
             id = "e1",
             health = 100f,
             maxHealth = 100f,
             position = PreciseAxialCoordinate(2f, 0f),
-            path = listOf(start, AxialCoordinate(1, 0), coord, AxialCoordinate(3, 0), end)
+            path = listOf(start, AxialCoordinate(1, 0), coord, AxialCoordinate(3, 0), end),
+            currentPathIndex = 2
         )

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a22b5ec9-2e94-4b5d-a3fb-b2462ee47588

📥 Commits

Reviewing files that changed from the base of the PR and between 9657dc4 and 73dbda3.

📒 Files selected for processing (3)
  • app/src/main/java/com/messark/hawker/MainViewModel.kt
  • app/src/test/java/com/messark/hawker/StallPlacementEnemyTest.kt
  • fixes.md

Comment thread app/src/main/java/com/messark/hawker/MainViewModel.kt Outdated
@candour
candour enabled auto-merge (squash) May 17, 2026 07:12
@candour

candour commented May 17, 2026

Copy link
Copy Markdown
Owner Author

Move lastSoldStall = null after successful placement validation.

Line 1079 clears lastSoldStall after the enemy proximity check but before pathfinding validation (line 1109) and the Tray Return Uncle rule check (lines 1092-1107). If either of those validations fails, placement won't occur but the player will lose their undo ability. Move this line inside the successful placement block (around line 1124-1127) or include it in the state.copy() call to ensure it's only cleared when placement actually succeeds.

@google-labs-jules

Copy link
Copy Markdown
Contributor

Move lastSoldStall = null after successful placement validation.

Line 1079 clears lastSoldStall after the enemy proximity check but before pathfinding validation (line 1109) and the Tray Return Uncle rule check (lines 1092-1107). If either of those validations fails, placement won't occur but the player will lose their undo ability. Move this line inside the successful placement block (around line 1124-1127) or include it in the state.copy() call to ensure it's only cleared when placement actually succeeds.

Acknowledged. I've moved the lastSoldStall = null update into the successful placement block to ensure the undo ability is only cleared when a stall is actually placed.

- Added proximity check in `MainViewModel.onCellClick` to prevent building stalls on tiles occupied by enemies or tiles that are their next immediate target.
- Ensured `lastSoldStall` is only cleared if placement is valid (addressed PR feedback).
- Added `StallPlacementEnemyTest.kt` to verify the fix.
- Updated `fixes.md` with FIX-012.

Co-authored-by: candour <4670475+candour@users.noreply.github.com>
@candour
candour merged commit 4bb5e4a into main May 17, 2026
2 of 3 checks passed
@candour
candour deleted the fix-stall-placement-on-enemies-7100298176518883205 branch May 17, 2026 07:17
@github-actions

Copy link
Copy Markdown

Build Successful! 🚀

Download APK

Note: This link will be removed when the PR is closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant