## Summary Fixes three bugs in `GuardedRegion.CallGuards`: - **Operator precedence bug**: The condition `!m.Region.IsPartOf(this) && !m_GuardCandidates.ContainsKey(m)` was inverted from intent. Replaced with explicit split: dictionary members are targeted regardless of region; permanent candidates (reds/AlwaysMurderer) must be inside the region. - **Premature `break`**: Only the first guard candidate was ever processed per "guards" call. Removed the `break` so all valid candidates in range get a guard spawned. - **Misleading message for permanent reds**: "Guards can no longer be called on you." (502276) was sent to permanent reds, but guards can *always* be called on them. Now only sent to temporary criminals whose guard window is actually consumed. Also extracts `IsAlwaysGuardCandidate()` helper and simplifies `IsGuardCandidate()`. ## Edge cases verified (by analysis) - **Multiple players call guards on same red**: `BaseGuard.Spawn` dedup (scans 15 tiles for existing guard with same `Focus`) prevents duplicate guards. Message suppression eliminates spam. - **Red fights spawned guard → criminal → guards called again**: Same dedup prevents infinite guard spawns. Existing guard already has `Focus == red`. ## Test plan - [ ] Temporary criminal in guarded region → guard spawns, receives "Guards can no longer be called on you." - [ ] Permanent red (5+ kills) in guarded region → guard spawns, does NOT receive the message - [ ] Multiple players call "guards" on same red → only 1 guard spawns - [ ] Criminal outside region but in dictionary → still targeted by guards call from inside region - [ ] Red outside guarded region → NOT targeted by guards call (must be inside region) |
||
|---|---|---|
| .. | ||
| Application | ||
| Logger | ||
| Server | ||
| Server.Tests | ||
| UOContent | ||
| UOContent.Tests | ||