fix: Fixes curses and spell effects (#1112)

* * Fix statmod naming mismatch: everything in code searches for "[Magic] {type} Offset" but stat reductions are being added as "[Magic] {type} Curse"

* Clarifies and cleans up curses

* Fixes blood oath

* * NobleSacrifice remove all curses in one go

* Dont need a method

* Fix extra parentheses

Co-authored-by: Kamron Batman <3953314+kamronbatman@users.noreply.github.com>
This commit is contained in:
mark1145 2022-07-08 16:59:46 +10:00 committed by GitHub
parent ad0e1702a3
commit bd4e6fc30e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 126 additions and 126 deletions

View file

@ -1817,12 +1817,18 @@ namespace Server.Engines.ConPVP
public static void Debuff(Mobile mob) public static void Debuff(Mobile mob)
{ {
mob.RemoveStatMod("[Magic] Str Offset"); mob.RemoveStatMod("[Magic] Str Buff");
mob.RemoveStatMod("[Magic] Dex Offset"); mob.RemoveStatMod("[Magic] Dex Buff");
mob.RemoveStatMod("[Magic] Int Offset"); mob.RemoveStatMod("[Magic] Int Buff");
mob.RemoveStatMod("[Magic] Str Curse");
mob.RemoveStatMod("[Magic] Dex Curse");
mob.RemoveStatMod("[Magic] Int Curse");
mob.RemoveStatMod("Concussion"); mob.RemoveStatMod("Concussion");
mob.RemoveStatMod("blood-rose"); mob.RemoveStatMod("blood-rose");
mob.RemoveStatMod("clarity-potion"); mob.RemoveStatMod("clarity-potion");
mob.RemoveStatMod("RoseOfTrinsicPetal");
mob.RemoveStatMod("Holy Bless");
mob.RemoveStatMod("Holy Curse");
OrangePetals.RemoveContext(mob); OrangePetals.RemoveContext(mob);

View file

@ -209,17 +209,8 @@ namespace Server.Factions
return true; return true;
} }
public int GetStatMod(Mobile mob, StatType type) public static int GetStatMod(Mobile mob, StatType type) =>
{ mob.GetStatMod($"[Magic] {type} Curse")?.Offset ?? 0;
var mod = mob.GetStatMod($"[Magic] {type} Offset");
if (mod == null)
{
return 0;
}
return mod.Offset;
}
public Spell RandomOffenseSpell() public Spell RandomOffenseSpell()
{ {

View file

@ -1238,24 +1238,22 @@ namespace Server.Items
0x100 0x100
); );
StatMod mod; var mod = target.GetStatMod("[Magic] Str Curse");
mod = target.GetStatMod("[Magic] Str Offset");
if (mod?.Offset < 0) if (mod?.Offset < 0)
{ {
target.RemoveStatMod("[Magic] Str Offset"); target.RemoveStatMod("[Magic] Str Curse");
} }
mod = target.GetStatMod("[Magic] Dex Offset"); mod = target.GetStatMod("[Magic] Dex Curse");
if (mod?.Offset < 0) if (mod?.Offset < 0)
{ {
target.RemoveStatMod("[Magic] Dex Offset"); target.RemoveStatMod("[Magic] Dex Curse");
} }
mod = target.GetStatMod("[Magic] Int Offset"); mod = target.GetStatMod("[Magic] Int Curse");
if (mod?.Offset < 0) if (mod?.Offset < 0)
{ {
target.RemoveStatMod("[Magic] Int Offset"); target.RemoveStatMod("[Magic] Int Curse");
} }
target.Paralyzed = false; target.Paralyzed = false;

View file

@ -41,12 +41,15 @@ namespace Server.Items
public static bool IsWounded(Mobile m) => _table.ContainsKey(m); public static bool IsWounded(Mobile m) => _table.ContainsKey(m);
private static void StopTimer(Mobile m) private static bool StopTimer(Mobile m)
{ {
if (_table.Remove(m, out var timerToken)) if (_table.Remove(m, out var timerToken))
{ {
timerToken.Cancel(); timerToken.Cancel();
return true;
} }
return false;
} }
public static void BeginWound(Mobile m, TimeSpan duration) public static void BeginWound(Mobile m, TimeSpan duration)
@ -58,11 +61,16 @@ namespace Server.Items
m.YellowHealthbar = true; m.YellowHealthbar = true;
} }
public static void EndWound(Mobile m) public static bool EndWound(Mobile m)
{ {
StopTimer(m); if (StopTimer(m))
m.YellowHealthbar = false; {
m.SendLocalizedMessage(1060208); // You are no longer mortally wounded. m.YellowHealthbar = false;
m.SendLocalizedMessage(1060208); // You are no longer mortally wounded.
return true;
}
return false;
} }
} }
} }

View file

@ -303,7 +303,7 @@ namespace Server.Spells
public static bool AddStatBonus(Mobile caster, Mobile target, StatType type, int bonus, TimeSpan duration) public static bool AddStatBonus(Mobile caster, Mobile target, StatType type, int bonus, TimeSpan duration)
{ {
var offset = bonus; var offset = bonus;
var name = $"[Magic] {type} Offset"; var name = $"[Magic] {type} Buff";
var mod = target.GetStatMod(name); var mod = target.GetStatMod(name);

View file

@ -1,7 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Server.Gumps; using Server.Gumps;
using Server.Items;
using Server.Mobiles; using Server.Mobiles;
using Server.Spells.Fourth;
using Server.Spells.Mysticism;
using Server.Spells.Necromancy; using Server.Spells.Necromancy;
namespace Server.Spells.Chivalry namespace Server.Spells.Chivalry
@ -83,7 +86,7 @@ namespace Server.Spells.Chivalry
} }
else else
{ {
var sendEffect = false; bool sendEffect = false;
if (m.Poisoned && m.CurePoison(Caster)) if (m.Poisoned && m.CurePoison(Caster))
{ {
@ -108,26 +111,24 @@ namespace Server.Spells.Chivalry
sendEffect = true; sendEffect = true;
} }
StatMod mod; var mod = m.GetStatMod("[Magic] Str Curse");
mod = m.GetStatMod("[Magic] Str Offset");
if (mod?.Offset < 0) if (mod?.Offset < 0)
{ {
m.RemoveStatMod("[Magic] Str Offset"); m.RemoveStatMod("[Magic] Str Curse");
sendEffect = true; sendEffect = true;
} }
mod = m.GetStatMod("[Magic] Dex Offset"); mod = m.GetStatMod("[Magic] Dex Curse");
if (mod?.Offset < 0) if (mod?.Offset < 0)
{ {
m.RemoveStatMod("[Magic] Dex Offset"); m.RemoveStatMod("[Magic] Dex Curse");
sendEffect = true; sendEffect = true;
} }
mod = m.GetStatMod("[Magic] Int Offset"); mod = m.GetStatMod("[Magic] Int Curse");
if (mod?.Offset < 0) if (mod?.Offset < 0)
{ {
m.RemoveStatMod("[Magic] Int Offset"); m.RemoveStatMod("[Magic] Int Curse");
sendEffect = true; sendEffect = true;
} }
@ -137,22 +138,24 @@ namespace Server.Spells.Chivalry
sendEffect = true; sendEffect = true;
} }
if (EvilOmenSpell.TryEndEffect(m)) sendEffect = EvilOmenSpell.TryEndEffect(m) || sendEffect;
{ sendEffect = StrangleSpell.RemoveCurse(m) || sendEffect;
sendEffect = true; sendEffect = CorpseSkinSpell.RemoveCurse(m) || sendEffect;
} sendEffect = CurseSpell.RemoveEffect(m) || sendEffect;
sendEffect = MortalStrike.EndWound(m) || sendEffect;
sendEffect = MindRotSpell.ClearMindRotScalar(m) || sendEffect;
sendEffect = BloodOathSpell.RemoveCurse(m) || sendEffect;
sendEffect = SpellPlagueSpell.RemoveEffect(m) || sendEffect;
if (StrangleSpell.RemoveCurse(m)) // TODO: Move these into their respective end effect methods
{ BuffInfo.RemoveBuff(m, BuffIcon.Clumsy);
sendEffect = true; BuffInfo.RemoveBuff(m, BuffIcon.FeebleMind);
} BuffInfo.RemoveBuff(m, BuffIcon.Weaken);
BuffInfo.RemoveBuff(m, BuffIcon.Curse);
if (CorpseSkinSpell.RemoveCurse(m)) BuffInfo.RemoveBuff(m, BuffIcon.MassCurse);
{ BuffInfo.RemoveBuff(m, BuffIcon.MortalStrike);
sendEffect = true; BuffInfo.RemoveBuff(m, BuffIcon.Strangle);
} BuffInfo.RemoveBuff(m, BuffIcon.EvilOmen);
// TODO: Should this remove blood oath? Pain spike?
if (sendEffect) if (sendEffect)
{ {

View file

@ -2,6 +2,7 @@ using System;
using Server.Engines.ConPVP; using Server.Engines.ConPVP;
using Server.Items; using Server.Items;
using Server.Spells.Fourth; using Server.Spells.Fourth;
using Server.Spells.Mysticism;
using Server.Spells.Necromancy; using Server.Spells.Necromancy;
using Server.Targeting; using Server.Targeting;
@ -44,24 +45,13 @@ namespace Server.Spells.Chivalry
* Chance of removing curse is affected by Caster's Karma. * Chance of removing curse is affected by Caster's Karma.
*/ */
int chance; int chance = Caster.Karma switch
if (Caster.Karma < -5000)
{ {
chance = 0; < -5000 => 0,
} < 0 => (int)Math.Sqrt(20000 + Caster.Karma) - 122,
else if (Caster.Karma < 0) < 5625 => (int)Math.Sqrt(Caster.Karma) + 25,
{ _ => 100
chance = (int)Math.Sqrt(20000 + Caster.Karma) - 122; };
}
else if (Caster.Karma < 5625)
{
chance = (int)Math.Sqrt(Caster.Karma) + 25;
}
else
{
chance = 100;
}
if (chance > Utility.Random(100)) if (chance > Utility.Random(100))
{ {
@ -88,22 +78,22 @@ namespace Server.Spells.Chivalry
0x100 0x100
); );
var mod = m.GetStatMod("[Magic] Str Offset"); var mod = m.GetStatMod("[Magic] Str Curse");
if (mod?.Offset < 0) if (mod?.Offset < 0)
{ {
m.RemoveStatMod("[Magic] Str Offset"); m.RemoveStatMod("[Magic] Str Curse");
} }
mod = m.GetStatMod("[Magic] Dex Offset"); mod = m.GetStatMod("[Magic] Dex Curse");
if (mod?.Offset < 0) if (mod?.Offset < 0)
{ {
m.RemoveStatMod("[Magic] Dex Offset"); m.RemoveStatMod("[Magic] Dex Curse");
} }
mod = m.GetStatMod("[Magic] Int Offset"); mod = m.GetStatMod("[Magic] Int Curse");
if (mod?.Offset < 0) if (mod?.Offset < 0)
{ {
m.RemoveStatMod("[Magic] Int Offset"); m.RemoveStatMod("[Magic] Int Curse");
} }
m.Paralyzed = false; m.Paralyzed = false;
@ -113,22 +103,19 @@ namespace Server.Spells.Chivalry
CorpseSkinSpell.RemoveCurse(m); CorpseSkinSpell.RemoveCurse(m);
CurseSpell.RemoveEffect(m); CurseSpell.RemoveEffect(m);
MortalStrike.EndWound(m); MortalStrike.EndWound(m);
if (Core.ML)
{
BloodOathSpell.RemoveCurse(m);
}
MindRotSpell.ClearMindRotScalar(m); MindRotSpell.ClearMindRotScalar(m);
BloodOathSpell.RemoveCurse(m);
SpellPlagueSpell.RemoveEffect(m);
// TODO: Move these into their respective end effect methods
BuffInfo.RemoveBuff(m, BuffIcon.Clumsy); BuffInfo.RemoveBuff(m, BuffIcon.Clumsy);
BuffInfo.RemoveBuff(m, BuffIcon.FeebleMind); BuffInfo.RemoveBuff(m, BuffIcon.FeebleMind);
BuffInfo.RemoveBuff(m, BuffIcon.Weaken); BuffInfo.RemoveBuff(m, BuffIcon.Weaken);
BuffInfo.RemoveBuff(m, BuffIcon.Curse); BuffInfo.RemoveBuff(m, BuffIcon.Curse);
BuffInfo.RemoveBuff(m, BuffIcon.MassCurse); BuffInfo.RemoveBuff(m, BuffIcon.MassCurse);
BuffInfo.RemoveBuff(m, BuffIcon.MortalStrike); BuffInfo.RemoveBuff(m, BuffIcon.MortalStrike);
BuffInfo.RemoveBuff(m, BuffIcon.Mindrot); BuffInfo.RemoveBuff(m, BuffIcon.Strangle);
BuffInfo.RemoveBuff(m, BuffIcon.EvilOmen);
// TODO: Should this remove blood oath? Pain spike?
} }
else else
{ {

View file

@ -80,12 +80,16 @@ namespace Server.Spells.Mysticism
public static bool UnderEffect(Mobile m) => _table.ContainsKey(m); public static bool UnderEffect(Mobile m) => _table.ContainsKey(m);
public static void RemoveEffect(Mobile m) public static bool RemoveEffect(Mobile m)
{ {
if (_table.TryGetValue(m, out var context)) if (_table.Remove(m, out var context))
{ {
context.EndPlague(false); context.Stop();
BuffInfo.RemoveBuff(m, BuffIcon.SpellPlague);
return true;
} }
return false;
} }
public static void CheckPlague(Mobile m) public static void CheckPlague(Mobile m)
@ -179,9 +183,9 @@ namespace Server.Spells.Mysticism
} }
} }
public void EndPlague(bool restart = true) public void EndPlague()
{ {
if (restart && m_Next != null) if (m_Next != null)
{ {
_table[m_Target] = m_Next; _table[m_Target] = m_Next;
m_Next.StartPlague(); m_Next.StartPlague();
@ -191,6 +195,8 @@ namespace Server.Spells.Mysticism
_table.Remove(m_Target); _table.Remove(m_Target);
BuffInfo.RemoveBuff(m_Target, BuffIcon.SpellPlague); BuffInfo.RemoveBuff(m_Target, BuffIcon.SpellPlague);
} }
Stop();
} }
} }

View file

@ -65,8 +65,7 @@ namespace Server.Spells.Necromancy
* ((ss-rm)/8)+8 * ((ss-rm)/8)+8
*/ */
_table.TryGetValue(m, out var timer); RemoveCurse(m);
timer?.DoExpire();
m_OathTable[Caster] = Caster; m_OathTable[Caster] = Caster;
m_OathTable[m] = Caster; m_OathTable[m] = Caster;
@ -84,7 +83,7 @@ namespace Server.Spells.Necromancy
var duration = TimeSpan.FromSeconds((GetDamageSkill(Caster) - GetResistSkill(m)) / 8 + 8); var duration = TimeSpan.FromSeconds((GetDamageSkill(Caster) - GetResistSkill(m)) / 8 + 8);
m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); // Skill check for gain m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); // Skill check for gain
timer = new ExpireTimer(Caster, m, duration); var timer = new ExpireTimer(Caster, m, duration);
timer.Start(); timer.Start();
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.BloodOathCaster, 1075659, duration, Caster, m.Name)); BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.BloodOathCaster, 1075659, duration, Caster, m.Name));
@ -102,10 +101,30 @@ namespace Server.Spells.Necromancy
Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12);
} }
public static void RemoveCurse(Mobile m) public static bool RemoveCurse(Mobile target)
{ {
_table.TryGetValue(m, out var t); if (_table.Remove(target, out var timer))
t?.DoExpire(); {
var caster = timer.Caster;
if (m_OathTable.Remove(caster))
{
caster.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
}
if (m_OathTable.Remove(target))
{
target.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
}
timer.Stop();
BuffInfo.RemoveBuff(caster, BuffIcon.BloodOathCaster);
BuffInfo.RemoveBuff(target, BuffIcon.BloodOathCurse);
return true;
}
return false;
} }
public static Mobile GetBloodOath(Mobile m) => public static Mobile GetBloodOath(Mobile m) =>
@ -113,48 +132,29 @@ namespace Server.Spells.Necromancy
private class ExpireTimer : Timer private class ExpireTimer : Timer
{ {
private readonly Mobile m_Caster; private Mobile _target;
private readonly DateTime m_End; private DateTime _end;
private readonly Mobile m_Target;
public Mobile Caster { get; }
public ExpireTimer(Mobile caster, Mobile target, TimeSpan delay) : base( public ExpireTimer(Mobile caster, Mobile target, TimeSpan delay) : base(
TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0),
TimeSpan.FromSeconds(1.0) TimeSpan.FromSeconds(1.0)
) )
{ {
m_Caster = caster; Caster = caster;
m_Target = target; _target = target;
m_End = Core.Now + delay; _end = Core.Now + delay;
} }
protected override void OnTick() protected override void OnTick()
{ {
if (m_Caster.Deleted || m_Target.Deleted || !m_Caster.Alive || !m_Target.Alive || if (Caster.Deleted || _target.Deleted || !Caster.Alive || !_target.Alive ||
Core.Now >= m_End) Core.Now >= _end)
{ {
DoExpire(); RemoveCurse(_target);
} }
} }
public void DoExpire()
{
if (m_OathTable.Remove(m_Caster))
{
m_Caster.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
}
if (m_OathTable.Remove(m_Target))
{
m_Target.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
}
Stop();
BuffInfo.RemoveBuff(m_Caster, BuffIcon.BloodOathCaster);
BuffInfo.RemoveBuff(m_Target, BuffIcon.BloodOathCurse);
_table.Remove(m_Caster);
}
} }
} }
} }

View file

@ -71,15 +71,17 @@ namespace Server.Spells.Necromancy
Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12);
} }
public static void ClearMindRotScalar(Mobile m) public static bool ClearMindRotScalar(Mobile m)
{ {
if (_table.Remove(m, out var tmpB)) if (_table.Remove(m, out var tmpB))
{ {
tmpB.m_MRExpireTimer.Stop(); tmpB.m_MRExpireTimer.Stop();
m.SendLocalizedMessage(1060872); // Your mind feels normal again. m.SendLocalizedMessage(1060872); // Your mind feels normal again.
BuffInfo.RemoveBuff(m, BuffIcon.Mindrot);
return true;
} }
BuffInfo.RemoveBuff(m, BuffIcon.Mindrot); return false;
} }
public static bool HasMindRotScalar(Mobile m) => _table.ContainsKey(m); public static bool HasMindRotScalar(Mobile m) => _table.ContainsKey(m);
@ -127,7 +129,6 @@ namespace Server.Spells.Necromancy
if (m_Target.Deleted || !m_Target.Alive || Core.Now >= m_End) if (m_Target.Deleted || !m_Target.Alive || Core.Now >= m_End)
{ {
MindRotSpell.ClearMindRotScalar(m_Target); MindRotSpell.ClearMindRotScalar(m_Target);
Stop();
} }
} }
} }