Code: Select all
using System;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Factions;
using System.Collections.Generic;
namespace Server.Mobiles
{
[CorpseName("an ascended elven corpse")]
public class ElvenBoss : BaseCreature
{
private Mobile m_TopDamager;
private DateTime m_NextSpecial = DateTime.MinValue;
private TimeSpan SpecialCooldown => TimeSpan.FromSeconds(Utility.RandomMinMax(10, 15));
public override bool InitialInnocent => false;
public override void OnDamagedBySpell(Mobile from)
{
base.OnDamagedBySpell(from);
TrackTopDamager(from);
}
public override void OnGotMeleeAttack(Mobile attacker)
{
base.OnGotMeleeAttack(attacker);
TrackTopDamager(attacker);
attacker.Stam = Math.Max(0, attacker.Stam - Utility.RandomMinMax(10, 25));
attacker.Mana = Math.Max(0, attacker.Mana - Utility.RandomMinMax(15, 30));
attacker.SendMessage(33, "You feel your strength being drained!");
}
private void TrackTopDamager(Mobile from)
{
if (from == null || from is BaseCreature)
return;
if (m_TopDamager == null || from.Hits > m_TopDamager.Hits)
m_TopDamager = from;
}
public override bool OnBeforeDamage(Mobile attacker, ref int damage)
{
if (attacker is BaseCreature bc && bc.Controlled)
{
damage = 0;
attacker.SendMessage(38, "Your pet cannot harm this being!");
return false;
}
return base.OnBeforeDamage(attacker, ref damage);
}
public override void OnThink()
{
base.OnThink();
if (DateTime.UtcNow >= m_NextSpecial)
{
PerformSpecialAttack();
m_NextSpecial = DateTime.UtcNow + SpecialCooldown;
}
}
private void PerformSpecialAttack()
{
Mobile target = Combatant;
if (target == null || !CanBeHarmful(target))
return;
int roll = Utility.Random(4); // 0–3
switch (roll)
{
case 0: // Paralyzing Blow
if (!target.Paralyzed)
{
DoHarmful(target);
target.Paralyzed = true;
Timer.DelayCall(TimeSpan.FromSeconds(5), () => target.Paralyzed = false);
PublicOverheadMessage(MessageType.Emote, 33, false, "*delivers a paralyzing strike!*");
target.SendMessage(33, "You have been paralyzed by a devastating blow!");
target.FixedEffect(0x376A, 9, 32);
}
break;
case 1: // Whirlwind Attack
PublicOverheadMessage(MessageType.Emote, 33, false, "*spins in a deadly arc!*");
PlaySound(0x23B);
foreach (Mobile m in GetMobilesInRange(1))
{
if (m != this && CanBeHarmful(m) && !m.Hidden && m.Alive)
{
DoHarmful(m);
AOS.Damage(m, this, Utility.RandomMinMax(30, 45), true, 100, 0, 0, 0, 0);
m.SendMessage(38, "You're struck by a whirlwind attack!");
m.FixedParticles(0x3728, 10, 20, 5032, 0, 0, EffectLayer.Waist);
}
}
break;
case 2: // Ignore Armor
DoHarmful(target);
int damage = Utility.RandomMinMax(55, 70);
target.Damage(damage);
target.SendMessage(38, "The strike bypasses your armor!");
PublicOverheadMessage(MessageType.Emote, 33, false, "*lands an armor-piercing strike!*");
target.FixedParticles(0x36BD, 20, 10, 5044, 0, 0, EffectLayer.Waist);
break;
case 3: // Disarm
DoHarmful(target);
if (target.FindItemOnLayer(Layer.OneHanded) is Item weapon)
{
target.SendMessage(38, "You have been disarmed!");
weapon.MoveToWorld(target.Location, target.Map);
PublicOverheadMessage(MessageType.Emote, 33, false, "*disarms their opponent with precision!*");
}
break;
}
}
[Constructable]
public ElvenBoss() : base(AIType.AI_Mage, FightMode.Closest, 12, 1, 0.2, 0.4)
{
Female = Utility.RandomBool();
Name = Female ? "Galadriel" : "Elrond [Half Elf]";
Body = Female ? 606 : 605;
Hue = 0x83EA;
Title = "- Ascended Avatar";
Fame = 45000;
Karma = -45000;
SetStr(1200, 1500);
SetDex(360, 480);
SetInt(1200, 1500);
SetHits(30000, 85000);
SetStam(3000);
SetMana(5000);
SetDamage(45, 70);
SetDamageType(ResistanceType.Physical, 45);
SetDamageType(ResistanceType.Fire, 45);
SetDamageType(ResistanceType.Cold, 45);
SetDamageType(ResistanceType.Poison, 45);
SetDamageType(ResistanceType.Energy, 45);
SetResistance(ResistanceType.Physical, 85);
SetResistance(ResistanceType.Fire, 85);
SetResistance(ResistanceType.Cold, 85);
SetResistance(ResistanceType.Poison, 85);
SetResistance(ResistanceType.Energy, 85);
SetSkill(SkillName.Magery, 120.0, 350.0);
SetSkill(SkillName.SpiritSpeak, 120.0, 350.0);
SetSkill(SkillName.Wrestling, 120.0, 350.0);
SetSkill(SkillName.Parry, 120.0, 350.0);
SetSkill(SkillName.Resist, 120.0, 350.0);
SetSkill(SkillName.Anatomy, 120.0, 350.0);
SetSkill(SkillName.Healing, 120.0, 350.0);
SetSkill(SkillName.Tactics, 120.0, 350.0);
VirtualArmor = 100;
FasterCasting = 4;
FasterCastRecovery = 6;
if (Female)
Faction = Minax.Instance;
else
Faction = CouncilOfMages.Instance;
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
if (m_TopDamager != null && m_TopDamager is PlayerMobile pm)
{
FellowshipRing ring = new FellowshipRing();
ring.LootType = LootType.Blessed;
pm.AddToBackpack(ring);
pm.SendMessage(38, "You have been granted the Fellowship Ring for your bravery!");
}
}
public ElvenBoss(Serial serial) : base(serial) { }
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.ReadInt();
}
}
}
below is the matching item.
Code: Select all
using System;
using Server;
using Server.Mobiles;
namespace Server.Items
{
public class FollowshipRing : Ring
{
private const double SwordsBonus = 15.0; // Or whatever you want
private const double TacticsBonus = 15.0; // Or whatever you want
private const double ParryBonus = 15.0; // Or whatever you want
private Account _boundAccount;
private DateTime _bindExpiration;
[Constructable]
public FollowshipRing()
{
Name = "Followship Ring";
Hue = 1153;
LootType = LootType.Blessed;
// Stat bonuses
Attributes.BonusStr = 10;
Attributes.BonusDex = 10;
// Combat & casting enhancements
Attributes.LowerRegCost = 40;
Attributes.LowerManaCost = 20;
Attributes.CastSpeed = 2;
Attributes.CastRecovery = 4;
Attributes.WeaponSpeed = 20;
Attributes.WeaponDamage = 45;
Attributes.SpellDamage = 30;
new InternalTimer(this).Start();
}
public override bool OnEquip(Mobile from)
{
if (from.Account == null)
return false;
if (_boundAccount == null)
{
// First-time equip: bind to this account
_boundAccount = from.Account as Account;
_bindExpiration = DateTime.UtcNow + TimeSpan.FromDays(14);
from.SendMessage(38, "The Followship Ring has been bound to your account for 14 days.");
}
else
{
// Already bound
if (_boundAccount != from.Account && DateTime.UtcNow < _bindExpiration)
{
from.SendMessage(33, "This item is bound to another account and cannot be equipped yet.");
return false;
}
}
// Apply hidden skill bonuses
AddSkillBonus(from, SkillName.Swords, SwordsBonus);
AddSkillBonus(from, SkillName.Tactics, TacticsBonus);
AddSkillBonus(from, SkillName.Parry, ParryBonus);
return base.OnEquip(from);
}
public override void OnRemoved(object parent)
{
base.OnRemoved(parent);
if (parent is Mobile m)
{
RemoveSkillBonus(m, SkillName.Swords, SwordsBonus);
RemoveSkillBonus(m, SkillName.Tactics, TacticsBonus);
RemoveSkillBonus(m, SkillName.Parry, ParryBonus);
}
}
private void AddSkillBonus(Mobile m, SkillName skill, double value)
{
Skill sk = m.Skills[skill];
if (sk != null)
sk.Base += value;
}
private void RemoveSkillBonus(Mobile m, SkillName skill, double value)
{
Skill sk = m.Skills[skill];
if (sk != null)
sk.Base -= value;
}
public override void OnSingleClick(Mobile from)
{
base.OnSingleClick(from);
LabelTo(from, "(Blessed)");
if (_boundAccount != null && DateTime.UtcNow < _bindExpiration)
from.SendMessage(52, "Account-bound for: {0} more days", (_bindExpiration - DateTime.UtcNow).Days);
}
public FollowshipRing(Serial serial) : base(serial) { }
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(1); // version
writer.Write(_boundAccount?.Username ?? string.Empty);
writer.Write(_bindExpiration);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (version >= 1)
{
string accountName = reader.ReadString();
_bindExpiration = reader.ReadDateTime();
if (!string.IsNullOrEmpty(accountName))
_boundAccount = Accounts.Accounts.GetAccount(accountName) as Account;
}
}
private class InternalTimer : Timer
{
private readonly Item _item;
public InternalTimer(Item item) : base(TimeSpan.Zero, TimeSpan.FromSeconds(10))
{
_item = item;
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
if (_item == null || _item.Deleted || !_item.IsChildOfMobile)
return;
Mobile wearer = _item.RootParent as Mobile;
if (wearer != null && wearer.Alive)
{
Effects.SendLocationParticles(
EffectItem.Create(wearer.Location, wearer.Map, TimeSpan.FromSeconds(0.25)),
0x376A, 10, 15, 1358, 0, 5052, 0); // Magenta hue = 1358
wearer.PlaySound(0x5C9);
}
}
}
}
}