feat: Refactor Poison system, implement Darkglow & Parasitic effects (#2385)
## Summary - Refactors the poison system to separate `Index` (globally unique ID) from `Level` (tier within a family), enabling multiple poison families (Standard, Darkglow, Parasitic) to coexist without collisions - Implements Darkglow and Parasitic poison special effects from Mondain's Legacy: Darkglow boosts damage by 10% when attacker is ranged, Parasitic heals the attacker for damage dealt in melee range - Fixes several bugs: `Register()` crashing on duplicate `Level` values across families, `IncreaseLevel()` crossing family boundaries, `InfectiousStrike` and `NinjaWeapons` stripping poison family via level-based lookups, and `ArchCure`/`CleansingWinds` using raw `Level + 1` instead of `IncreaseLevel()` ## Changes **`Projects/Server/Poison.cs`** — Adds `PoisonFamily` enum and abstract `Family` property. Adds `Index` as unique identifier. Fixes `Register()` to check `Index` uniqueness (not `Level`) and validate the new poison's name (not the existing one's). Fixes `IncreaseLevel()` to use `Index + 1`, naturally respecting family boundaries via Index gaps. Replaces linear name lookup with `Dictionary`-based `PoisonsByName`. **`Projects/UOContent/Misc/Poison.cs`** — Adds `family` parameter to `PoisonImpl`. Implements Darkglow effect (10% damage boost when `From` >1 tile, cliloc 1072850) and Parasitic effect (heals `From` for damage dealt within 1 tile, cliloc 1060203) in `PoisonTimer.OnTick()`. Renames `m_` fields to `_` convention. **`Projects/UOContent/Misc/PoisonKinds.cs`** — New file. Moves poison registration out of `PoisonImpl` into `PoisonKinds.Configure()`. Adds `PoisonFamily` to Darkglow/Parasitic registrations. Provides extension properties (`Lesser`, `Deadly`, `LesserDarkglow`, etc.), `GetPoison(int level)` (standard-only), `GetPoisonByFamilyAndLevel()`, and `IsDarkglow`/`IsParasitic` instance helpers. **`Projects/UOContent/Items/Weapons/Abilities/InfectiousStrike.cs`** — Family-aware poison scaling: Darkglow caps at Deadly (Poisoning/33.3), Parasitic caps at Lethal (Poisoning/25), Standard unchanged. Level bump uses `IncreaseLevel()` with family boundary check. **`Projects/UOContent/Items/Skill Items/Ninjitsu/NinjaWeapons.cs`** — EvilOmen level bump uses `Poison.IncreaseLevel()` instead of `Poison.GetPoison(Level + 1)`. **`Projects/UOContent/Spells/Fourth/ArchCure.cs`** and **`CleansingWindsSpell.cs`** — Replace `poison.Level + 1` with `Poison.IncreaseLevel(poison).Level` for family-safe cure chance calculation. **`Projects/Server/Serialization/SerializationExtensions.cs`** — Serializes/deserializes `Index` instead of `Level`. **`DarkglowPotion.cs`** / **`ParasiticPotion.cs`** — Point to actual Darkglow/Parasitic poisons instead of placeholder `Greater`. **`PotionKeg.cs`** / **`BasePotion.cs`** — Adds Darkglow, Parasitic, Invisibility, and FlintsPungentBrew to `PotionEffect` enum and keg label support. ## Test plan - [ ] `dotnet build` compiles cleanly (verified, 0 warnings 0 errors) - [ ] Verify `PoisonKinds.Configure()` registers all poisons without throwing (Register bug fix) - [ ] Standard poison behavior unchanged — PoisonField, PoisonSpell, SerpentArrow, SavageShaman, TrappableContainer all use `GetPoison(int level)` which now correctly filters to Standard family - [ ] Darkglow: poison tick deals +10% damage when attacker is >1 tile away, sends "Darkglow poison increases your damage!" message - [ ] Parasitic: poison tick heals attacker for damage dealt when within 1 tile, sends heal message - [ ] InfectiousStrike preserves poison family and respects family-specific skill scaling - [ ] EvilOmen + NinjaWeapons level bump stays within poison family - [ ] ArchCure/CleansingWinds cure chance calculations work correctly across all poison families - [ ] Serialization round-trips correctly using Index
This commit is contained in:
parent
3bb38bcb5b
commit
992bc95164
12 changed files with 316 additions and 205 deletions
|
|
@ -12,7 +12,9 @@ public partial class PotionKeg : Item
|
|||
TileData.ItemTable[0x1940].Height = 4;
|
||||
}
|
||||
|
||||
[InvalidateProperties] [SerializableField(0)] [SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
[InvalidateProperties]
|
||||
[SerializableField(0)]
|
||||
[SerializedCommandProperty(AccessLevel.GameMaster)]
|
||||
private PotionEffect _type;
|
||||
|
||||
[Constructible]
|
||||
|
|
@ -45,12 +47,20 @@ public partial class PotionKeg : Item
|
|||
{
|
||||
get
|
||||
{
|
||||
if (_held > 0 && (int)_type >= (int)PotionEffect.Conflagration)
|
||||
if (_held <= 0)
|
||||
{
|
||||
return 1072658 + (int)_type - (int)PotionEffect.Conflagration;
|
||||
return 1041641;
|
||||
}
|
||||
|
||||
return _held > 0 ? 1041620 + (int)_type : 1041641;
|
||||
return _type switch
|
||||
{
|
||||
< PotionEffect.Nightsight or > PotionEffect.FlintsPungentBrew => 1041619,
|
||||
PotionEffect.FlintsPungentBrew => 1113608,
|
||||
>= PotionEffect.Parasitic => 1080069 + (int)_type - (int)PotionEffect.Parasitic,
|
||||
PotionEffect.Invisibility => 1080071,
|
||||
>= PotionEffect.Conflagration => 1072658 + (int)_type - (int)PotionEffect.Conflagration,
|
||||
_ => 1041620 + (int)_type
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -249,6 +259,9 @@ public partial class PotionKeg : Item
|
|||
PotionEffect.ConflagrationGreater => new GreaterConflagrationPotion(),
|
||||
PotionEffect.ConfusionBlast => new ConfusionBlastPotion(),
|
||||
PotionEffect.ConfusionBlastGreater => new GreaterConfusionBlastPotion(),
|
||||
PotionEffect.Invisibility => new InvisibilityPotion(),
|
||||
PotionEffect.Parasitic => new ParasiticPotion(),
|
||||
PotionEffect.Darkglow => new DarkglowPotion(),
|
||||
_ => new NightSightPotion()
|
||||
};
|
||||
|
||||
|
|
@ -279,6 +292,9 @@ public partial class PotionKeg : Item
|
|||
_ when type == typeof(GreaterConflagrationPotion) => PotionEffect.ConflagrationGreater,
|
||||
_ when type == typeof(ConfusionBlastPotion) => PotionEffect.ConfusionBlast,
|
||||
_ when type == typeof(GreaterConfusionBlastPotion) => PotionEffect.ConfusionBlastGreater,
|
||||
_ /* when type == typeof(NightSightPotion) */ => PotionEffect.Nightsight
|
||||
_ when type == typeof(InvisibilityPotion) => PotionEffect.Invisibility,
|
||||
_ when type == typeof(ParasiticPotion) => PotionEffect.Parasitic,
|
||||
_ when type == typeof(DarkglowPotion) => PotionEffect.Darkglow,
|
||||
_ => PotionEffect.Nightsight
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@ public enum PotionEffect
|
|||
ConfusionBlastGreater,
|
||||
Invisibility,
|
||||
Parasitic,
|
||||
Darkglow
|
||||
Darkglow,
|
||||
FlintsPungentBrew
|
||||
}
|
||||
|
||||
[SerializationGenerator(2, false)]
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ public partial class DarkglowPotion : BasePoisonPotion
|
|||
[Constructible]
|
||||
public DarkglowPotion() : base(PotionEffect.Darkglow) => Hue = 0x96;
|
||||
|
||||
/* public override Poison Poison => Poison.DarkGlow; // MUST be restored when prerequisites are done */
|
||||
public override Poison Poison => Poison.Greater;
|
||||
public override Poison Poison => Poison.GreaterDarkglow;
|
||||
|
||||
public override double MinPoisoningSkill => 95.0;
|
||||
public override double MaxPoisoningSkill => 100.0;
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ public partial class ParasiticPotion : BasePoisonPotion
|
|||
[Constructible]
|
||||
public ParasiticPotion() : base(PotionEffect.Parasitic) => Hue = 0x17C;
|
||||
|
||||
/* public override Poison Poison => Poison.Parasitic; // MUST be restored when prerequisites are done */
|
||||
public override Poison Poison => Poison.Greater;
|
||||
public override Poison Poison => Poison.DeadlyParasitic;
|
||||
|
||||
public override double MinPoisoningSkill => 95.0;
|
||||
public override double MaxPoisoningSkill => 100.0;
|
||||
|
||||
public override int LabelNumber => 1072848; // Parasitic Poison
|
||||
}
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ public static class NinjaWeapon
|
|||
{
|
||||
if (EvilOmenSpell.EndEffect(target))
|
||||
{
|
||||
target.ApplyPoison(from, Poison.GetPoison(weapon.Poison.Level + 1));
|
||||
target.ApplyPoison(from, Poison.IncreaseLevel(weapon.Poison));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue