fix: Fixes lightning arrow (#1583)

### Summary
- [X] Lightning arrow no longer allows SDI
- [X] Lightning arrow now proc's even without arrows
- [X] Fixed NPE with lightning arrow when a monster is already killed.
This commit is contained in:
Kamron Batman 2023-11-05 17:36:09 -08:00 committed by GitHub
parent ca3df9cfa7
commit c8463e2eaf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 104 additions and 79 deletions

View file

@ -12,7 +12,7 @@ namespace Server.Items
public override int BaseMana => 30;
public override double DamageScalar => 0.9;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -12,7 +12,7 @@ namespace Server.Items
public override bool RequiresSE => true;
public override bool RequiresSecondarySkill(Mobile from) => true;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -69,18 +69,18 @@ namespace Server.Items
? bwr.NewAbility.OnBeforeDamage(attacker, defender)
: base.OnBeforeDamage(attacker, defender);
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (CheckMana(attacker, false))
{
if (_newAttack.TryGetValue(attacker, out var bwr))
{
attacker.SendLocalizedMessage(1072841, $"#{bwr.ClilocEntry}");
bwr.NewAbility.OnHit(attacker, defender, damage);
bwr.NewAbility.OnHit(attacker, defender, damage, worldLocation);
}
else
{
base.OnHit(attacker, defender, damage);
base.OnHit(attacker, defender, damage, worldLocation);
}
_newAttack.Remove(attacker);

View file

@ -17,7 +17,7 @@ namespace Server.Items
public override int BaseMana => 30;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -13,7 +13,7 @@ namespace Server.Items
public override int BaseMana => 30;
public override bool RequiresSecondarySkill(Mobile from) => true;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -26,7 +26,7 @@ namespace Server.Items
return 200.0;
}
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -14,7 +14,7 @@ namespace Server.Items
public override int BaseMana => 30;
public override bool RequiresSecondarySkill(Mobile from) => true;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -33,7 +33,7 @@ namespace Server.Items
return 200.0;
}
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -16,7 +16,7 @@ public class Dismount : WeaponAbility
public override int BaseMana => 20;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -10,7 +10,7 @@ namespace Server.Items
public override bool RequiresTactics(Mobile from) => false;
public override bool RequiresSecondarySkill(Mobile from) => true;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
Use(attacker, defender);
}

View file

@ -9,7 +9,7 @@ namespace Server.Items
public override int BaseMana => 30;
public override double DamageScalar => 0.9;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -15,7 +15,7 @@ namespace Server.Items
public override bool RequiresSecondarySkill(Mobile from) => true;
public override SkillName GetSecondarySkillName(Mobile from) => SkillName.Ninjitsu;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -13,7 +13,7 @@ namespace Server.Items
public override int BaseMana => 30;
public override bool RequiresSecondarySkill(Mobile from) => true;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -10,7 +10,7 @@ namespace Server.Items
public override bool RequiresTactics(Mobile from) => false;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -7,7 +7,7 @@ namespace Server.Items
{
public override int BaseMana => 35;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -15,7 +15,7 @@ namespace Server.Items
public override bool RequiresTactics(Mobile from) => false;
public override bool RequiresSecondarySkill(Mobile from) => true;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -21,7 +21,7 @@ namespace Server.Items
public override bool RequiresTactics(Mobile from) => false;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -12,7 +12,7 @@ public class InfusedThrow : WeaponAbility
{
public override int BaseMana => 25;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!CheckMana(attacker, true))
{

View file

@ -8,10 +8,7 @@ namespace Server.Items
{
public override int BaseMana => 20;
//TODO - add ConsumeAmmo on weaponabilities
// public override bool ConsumeAmmo => false;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker))
{
@ -28,26 +25,38 @@ namespace Server.Items
}
using var list = PooledRefList<Mobile>.Create();
foreach (Mobile m in defender.GetMobilesInRange(5))
foreach (Mobile m in worldLocation.Map.GetMobilesInRange(worldLocation.Location, 5))
{
if (m != defender && m != attacker && SpellHelper.ValidIndirectTarget(attacker, m) && m?.Deleted == false &&
m.Map == attacker.Map && m.Alive && attacker.CanSee(m) && attacker.CanBeHarmful(m) &&
if (m != defender && m != attacker && SpellHelper.ValidIndirectTarget(attacker, m) &&
m is { Deleted: false, Alive: true } && attacker.CanSee(m) && attacker.CanBeHarmful(m) &&
attacker.InRange(m, weapon.MaxRange) && attacker.InLOS(m))
{
list.Add(m);
}
}
defender.BoltEffect(0);
// Defender might be already dead/internalized
if (defender is { Deleted: false, Alive: true })
{
defender.BoltEffect(0);
AOS.Damage(defender, attacker, Utility.RandomMinMax(29, 40), 0, 0, 0, 0, 100);
}
else
{
Effects.SendBoltEffect(new Entity(Serial.Zero, worldLocation.Location, worldLocation.Map));
}
var count = Math.Min(list.Count, 2);
list.Shuffle();
for (var i = 0; i < count; i++)
if (count > 0)
{
var m = list[i];
m.BoltEffect(0);
AOS.Damage(m, attacker, Utility.RandomMinMax(29, 40), 0, 0, 0, 0, 100);
list.Shuffle();
for (var i = 0; i < count; i++)
{
var m = list[i];
m.BoltEffect(0);
AOS.Damage(m, attacker, Utility.RandomMinMax(29, 40), 0, 0, 0, 0, 100);
}
}
}
}

View file

@ -17,7 +17,7 @@ namespace Server.Items
public override int BaseMana => 30;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -23,7 +23,7 @@ namespace Server.Items
attacker.SendLocalizedMessage(1060089); // You fail to execute your special move
}
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
// Validates in OnSwing for accuracy scalar

View file

@ -13,7 +13,7 @@ public class MysticArc : WeaponAbility
public override int BaseMana => 20;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!CheckMana(attacker, true) && defender != null)
{

View file

@ -23,7 +23,7 @@ namespace Server.Items
return true;
}
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -54,7 +54,7 @@ namespace Server.Items
return true;
}
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -8,7 +8,7 @@ namespace Server.Items
public static Dictionary<Mobile, PsychicAttackTimer> Registry { get; } = new();
public override int BaseMana => 30;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -16,7 +16,7 @@ namespace Server.Items
public override bool RequiresSecondarySkill(Mobile from) => true;
public override SkillName GetSecondarySkillName(Mobile from) => SkillName.Bushido;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!defender.Mounted)
{

View file

@ -9,7 +9,7 @@ namespace Server.Items
public override double GetRequiredSecondarySkill(Mobile from) => 60;
public override SkillName GetSecondarySkillName(Mobile from) => SkillName.Poisoning;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -35,7 +35,7 @@ namespace Server.Items
return false;
}
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -17,7 +17,7 @@ namespace Server.Items
public override SkillName GetSecondarySkillName(Mobile from) => SkillName.Ninjitsu;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (_defenders.Contains(defender) || !Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -96,7 +96,8 @@ namespace Server.Items
public virtual bool ValidatesDuringHit => true;
public virtual void OnHit(Mobile attacker, Mobile defender, int damage)
// Passing location since defender might be already killed (deleted/internalized)
public virtual void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
}
@ -276,7 +277,7 @@ namespace Server.Items
return false;
}
private int GetSkillLocalization(SkillName skill)
private static int GetSkillLocalization(SkillName skill)
{
return skill switch
{
@ -359,28 +360,36 @@ namespace Server.Items
string option = this switch
{
ArmorIgnore _ => "Armor Ignore",
ArmorPierce _ => "Armor Pierce",
Bladeweave _ => "Bladeweave",
BleedAttack _ => "Bleed Attack",
Block _ => "Block",
ConcussionBlow _ => "Concussion Blow",
CrushingBlow _ => "Crushing Blow",
DefenseMastery _ => "Defense Mastery",
Disarm _ => "Disarm",
Dismount _ => "Dismount",
DoubleShot _ => "Double Shot",
DoubleStrike _ => "Double Strike",
DualWield _ => "Dual Wield",
Feint _ => "Feint",
ForceArrow _ => "Force Arrow",
ForceOfNature _ => "Force of Nature",
FrenziedWhirlwind _ => "Frenzied Whirlwind",
InfectiousStrike _ => "Infectious Strike",
InfusedThrow _ => "Infused Throw",
LightningArrow _ => "Lightning Arrow",
MortalStrike _ => "Mortal Strike",
MovingShot _ => "Moving Shot",
ParalyzingBlow _ => "Paralyzing Blow",
ShadowStrike _ => "Shadow Strike",
WhirlwindAttack _ => "Whirlwind Attack",
RidingSwipe _ => "Riding Swipe",
FrenziedWhirlwind _ => "Frenzied Whirlwind",
Block _ => "Block",
DefenseMastery _ => "Defense Mastery",
MysticArc _ => "Mystic Arc",
NerveStrike _ => "Nerve Strike",
ParalyzingBlow _ => "Paralyzing Blow",
PsychicAttack _ => "Psychic Attack",
RidingSwipe _ => "Riding Swipe",
SerpentArrow _ => "Serpent Arrow",
ShadowStrike _ => "Shadow Strike",
TalonStrike _ => "Talon Strike",
Feint _ => "Feint",
DualWield _ => "Dual Wield",
DoubleShot _ => "Double Shot",
ArmorPierce _ => "Armor Pierce",
WhirlwindAttack _ => "Whirlwind Attack",
_ => null
};

View file

@ -12,7 +12,7 @@ namespace Server.Items
{
public override int BaseMana => 15;
public override void OnHit(Mobile attacker, Mobile defender, int damage)
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{

View file

@ -1066,21 +1066,19 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
{
var m = from;
var serial = Serial;
if (strBonus != 0)
{
m.AddStatMod(new StatMod(StatType.Str, $"{serial}Str", strBonus, TimeSpan.Zero));
m.AddStatMod(new StatMod(StatType.Str, $"{Serial}Str", strBonus, TimeSpan.Zero));
}
if (dexBonus != 0)
{
m.AddStatMod(new StatMod(StatType.Dex, $"{serial}Dex", dexBonus, TimeSpan.Zero));
m.AddStatMod(new StatMod(StatType.Dex, $"{Serial}Dex", dexBonus, TimeSpan.Zero));
}
if (intBonus != 0)
{
m.AddStatMod(new StatMod(StatType.Int, $"{serial}Int", intBonus, TimeSpan.Zero));
m.AddStatMod(new StatMod(StatType.Int, $"{Serial}Int", intBonus, TimeSpan.Zero));
}
}
@ -1871,6 +1869,7 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
damage = AOS.Scale(damage, 100 + percentageBonus);
var defLoc = new WorldLocation(defender);
var bcAtt = attacker as BaseCreature;
var bcDef = defender as BaseCreature;
@ -2210,7 +2209,7 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
bcAtt?.OnGaveMeleeAttack(defender, damage);
bcDef?.OnGotMeleeAttack(attacker, damage);
a?.OnHit(attacker, defender, damage);
a?.OnHit(attacker, defender, damage, defLoc);
move?.OnHit(attacker, defender, damage);
ForceOfNature.OnHit(attacker, defender);
@ -2276,23 +2275,26 @@ public abstract partial class BaseWeapon : Item, IWeapon, IFactionItem, ICraftab
public virtual CheckSlayerResult CheckSlayers(Mobile attacker, Mobile defender)
{
var atkWeapon = attacker.Weapon as BaseWeapon;
var atkSlayer = SlayerGroup.GetEntryByName(atkWeapon?.Slayer ?? SlayerName.None);
var atkSlayer2 = SlayerGroup.GetEntryByName(atkWeapon?.Slayer2 ?? SlayerName.None);
if (atkWeapon is ButchersWarCleaver && TalismanSlayer.Slays(TalismanSlayerName.Bovine, defender))
if (WeaponAbility.GetCurrentAbility(attacker) is not LightningArrow)
{
return CheckSlayerResult.Slayer;
}
var atkWeapon = attacker.Weapon as BaseWeapon;
var atkSlayer = SlayerGroup.GetEntryByName(atkWeapon?.Slayer ?? SlayerName.None);
var atkSlayer2 = SlayerGroup.GetEntryByName(atkWeapon?.Slayer2 ?? SlayerName.None);
if (atkSlayer?.Slays(defender) == true || atkSlayer2?.Slays(defender) == true)
{
return CheckSlayerResult.Slayer;
}
if (atkWeapon is ButchersWarCleaver && TalismanSlayer.Slays(TalismanSlayerName.Bovine, defender))
{
return CheckSlayerResult.Slayer;
}
if (attacker.Talisman is BaseTalisman talisman && TalismanSlayer.Slays(talisman.Slayer, defender))
{
return CheckSlayerResult.Slayer;
if (atkSlayer?.Slays(defender) == true || atkSlayer2?.Slays(defender) == true)
{
return CheckSlayerResult.Slayer;
}
if (attacker.Talisman is BaseTalisman talisman && TalismanSlayer.Slays(talisman.Slayer, defender))
{
return CheckSlayerResult.Slayer;
}
}
if (!Core.SE)

View file

@ -81,6 +81,12 @@ namespace Server.Items
OnMiss(attacker, defender);
}
}
else if (WeaponAbility.GetCurrentAbility(attacker) is LightningArrow lightningArrow)
{
// Lightning Arrow doesn't require ammunition
attacker.MovingEffect(defender, EffectID, 18, 1, false, false);
lightningArrow.OnHit(attacker, defender, 0, new WorldLocation(defender));
}
}
attacker.RevealingAction();
@ -201,7 +207,6 @@ namespace Server.Items
}
attacker.MovingEffect(defender, EffectID, 18, 1, false, false);
return true;
}
}