ModernUO/Projects/UOContent/Items/Weapons/Abilities/BleedAttack.cs
2026-07-09 08:10:12 +02:00

162 lines
5.2 KiB
C#

using System;
using System.Collections.Generic;
using Server.Mobiles;
using Server.Spells;
using Server.Spells.Necromancy;
namespace Server.Items
{
/// <summary>
/// Make your opponent bleed profusely with this wicked use of your weapon.
/// When successful, the target will bleed for several seconds, taking damage as time passes for up to ten seconds.
/// The rate of damage slows down as time passes, and the blood loss can be completely staunched with the use of bandages.
/// </summary>
public class BleedAttack : WeaponAbility
{
private static readonly Dictionary<Mobile, Timer> _table = new();
public override int BaseMana => 30;
public override void OnHit(Mobile attacker, Mobile defender, int damage, WorldLocation worldLocation)
{
if (!Validate(attacker) || !CheckMana(attacker, true))
{
return;
}
ClearCurrentAbility(attacker);
// Necromancers under Lich or Wraith Form are immune to Bleed Attacks.
var context = TransformationSpellHelper.GetContext(defender);
if (context != null && (context.Type == typeof(LichFormSpell) || context.Type == typeof(WraithFormSpell)) ||
defender is BaseCreature creature && creature.BleedImmune)
{
attacker.SendLocalizedMessage(1062052); // Your target is not affected by the bleed attack!
return;
}
attacker.SendLocalizedMessage(1060159); // Your target is bleeding!
defender.SendLocalizedMessage(1060160); // You are bleeding!
if (defender is PlayerMobile)
{
defender.LocalOverheadMessage(MessageType.Regular, 0x21, 1060757); // You are bleeding profusely
defender.NonlocalOverheadMessage(
MessageType.Regular,
0x21,
1060758, // ~1_NAME~ is bleeding profusely
defender.Name
);
}
defender.PlaySound(0x133);
defender.FixedParticles(0x377A, 244, 25, 9950, 31, 0, EffectLayer.Waist);
BeginBleed(defender, attacker);
}
public static bool IsBleeding(Mobile m) => _table.ContainsKey(m);
public static void BeginBleed(Mobile m, Mobile from)
{
_table.TryGetValue(m, out var timer);
timer?.Stop();
var bloodDrinker = CheckBloodDrinker(from);
_table[m] = timer = new InternalTimer(from, m, bloodDrinker);
timer.Start();
}
public static void DoBleed(Mobile m, Mobile from, int level)
{
DoBleed(m, from, level, false);
}
internal static void DoBleed(Mobile m, Mobile from, int level, bool bloodDrinker)
{
if (m.Alive)
{
var damage = Utility.RandomMinMax(level, level * 2);
if (!m.Player)
{
damage *= 2;
}
m.PlaySound(0x133);
var oldHits = m.Hits;
m.Damage(damage, from);
var applied = Math.Max(0, oldHits - m.Hits);
if (bloodDrinker && applied > 0 && from is { Deleted: false, Alive: true })
{
var oldFromHits = from.Hits;
from.Heal(applied, from, message: false);
if (from.Hits > oldFromHits)
{
from.SendLocalizedMessage(1113606); // The blood drinker effect heals you.
}
}
var blood = new Blood { ItemID = Utility.Random(0x122A, 5) };
blood.MoveToWorld(m.Location, m.Map);
}
else
{
EndBleed(m, false);
}
}
public static void EndBleed(Mobile m, bool message)
{
if (!_table.Remove(m, out var t))
{
return;
}
t.Stop();
if (message)
{
m.SendLocalizedMessage(1060167); // The bleeding wounds have healed, you are no longer bleeding!
}
}
internal static bool CheckBloodDrinker(Mobile from)
{
if (!Core.SA || from?.Deleted != false || !from.Alive)
{
return false;
}
return from.Weapon is BaseWeapon weapon && weapon.ExtendedWeaponAttributes.BloodDrinker != 0;
}
private class InternalTimer : Timer
{
private readonly Mobile m_From;
private readonly Mobile m_Mobile;
private readonly bool m_BloodDrinker;
public InternalTimer(Mobile from, Mobile m, bool bloodDrinker) : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0), 5)
{
m_From = from;
m_Mobile = m;
m_BloodDrinker = bloodDrinker;
}
protected override void OnTick()
{
DoBleed(m_Mobile, m_From, 5 - Index, m_BloodDrinker);
if (Index == 4)
{
EndBleed(m_Mobile, true);
}
}
}
}
}