ModernUO/Projects/UOContent/Spells
Kamron Batman 8e5e4f72c8
fix(ninjitsu): gate Animal Form gump by skill and stop mana drain (#2452) (#2468)
## Issue

Fixes #2452. A player with 30 Ninjitsu reported that the Animal Form menu showed **every** form; selecting one above their skill (e.g. Dog, req 40) **consumed mana** and returned "you need at least 40 skill", and afterwards the **gump never reopened** — every recast silently re-attempted the unusable form and drained more mana.

## Root cause

Three linked bugs, all reproduced from the code:

1. **Gump not gated by skill.** `AnimalFormGump.BuildLayout` compared `Skill.Fixed` (which is `Value * 10`, so 30 skill → `300`) against the raw 0–100 `ReqSkill` (Dog = `40`). `300 >= 40` is always true, so all forms were shown. `Morph` itself correctly uses `.Value`.
2. **Mana charged on a no-skill cast.** `Morph` returns `MorphResult.NoSkill` for an under-skilled form, but both call sites (`OnCast`, `OnResponse`) only special-cased `MorphResult.Fail`; `NoSkill` fell through to the branch that deducts mana.
3. **Menu never reopened.** Per OSI ([uo.com](https://uo.com/wiki/ultima-online-wiki/skills/ninjitsu/), [uoguide](https://www.uoguide.com/Animal_Form)), casting while **standing still always opens the selection menu**, and casting while **moving** quick-transforms into the last selected form. ModernUO only opened the menu when `lastAnimalForm == -1`, so once any form was selected a stationary recast skipped the menu.

## Fix

- Add `AnimalForm.CanSelectEntry` (compares `Skill.Value` to `ReqSkill`, plus the talisman check) and use it for the gump's per-entry enable check.
- `OnCast`: standing still always opens the menu; moving quick-transforms into the last form. `NoSkill` no longer costs mana.
- `OnResponse`: handle `Success` / `Fail` / `NoSkill` explicitly so `NoSkill` costs no mana.

## Tests

Adds `AnimalFormTests`:
- `CanSelectEntry` rejects forms above skill, accepts forms at/below skill, and requires a talisman for talisman-gated forms.
- `Morph` returns `NoSkill` (without transforming) when under-skilled, and `Success` when sufficiently skilled.

Verified the gating test catches the regression (reintroducing `.Fixed` fails it). Full solution build is clean; the 5 new tests plus 284 other UOContent tests pass (the pathfinding/AI sequential tests were excluded only because they deadlock under concurrent local runs — they are unrelated to this change).
2026-06-06 15:56:31 -07:00
..
Base feat: Adjusts fame and karma system with era gates for OSI accuracy (#2389) 2026-04-25 11:19:57 -07:00
Bushido chore: Use var everywhere (#2294) 2025-12-27 16:47:28 -08:00
Chivalry feat: Adds Mobile.Murderer virtual property, consolidates kill-threshold checks (#2355) 2026-03-06 08:36:41 -08:00
Eighth feat: Adjusts fame and karma system with era gates for OSI accuracy (#2389) 2026-04-25 11:19:57 -07:00
Fifth feat: T2A defensive spells (#2378) 2026-03-22 11:18:34 -07:00
First feat: T2A defensive spells (#2378) 2026-03-22 11:18:34 -07:00
Fourth feat: T2A defensive spells (#2378) 2026-03-22 11:18:34 -07:00
Gargoyle/SpellDefinitions fix: Fixes buffs don't start/stop properly. Streamlines constructor and Add/Remove buffs. (#2082) 2025-01-24 18:20:23 -08:00
Mysticism feat: Refactor Poison system, implement Darkglow & Parasitic effects (#2385) 2026-03-21 21:27:22 -07:00
Necromancy chore: Use var everywhere (#2294) 2025-12-27 16:47:28 -08:00
Ninjitsu fix(ninjitsu): gate Animal Form gump by skill and stop mana drain (#2452) (#2468) 2026-06-06 15:56:31 -07:00
Second feat: T2A defensive spells (#2378) 2026-03-22 11:18:34 -07:00
Seventh feat: Adds Mobile.Murderer virtual property, consolidates kill-threshold checks (#2355) 2026-03-06 08:36:41 -08:00
Sixth fix: Fixes various spell animations (#2346) 2026-03-06 00:30:40 -08:00
Spellweaving feat: Adds new decay system and SkipSerialization (#2311) 2026-01-08 11:43:51 -08:00
Targeting fix: Adjusts spell ranges to match OSI (#2171) 2025-05-01 20:03:56 -07:00
Third fix: Fixes various spell animations (#2346) 2026-03-06 00:30:40 -08:00
Initializer.cs fix: Adds Cleansing Winds Spell (#1126) 2022-07-17 07:49:55 -07:00
Reagent.cs Formats UO Content (#201) 2020-08-27 18:30:38 -07:00
UnsummonTimer.cs chore: Use var everywhere (#2294) 2025-12-27 16:47:28 -08:00