Raid bosses?

Name says it all
Post Reply
Drake.PC-LoT
Apprentice Scribe
Posts: 16
Joined: Tue Apr 15, 2025 11:15 am

Raid bosses?

Post by Drake.PC-LoT »

wasn't sure where to put this, since the suggestion zone is locked.

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();
        }
    }
}
figured i'd share something i did a while ago.
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);
                }
            }
        }
    }
}
Post Reply