refactor(spells): TargetedSpell base owns target+range+LOS validation once #152

Merged
marco merged 1 commit from refactor/targeted-spell-base into main 2026-07-22 17:27:52 +02:00
Owner

Summary

Every targeted spell had to re-implement the same preamble — target exists? alive? not the caster? in range? in line of sight? — before its effect. With more targeted spells coming, that's duplicated logic per spell (and the line-of-sight check, which is what makes arena cover real, would be copied N times).

  • New TargetedSpell base owns the validation once: target valid → in range → (by default) has line of sight, else Fizzled with the right SystemMessageId. Subclasses supply only Range(options) and Apply(target, context) (the effect).
  • BoltSpell now derives from it — its Resolve shrank to Range => BoltRange + Apply = deal damage. FireBolt/WaterBolt unchanged.
  • The LoS re-check stays at resolution (the cast is server-paced, #75) so ducking behind cover mid-incantation still dodges — but now it lives in one place for the whole family.

This is the server-enforced attack line-of-sight the PvP arena relies on: a blocking static (wall/pillar/tree) between caster and target fizzles the cast. (We deliberately did not hide out-of-LoS entities from the client — see the closed #150; cover is enforced on the attack, UO-style visibility is kept.)

How it was tested

  • New test IncantationTests.Bolt_TargetBehindBlockingStatic_FizzlesNoLineOfSight: caster and target 2 tiles apart (in range) with a blocking static between them → the bolt resolves Fizzled / NoLineOfSight. Locks the arena's essential cover behaviour through a concrete spell + the shared base.
  • Existing incantation/heal/shield/target-validator tests stay green (no behaviour change to a clear-LoS cast).
  • just lint (zero warnings) + just test (422 tests) green; whole solution builds.

Checklist

  • just lint passes (zero warnings)
  • just test is green
  • The whole solution builds
  • Multi-platform preserved (server-only logic change)
  • Tests added/updated for this change
  • No wire/protocol change
## Summary Every targeted spell had to re-implement the same preamble — *target exists? alive? not the caster? in range? in line of sight?* — before its effect. With more targeted spells coming, that's duplicated logic per spell (and the line-of-sight check, which is what makes arena cover real, would be copied N times). - New **`TargetedSpell` base** owns the validation **once**: target valid → in range → (by default) has line of sight, else `Fizzled` with the right `SystemMessageId`. Subclasses supply only `Range(options)` and `Apply(target, context)` (the effect). - **`BoltSpell` now derives from it** — its `Resolve` shrank to `Range => BoltRange` + `Apply` = deal damage. `FireBolt`/`WaterBolt` unchanged. - The LoS re-check stays at **resolution** (the cast is server-paced, #75) so ducking behind cover mid-incantation still dodges — but now it lives in one place for the whole family. This is the server-enforced attack line-of-sight the PvP arena relies on: a blocking static (wall/pillar/tree) between caster and target fizzles the cast. (We deliberately did **not** hide out-of-LoS entities from the client — see the closed #150; cover is enforced on the *attack*, UO-style visibility is kept.) ## How it was tested - **New test** `IncantationTests.Bolt_TargetBehindBlockingStatic_FizzlesNoLineOfSight`: caster and target 2 tiles apart (in range) with a blocking static between them → the bolt resolves `Fizzled` / `NoLineOfSight`. Locks the arena's essential cover behaviour through a concrete spell + the shared base. - Existing incantation/heal/shield/target-validator tests stay green (no behaviour change to a clear-LoS cast). - `just lint` (zero warnings) + `just test` (**422 tests**) green; whole solution builds. ## Checklist - [x] `just lint` passes (zero warnings) - [x] `just test` is green - [x] The whole solution builds - [x] Multi-platform preserved (server-only logic change) - [x] Tests added/updated for this change - [x] No wire/protocol change
refactor(spells): TargetedSpell base owns target+range+LOS validation once
All checks were successful
ci / Lint & Test (pull_request) Successful in 1m43s
699f45e126
marco merged commit b894a1e4a3 into main 2026-07-22 17:27:52 +02:00
marco deleted branch refactor/targeted-spell-base 2026-07-22 17:27:52 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
marco/IsoMmo!152
No description provided.