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)
{
mob.RemoveStatMod("[Magic] Str Offset");
mob.RemoveStatMod("[Magic] Dex Offset");
mob.RemoveStatMod("[Magic] Int Offset");
mob.RemoveStatMod("[Magic] Str Buff");
mob.RemoveStatMod("[Magic] Dex Buff");
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("blood-rose");
mob.RemoveStatMod("clarity-potion");
mob.RemoveStatMod("RoseOfTrinsicPetal");
mob.RemoveStatMod("Holy Bless");
mob.RemoveStatMod("Holy Curse");
OrangePetals.RemoveContext(mob);

View file

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

View file

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

View file

@ -41,12 +41,15 @@ namespace Server.Items
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))
{
timerToken.Cancel();
return true;
}
return false;
}
public static void BeginWound(Mobile m, TimeSpan duration)
@ -58,11 +61,16 @@ namespace Server.Items
m.YellowHealthbar = true;
}
public static void EndWound(Mobile m)
public static bool EndWound(Mobile m)
{
StopTimer(m);
m.YellowHealthbar = false;
m.SendLocalizedMessage(1060208); // You are no longer mortally wounded.
if (StopTimer(m))
{
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)
{
var offset = bonus;
var name = $"[Magic] {type} Offset";
var name = $"[Magic] {type} Buff";
var mod = target.GetStatMod(name);

View file

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

View file

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

View file

@ -80,12 +80,16 @@ namespace Server.Spells.Mysticism
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)
@ -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;
m_Next.StartPlague();
@ -191,6 +195,8 @@ namespace Server.Spells.Mysticism
_table.Remove(m_Target);
BuffInfo.RemoveBuff(m_Target, BuffIcon.SpellPlague);
}
Stop();
}
}

View file

@ -65,8 +65,7 @@ namespace Server.Spells.Necromancy
* ((ss-rm)/8)+8
*/
_table.TryGetValue(m, out var timer);
timer?.DoExpire();
RemoveCurse(m);
m_OathTable[Caster] = Caster;
m_OathTable[m] = Caster;
@ -84,7 +83,7 @@ namespace Server.Spells.Necromancy
var duration = TimeSpan.FromSeconds((GetDamageSkill(Caster) - GetResistSkill(m)) / 8 + 8);
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();
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);
}
public static void RemoveCurse(Mobile m)
public static bool RemoveCurse(Mobile target)
{
_table.TryGetValue(m, out var t);
t?.DoExpire();
if (_table.Remove(target, out var timer))
{
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) =>
@ -113,48 +132,29 @@ namespace Server.Spells.Necromancy
private class ExpireTimer : Timer
{
private readonly Mobile m_Caster;
private readonly DateTime m_End;
private readonly Mobile m_Target;
private Mobile _target;
private DateTime _end;
public Mobile Caster { get; }
public ExpireTimer(Mobile caster, Mobile target, TimeSpan delay) : base(
TimeSpan.FromSeconds(1.0),
TimeSpan.FromSeconds(1.0)
)
{
m_Caster = caster;
m_Target = target;
m_End = Core.Now + delay;
Caster = caster;
_target = target;
_end = Core.Now + delay;
}
protected override void OnTick()
{
if (m_Caster.Deleted || m_Target.Deleted || !m_Caster.Alive || !m_Target.Alive ||
Core.Now >= m_End)
if (Caster.Deleted || _target.Deleted || !Caster.Alive || !_target.Alive ||
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);
}
public static void ClearMindRotScalar(Mobile m)
public static bool ClearMindRotScalar(Mobile m)
{
if (_table.Remove(m, out var tmpB))
{
tmpB.m_MRExpireTimer.Stop();
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);
@ -127,7 +129,6 @@ namespace Server.Spells.Necromancy
if (m_Target.Deleted || !m_Target.Alive || Core.Now >= m_End)
{
MindRotSpell.ClearMindRotScalar(m_Target);
Stop();
}
}
}