Skip to content

fix(char): range checks use sprite frame hitbox (CON-30)#5

Merged
ropoko merged 19 commits into
mainfrom
cursor/fix-char-range-f8db
May 28, 2026
Merged

fix(char): range checks use sprite frame hitbox (CON-30)#5
ropoko merged 19 commits into
mainfrom
cursor/fix-char-range-f8db

Conversation

@ropoko
Copy link
Copy Markdown
Collaborator

@ropoko ropoko commented May 21, 2026

Summary

Resolves CON-30 (char cards attacking out of range).

Merged with feat/matchmaking.

Root cause

  1. Hitbox size: Range checks used img_preview dimensions instead of in-world sprite frame size, inflating the target rectangle.
  2. Nearest target: get_nearest_enemy could clear the closest enemy depending on iteration order.
  3. Debug vs logic: Range circles did not match collision anchor/radii.

Changes

  • Use scaled frame_width / frame_height (with RENDER_SCALE from matchmaking) for hitbox bounds.
  • Center perception/attack checks on char_range_center so they match on-map rendering.
  • Fix get_nearest_enemy to always keep the closest enemy.
  • Preserve matchmaking updates: scaled animations, death timing, walk preview quad, predicted movement.

Verification

  • luacheck src/entities/cards/char.lua
  • Merge conflict in char.lua resolved against feat/matchmaking

Linear Issue: CON-30

Open in Web Open in Cursor 

ropoko and others added 18 commits March 26, 2026 22:32
…ogic

Use frame_width/frame_height for circle-rect collisions instead of the full
preview image so melee range matches the on-map sprite.

Center attack and perception circles on the hitbox center and use radii that
match collision (half of configured range).

Fix get_nearest_enemy clearing the target when a farther enemy appeared later
in iteration order.

Co-authored-by: Rodrigo Stramantinoli <rodrigostramantinoli@gmail.com>
Resolve char.lua conflict by keeping matchmaking rendering (RENDER_SCALE,
char_range_center, scaled draw/update) and re-applying CON-30 range fixes
using scaled frame hitboxes instead of preview image dimensions.

Co-authored-by: Rodrigo Stramantinoli <rodrigostramantinoli@gmail.com>
@ropoko ropoko marked this pull request as ready for review May 28, 2026 01:04
Comment thread src/entities/cards/char.lua
@ropoko ropoko merged commit a82268d into main May 28, 2026
3 checks passed
@ropoko ropoko deleted the cursor/fix-char-range-f8db branch May 28, 2026 02:08
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0015c8d. Configure here.

else
self.enemies_around[k] = nil
end
end
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale enemies_around entries after direct card removal

Medium Severity

get_enemies_in_range only iterates keys present in the current enemies table, so any key previously stored in self.enemies_around that has since been directly removed from the cards table (e.g., via reject_intent which does self.cards[...][card_id] = nil) is never cleaned up. The stale reference persists indefinitely and can be selected by get_nearest_enemy, causing the character to target and attack a phantom enemy that no longer exists in the game.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 0015c8d. Configure here.

Comment thread src/states/game.lua
end
for _, tower in ipairs(self.cards[Constants.ENEMY_ID]) do
tower:draw(tower.current_life)
end
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Towers rendered twice per frame in draw loop

Low Severity

Towers are stored with numeric keys (via table.insert) in the same table as char cards (stored with string keys). The main pairs() draw loops iterate all entries including towers, and then draw_towers() draws towers again using ipairs(). The new code extends this double-draw to enemy towers by adding the Constants.ENEMY_ID loop to draw_towers.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 0015c8d. Configure here.

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.

2 participants