## Summary
Overhauls the fame and karma system to be more era-accurate, based on original design documents and publish notes.
### Karma on player kill → karma on murder report
- Removes karma gain/loss on player kill (was immediate on death)
- Karma is now set to `Kills * -1000` on murder **report** instead
- Fame on player kill now uses the same formula as monster kills (`Fame / 100`)
This karma loss on murder report behaviour was tested on both the demo and live servers, behaviour was matching in terms of karma loss on report. Official UO servers karma loss AMOUNT match with my memory of T2A/UOR with one caveat - it's doubled on live servers (-2000 * kill count). I'm not sure when this changed and this behaviour has always had very poor and incorrect documentation, even 10-20 years ago. I was obsessed with the dread lord title on OSI and the only way I knew how to get it was reach 10 kills then macro them off. Even in publish 16 (when "The Murderer" title was removed) it still required 10 kills. Maybe it changed to -2000*Kills in AOS - that's where I've put the era gating diff.
### Era gates
- **Karma lock** (ankh toggle + auto-lock on negative karma) gated to `Core.UOTD && !Core.AOS` — [didn't exist before Jan 28, 2001](https://web.archive.org/web/20010128092700/http://update.uo.com/design_300.html)
- **Felucca fame/karma +30% bonus** gated to `Core.LBR` — [added in Publish 16, July 2002](https://uo.com/wiki/ultima-online-wiki/technical/previous-publishes/2002-2/publish-16-part-2-5-23rd-july/)
- **Fame/karma splitting** among damage dealers gated to `Core.UOR` — pre-UOR awards go to last hit only
### Skill karma penalties
- **Provocation** on innocent NPC: NPC says cliloc 501591, karma loss (floor -7500)
- **Stealing** attempt: karma loss on every attempt (floor -5000). Stealing did not cause karma loss at all before!
- **Summon Daemon**: karma loss on successful cast (floor -7000)
- **Corpse carving** (human): -70 for innocent corpses (floor -7000), -20 for freely-aggressable (floor -2000)
- **Bounty head turn-in**: karma gain capped at 2000 (was awarding flat +2000)
### Beneficial action karma
- **Beneficial spells** (heal, cure, etc.): `AwardKarma(caster, target.Karma / 5)` — healing good targets raises karma, healing evil targets lowers it - source is UO98 demo scripts
- **Bandages**: same formula but gain only (skipped if target karma ≤ 0) - see stratics link ("only ever gain karma, not lose it")
Sources: UO98 Demo scripts and playing, [Fame and Karma wiki](https://uo.com/wiki/ultima-online-wiki/player/fame-and-karma/), [UO design doc (Jan 2001)](https://web.archive.org/web/20010128092700/http://update.uo.com/design_300.html), [Publish 16](https://uo.com/wiki/ultima-online-wiki/technical/previous-publishes/2002-2/publish-16-part-2-5-23rd-july/), [Stratics healing reference](https://web.archive.org/web/20001209014200fw_/http://uo.stratics.com/heal.shtml)
### Refactoring
- Extracted `Titles.ComputeKillAwards(killed, map)` shared by player kill and creature kill paths
- Extracted `Titles.SetKarma(m, value, message)` for direct karma assignment (used by murder report)
- Extracted `SendKarmaMessage` and `CheckKarmaLock` helpers from `AwardKarma`
> [!Important]
> **Developer Note**
> This code change will **completely move gumps out of the core**
### Summary
- Adds `GetGumps()` convenience which exposes methods to Find/Close/Send multiple gumps. This helper is a performance improvement by eliminating the Dictionary<Player, List> lookup for gumps.
### Summary
- Drastically streamlines the spell targeting by collapsing the target classes into a single `SpellTarget<T>` class.
- Moves TargetRange to the spell itself so it can be used by MageAI.
- Changes range check in MageAI to use TargetRange. This should fix target acquisition bugs
### Summary
- Cleans up target cancellation being called incorrectly.
- An invalid target type (which should never happen), now calls `OnTargetUntargetable` instead of `OnTargetCanceled`
- Removes double calls to `FinishSequence` in Spells.
### Summary
Eliminates `IPooledEnumerable<T>` and `eable.Free()` from `Map` for mobiles. This drastically simplifies code that iterates in range, for example:
```cs
foreach (var m in m.GetMobilesInRange(5))
{
}
```
The code above no longer requires an eable and calling `Free()`.
- [X] Fixed several locations where an NPC that was damaged would cause a server crash.
- [X] Removed an unnecessary allocation in guard fake calls (NPCs calling guards on you)
- [X] Fixes damage precision loss in Poison Strike Spell
- [X] BogThing no longer attempts to "search" for boglings to eat when it is at full health
* Fixes disarm
* Fixes strangle not refreshing
* Fixes curse not refreshing
* Fixes 125% bonus to looting rights
* Fixes mobs attacking each other, or not attacking each other
* Fixes items dropping to the floor
* Fixes protection spell
* Fixes cure sending wrong message
- [X] Fixes NPE from account tags.
- [X] Fixes bad skill check due to missing cast to double.
- [X] Fixes water elemental duration.
- [X] Standardizes spell summon duration by expansion.
- [X] Removes several `ToList()` uses with `PooledRefQueue`
- [X] Adds a `PeekRandom` to PooledRefQueue
- [X] Updates EV/BS so they dispel each other in a more efficient manner.
- [X] Fixes Firebomb so it works like a normal firefield.
- [X] Fixes field spells so they aren't unnecessarily using a Point3D ref more than necessary.
- [X] Removes extra allocation in campfire by using reverse loop.
- [X] Removes other LINQ calls that aren't needed.