Skip to content

feat(engine): grid-461 PR-2 — AoE templates on the combat grid (#1251)#1257

Merged
100yenadmin merged 2 commits into
mainfrom
feat/1251-grid-aoe
Jul 2, 2026
Merged

feat(engine): grid-461 PR-2 — AoE templates on the combat grid (#1251)#1257
100yenadmin merged 2 commits into
mainfrom
feat/1251-grid-aoe

Conversation

@100yenadmin

Copy link
Copy Markdown
Member

What

grid-461 PR-2 — geometric area-of-effect templates (sphere / cone / line) on the (x,y) combat grid, mapped to affected cells + multi-target resolution for area spells. Closes #1251; part of the combat epic #1100.

Given a grid cast with an origin=[x,y] aim cell, the engine projects the spell's SRD 5.2 shape onto the grid, returns affected_tile_coords, and auto-resolves save-for-half over the occupants standing in those cells.

Approach — template geometry

Pure, I/O-free helpers in combat_grid.py (mirroring the PR-1 movement-spine style), all using the module's one Chebyshev distance metric and edge-clipped to the grid extents:

  • sphere_cells(center, radius_ft, …) — cells within radius_ft/cell_size king-moves of the burst point. A Fireball bursts at origin (origin-independent).
  • cone_cells(origin, toward, length_ft, …) — SRD cone (width == distance from the point) snapped to one of the 8 grid facings from the caster toward origin; 1:1 widening quadrant fan; the emitter cell is excluded.
  • line_cells(origin, toward, length_ft, width_ft, …) — a line length_ft long × width_ft wide, thickened symmetrically about the centre line, along the 8-facing toward origin.

server._aoe_template_cells maps the SRD record's shape_type / shape_size (feet) onto those helpers. The occupants of the covered cells feed the existing target_ids shared-roll save-for-half loop — no new state writer, no new damage path.

Invariants

Tests

New tests/test_grid_aoe.py (18 tests): sphere/cone/line cell-set geometry at several origins + facings (orthogonal & diagonal), edge clipping at grid bounds; end-to-end Fireball-class cast hitting exactly the template occupants; honest save-for-half accounting; and byte-identical regression proofs (no-origin cast + explicit-target_ids cast unchanged).

tests/test_grid_aoe.py ............ 18 passed
qa/fast_gate.sh ................... 241 passed (T0 PASS)
full engine suite ................. 3277 passed

(run with -p no:xdist, single-process.)

Part of #1100.

Adds sphere/cone/line area-of-effect templates on the (x,y) combat grid and
wires them into cast_spell. When a grid cast passes origin=[x,y], the engine
projects the spell's SRD shape onto the cells, returns affected_tile_coords,
and auto-resolves save-for-half over the occupants caught (reusing the existing
target_ids multi-target loop).

- combat_grid: pure sphere_cells / cone_cells / line_cells (Chebyshev metric,
  edge-clipped to grid bounds); 8-facing cone/line snapping.
- server: _aoe_template_cells maps SRD shape_type/shape_size -> geometry;
  cast_spell gains one ListArg param (origin). Additive/default-off: no origin
  (or off-grid, or an explicit target_ids) == byte-identical to today.
- Line-of-effect (walls between origin and a cell) stubbed permissive, TODO(#1252).

Schema cost: +242 B on the engine tool-schema slab (headroom 1565 -> 1323 B,
under the 120 KB budget).

Part of #1100.
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 37 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ad42e734-72fd-4f14-8be6-411a73c167ff

📥 Commits

Reviewing files that changed from the base of the PR and between cb3c6bc and 49ebecb.

📒 Files selected for processing (3)
  • servers/engine/combat_grid.py
  • servers/engine/server.py
  • servers/engine/tests/test_grid_aoe.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/1251-grid-aoe

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

Review rework on PR #1257: remove the caster-cell carve-out from the AoE
occupant loop. Per SRD 5.2 a creature within a spell's area is affected and the
caster is not exempt (Fireball centered on yourself). The prior carve-out was
also internally inconsistent — a companion on the caster's cell was hit while
the caster was not. The caster now rides the same save-for-half loop; the DM
narrates. Cone/line geometry already excludes the emitter cell, so a cone/line
still never catches its own caster.

Tests: sphere centered on the caster -> caster appears in the resolved targets
and takes a save; cone/line assert the caster stays excluded (no regression).
@evaos-code-review-bot

evaos-code-review-bot Bot commented Jul 2, 2026

Copy link
Copy Markdown

evaOS review status: completed

PR: #1257 - feat(engine): grid-461 PR-2 — AoE templates on the combat grid (#1251)
Head: 49ebecb6dfe03a1cf2b0f688f9cac5c7cf12339f
Updated: 2026-07-02T10:19:36.172Z

evaOS review completed for this PR head.

Automation note: agents should wait for this comment to reach completed, stale_head, closed_or_merged_before_review, skipped, or failed before treating evaOS review as settled for this head. provider_deferred means evaOS still intends to retry.

PR URL: #1257

Review URL: #1257 (review)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d574333d37

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread servers/engine/server.py Outdated
Comment on lines +7566 to +7568
for cb in c.combat.order:
if cb.character_id == character_id:
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Include the caster when a burst covers them

When the caster stands inside their own sphere template, such as a Fireball centered on their cell or any burst whose affected_tile_coords includes the caster, this unconditional skip keeps them out of aoe_targets. cast_spell then spends the slot and auto-damages every other occupant while making self-centered/close bursts risk-free; the caster should only be excluded for emitter-only shapes like cones/lines, not for sphere templates that actually cover their cell.

Useful? React with 👍 / 👎.

Comment thread servers/engine/server.py
Comment on lines +6427 to +6428
if shape == "cone":
return combat_grid.cone_cells(src, aim, size, w, h, cs)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't project granted cones from the caster

When origin is supplied for a touch spell whose cone is granted to another creature, such as Dragon's Breath, the SRD record still has shape_type == 'cone', so this projects the cone from the caster and the existing AoE loop immediately applies the save-for-damage result. A grid cast of that spell on an ally can therefore damage creatures in front of the caster on the casting turn instead of setting up the touched creature's later breath action.

Useful? React with 👍 / 👎.

Comment thread servers/engine/server.py
Comment on lines +6420 to +6422
if shape == "sphere":
# A burst centred on the aim cell — origin-independent (no facing needed).
return combat_grid.sphere_cells(aim, size, w, h, cs)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't detonate delayed areas on cast

When origin is passed for a delayed sphere such as Delayed Blast Fireball, this branch projects it like an immediate Fireball, and the new origin handling feeds every occupant into the existing save-for-damage loop during the cast. That consumes the slot/concentration and deals the 12d6 immediately, even though this spell should create a bead that explodes only when the spell ends or is touched.

Useful? React with 👍 / 👎.

@evaos-code-review-bot evaos-code-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Walkthrough

PR: #1257 - feat(engine): grid-461 PR-2 — AoE templates on the combat grid (#1251)
Head: 49ebecb6dfe03a1cf2b0f688f9cac5c7cf12339f into main. Review event: COMMENT.

Estimated review effort: 1/5 (~10 min)

Changed Files

File Status Churn Purpose Risk

Review Signal

No validated inline findings.
Dropped findings before posting: 2. High-severity findings: 0.

Risk Taxonomy

No finding categories.

Validation and Proof

1 required validation/proof recommendation(s) selected from changed files.

  • required: Unity editor or Play Mode smoke - WorldOS repo profile implies Unity runtime risk. Proof: Unity editor smoke; Play Mode log; scene/prefab screenshot or recording.
    Proof status: missing - 1 required validation/proof recommendation(s) missing from PR metadata.
    Profile validation hints: Prefer correctness, persistence, CI, release, and regression findings over style-only feedback.
    Profile proof expectations: Look for Unity editor, play-mode, fixture, or focused smoke evidence when runtime behavior changes.

Related Context

Related issues/PRs: #1251, #1100, #1252, #1253, #1254.
Suggested labels: none.
Suggested reviewers: none from current metadata.

Pre-merge checklist

  • Inline comments target current RIGHT-side diff lines.
  • No secret-like content survived into posted inline comments.
  • REQUEST_CHANGES is only used when eligible P0/P1 findings survive validation.
  • Required behavior proof is present or not applicable.
  • Labels and reviewers are suggestions only; the bot did not auto-apply them.

@100yenadmin 100yenadmin merged commit 109ab7d into main Jul 2, 2026
32 checks passed
@100yenadmin 100yenadmin deleted the feat/1251-grid-aoe branch July 2, 2026 10:27
100yenadmin added a commit that referenced this pull request Jul 2, 2026
* feat(engine): grid-461 PR-3 — cover + line-of-sight (#1252)

Adds terrain-aware line-of-sight and SRD 5.2 cover on the combat grid,
building on the #1257 AoE templates.

combat_grid.py (pure):
- _supercover_cells / line_blockers: cell->cell supercover ray over the
  grid's blocking (impassable) cells. Corner-graze tie-break is permissive
  — a diagonal graze severs the ray only when BOTH shoulder cells of the
  step are blockers (a lone diagonal blocker is slipped past). Symmetric.
- has_line_of_effect: True iff the ray crosses no blocker (endpoints excluded).
- cover_between / cover_ac_bonus: 0 blockers=none, 1=half(+2), 2+=three-
  quarters(+5), a fully-walled ray=total (untargetable).

server.py (wiring, additive/default-off):
- cast_spell: cull AoE cells with no line of effect from the template origin
  (the deferred #1257 TODO) — a wall shields cells behind it.
- attack: when grid_enabled AND both combatants placed, fold cover AC into
  the target AC (half/three-quarters), refuse a total-cover shot up front,
  and surface a  result key. Off-grid / unplaced == byte-identical.

No new tool params (cover derives from existing state; surfaced in the
result payload) — tool-schema byte delta 0.

Part of #1100.

* fix(engine): trace AoE line-of-effect from the spell's point of origin (#1252)

Rework per review: the LoE cull traced every shape from the aim cell, which
is SRD-correct for a sphere (the burst's origin IS the aim) but wrong for a
cone/line, whose point of origin is the CASTER. A Burning Hands aimed past a
wall would leak onto cells beyond the wall — unreachable from the caster but
passing an aim-origin ray.

_aoe_template_cells now returns (cells, loe_origin): aim for sphere, the
caster's cell (src) for cone/line. cast_spell culls with that origin, keeping
the 'origin cell always retained' semantics relative to loe_origin.

Tests: cone aimed across a wall (cells behind the wall culled even though an
aim-origin ray would keep them) + line stops at a blocker; sphere behaviour
and all existing AoE tests unchanged.

---------

Co-authored-by: Eva <arncalso@gmail.com>
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.

[combat] grid-461 PR-2 — AoE templates (spheres/cones/lines) on the grid

1 participant