Skip to content

Commit

Permalink
Fix unresisted amnesia spells generating aggro
Browse files Browse the repository at this point in the history
  • Loading branch information
bm01 committed Jul 3, 2024
1 parent bd82b96 commit b6e0120
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 162 deletions.
11 changes: 2 additions & 9 deletions GameServer/ECS-Effects/AmnesiaECSEffect.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DOL.GS
namespace DOL.GS
{
public class AmnesiaECSEffect : ECSGameSpellEffect
{
public AmnesiaECSEffect(ECSGameEffectInitParams initParams)
: base(initParams) { }
public AmnesiaECSEffect(ECSGameEffectInitParams initParams) : base(initParams) { }

public override void OnStartEffect()
{
Expand Down
8 changes: 3 additions & 5 deletions GameServer/ai/brain/StandardMob/StandardMobBrain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -589,13 +589,11 @@ public virtual bool CanAggroTarget(GameLiving target)

public virtual void OnAttackedByEnemy(AttackData ad)
{
if (!Body.IsAlive || Body.ObjectState != GameObject.eObjectState.Active)
if (!Body.IsAlive || Body.ObjectState != GameObject.eObjectState.Active || FSM.GetCurrentState() == FSM.GetState(eFSMStateType.PASSIVE))
return;

if (FSM.GetCurrentState() == FSM.GetState(eFSMStateType.PASSIVE))
return;

ConvertDamageToAggroAmount(ad.Attacker, Math.Max(1, ad.Damage + ad.CriticalDamage));
if (ad.GeneratesAggro)
ConvertDamageToAggroAmount(ad.Attacker, Math.Max(1, ad.Damage + ad.CriticalDamage));

if (FSM.GetCurrentState() != FSM.GetState(eFSMStateType.AGGRO) && HasAggro)
{
Expand Down
2 changes: 2 additions & 0 deletions GameServer/gameutils/AttackData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,5 +316,7 @@ public bool CausesCombat
get { return m_causesCombat; }
set { m_causesCombat = value; }
}

public bool GeneratesAggro => SpellHandler == null || SpellHandler.Spell.SpellType is not eSpellType.Amnesia || IsSpellResisted;
}
}
185 changes: 47 additions & 138 deletions GameServer/spells/AmnesiaSpellHandler.cs
Original file line number Diff line number Diff line change
@@ -1,152 +1,61 @@
using DOL.AI.Brain;
using DOL.GS.PacketHandler;
using DOL.Language;

namespace DOL.GS.Spells
{
[SpellHandlerAttribute("Amnesia")]
public class AmnesiaSpellHandler : SpellHandler
{
public override ECSGameSpellEffect CreateECSEffect(ECSGameEffectInitParams initParams)
{
return new AmnesiaECSEffect(initParams);
}

/// <summary>
/// Execute direct damage spell
/// </summary>
/// <param name="target"></param>
public override void FinishSpellCast(GameLiving target)
{
m_caster.Mana -= PowerCost(target);
base.FinishSpellCast(target);
}

public override void OnDirectEffect(GameLiving target)
{
base.OnDirectEffect(target);
if (target == null || !target.IsAlive)
return;

/// [Atlas - Takii] This is a silly change by a silly person because disallowing Amnesia while MoC'd has never been a thing in this game.
//if (Caster.EffectList.GetOfType<MasteryofConcentrationEffect>() != null)
// return;
[SpellHandlerAttribute("Amnesia")]
public class AmnesiaSpellHandler : SpellHandler
{
public AmnesiaSpellHandler(GameLiving caster, Spell spell, SpellLine line) : base(caster, spell, line) { }

public override ECSGameSpellEffect CreateECSEffect(ECSGameEffectInitParams initParams)
{
return new AmnesiaECSEffect(initParams);
}

public override void FinishSpellCast(GameLiving target)
{
m_caster.Mana -= PowerCost(target);
base.FinishSpellCast(target);
}

public override void OnDirectEffect(GameLiving target)
{
base.OnDirectEffect(target);

if (target == null || !target.IsAlive)
return;

//have to do it here because OnAttackedByEnemy is not called to not get aggro
//if (target.Realm == 0 || Caster.Realm == 0)
//target.LastAttackedByEnemyTickPvE = GameLoop.GameLoopTime;
//else target.LastAttackedByEnemyTickPvP = GameLoop.GameLoopTime;
SendEffectAnimation(target, 0, false, 1);
SendEffectAnimation(target, 0, false, 1);

if (target is GamePlayer)
{
((GamePlayer)target).styleComponent.NextCombatStyle = null;
((GamePlayer)target).styleComponent.NextCombatBackupStyle = null;
}
if (target is GamePlayer player)
{
player.styleComponent.NextCombatStyle = null;
player.styleComponent.NextCombatBackupStyle = null;
}

//Amnesia only affects normal spells and not song activation (still affects pulses from songs though)
if (target.CurrentSpellHandler?.Spell.InstrumentRequirement == 0)
target.castingComponent.ClearUpSpellHandlers(); //stop even if MoC or QC
// Amnesia only affects normal spells and not song activation (still affects pulses from songs though)
if (target.CurrentSpellHandler?.Spell.InstrumentRequirement == 0)
target.castingComponent.ClearUpSpellHandlers();

target.rangeAttackComponent.AutoFireTarget = null;
//if(target is GamePlayer)
//target.TargetObject = null;
target.rangeAttackComponent.AutoFireTarget = null;

if (target is GamePlayer)
MessageToLiving(target, LanguageMgr.GetTranslation((target as GamePlayer).Client, "Amnesia.MessageToTarget"), eChatType.CT_Spell);

/*
GameSpellEffect effect;
effect = SpellHandler.FindEffectOnTarget(target, "Mesmerize");
if (effect != null)
{
effect.Cancel(false);
return;
}*/

//Targets next tick for pulsing speed enhancement spell will be skipped.
// if (target.effectListComponent.ContainsEffectForEffectType(eEffect.Pulse))
// {
// //EffectListService.TryCancelFirstEffectOfTypeOnTarget(target, eEffect.Pulse);
// foreach(ECSGameEffect e in target.effectListComponent.GetAllPulseEffects())
// {

// if(e is ECSGameSpellEffect effect && effect.SpellHandler.Spell.SpellType == eSpellType.SpeedEnhancement)
// {
// Console.WriteLine($"effect: {effect} SpellType: {effect.SpellHandler.Spell.SpellType} PulseFreq: {effect.PulseFreq} ");
// if(effect.ExpireTick > GameLoop.GameLoopTime && effect.ExpireTick < (GameLoop.GameLoopTime + 10000))
// {
// effect.ExpireTick += effect.PulseFreq;
// if(effect.ExpireTick < (GameLoop.GameLoopTime + 10000))
// effect.ExpireTick += effect.PulseFreq;

// }
// }
// }
// }

// //Casters next tick for pulsing speed enhancement spell will be skipped
// if (Caster.effectListComponent.ContainsEffectForEffectType(eEffect.Pulse))
// {
// //EffectListService.TryCancelFirstEffectOfTypeOnTarget(target, eEffect.Pulse);
// foreach(ECSGameEffect e in Caster.effectListComponent.GetAllPulseEffects())
// {

// if(e is ECSGameSpellEffect effect && effect.SpellHandler.Spell.SpellType == eSpellType.SpeedEnhancement)
// {
// Console.WriteLine($"effect: {effect} SpellType: {effect.SpellHandler.Spell.SpellType} PulseFreq: {effect.PulseFreq} Duration: {effect.Duration} ");

// if(effect.ExpireTick > GameLoop.GameLoopTime && effect.ExpireTick < (GameLoop.GameLoopTime + 10000))
// {
// effect.ExpireTick += effect.PulseFreq;
// if(effect.ExpireTick < (GameLoop.GameLoopTime + 10000))
// effect.ExpireTick += effect.PulseFreq;

// }
// }
// }
// }

// //Cancel Mez on target if Amnesia hits.
// if (target.effectListComponent.ContainsEffectForEffectType(eEffect.Mez))
// {
// var effect = EffectListService.GetEffectOnTarget(target, eEffect.Mez);

// if (effect != null)
// EffectService.RequestImmediateCancelEffect(effect);
// }

if (target is GameNPC)
{
GameNPC npc = (GameNPC)target;
IOldAggressiveBrain aggroBrain = npc.Brain as IOldAggressiveBrain;
if (aggroBrain != null)
{
if (Util.Chance(Spell.AmnesiaChance) && npc.TargetObject != null && npc.TargetObject is GameLiving living)
{
aggroBrain.ClearAggroList();
aggroBrain.AddToAggroList(living, 1);
}

}
}
}

/// <summary>
/// When spell was resisted
/// </summary>
/// <param name="target">the target that resisted the spell</param>
protected override void OnSpellResisted(GameLiving target)
{
base.OnSpellResisted(target);
if (Spell.CastTime == 0)
{
// start interrupt even for resisted instant amnesia
target.StartInterruptTimer(target.SpellInterruptDuration, AttackData.eAttackType.Spell, Caster);
}
}

// constructor
public AmnesiaSpellHandler(GameLiving caster, Spell spell, SpellLine line) : base(caster, spell, line) {}
}
}

/// <summary>
/// When spell was resisted
/// </summary>
/// <param name="target">the target that resisted the spell</param>
protected override void OnSpellResisted(GameLiving target)
{
base.OnSpellResisted(target);

// Start interrupt even for resisted instant amnesia.
if (Spell.CastTime == 0)
target.StartInterruptTimer(target.SpellInterruptDuration, AttackData.eAttackType.Spell, Caster);
}
}
}
22 changes: 12 additions & 10 deletions GameServer/spells/SpellHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2324,23 +2324,25 @@ public virtual void ApplyEffectOnTarget(GameLiving target)

if (!HasPositiveEffect)
{
AttackData ad = new AttackData();
ad.Attacker = Caster;
ad.Target = target;
ad.AttackType = AttackData.eAttackType.Spell;
ad.SpellHandler = this;
ad.AttackResult = eAttackResult.HitUnstyled;
ad.IsSpellResisted = false;
ad.Damage = (int)Spell.Damage;
ad.DamageType = Spell.DamageType;
AttackData ad = new()
{
Attacker = Caster,
Target = target,
AttackType = AttackData.eAttackType.Spell,
SpellHandler = this,
AttackResult = eAttackResult.HitUnstyled,
IsSpellResisted = false,
Damage = (int) Spell.Damage,
DamageType = Spell.DamageType
};

m_lastAttackData = ad;
Caster.OnAttackEnemy(ad);

// Harmful spells that deal no damage (ie. debuffs) should still trigger OnAttackedByEnemy.
// Exception for DoTs here since the initial landing of the DoT spell reports 0 damage
// and the first tick damage is done by the pulsing effect, which takes care of firing OnAttackedByEnemy.
if (ad.Damage == 0 && ad.SpellHandler.Spell.SpellType != eSpellType.DamageOverTime)
if (ad.Damage == 0 && ad.SpellHandler.Spell.SpellType is not eSpellType.DamageOverTime)
target.OnAttackedByEnemy(ad);
}
}
Expand Down

0 comments on commit b6e0120

Please sign in to comment.