Thank you always!! It's not urgent, so you can take your time.
Alright I added something to this that should help:
AbilityCooldownTimer and CustomAbilitiesList with the timer added.
There's a few line in CustomAbilitiesList:
Code:
            TimeSpan delay = TimeSpan.FromSeconds(Utility.RandomMinMax(0.5, 4));
                Timer = new AbilityCooldownTimer(this, delay);

You can change the (0.5, 4) to whatever you want the min time and max time of the cooldown between abilities to be.
 

Attachments

  • AbilityCooldownTimer.cs
    613 bytes · Views: 5
  • CustomAbilitiesList.cs
    5.1 KB · Views: 9
Alright I added something to this that should help:
AbilityCooldownTimer and CustomAbilitiesList with the timer added.
There's a few line in CustomAbilitiesList:
Code:
            TimeSpan delay = TimeSpan.FromSeconds(Utility.RandomMinMax(0.5, 4));
                Timer = new AbilityCooldownTimer(this, delay);

You can change the (0.5, 4) to whatever you want the min time and max time of the cooldown between abilities to be.
It works perfectly! Thank you so much from the bottom of my heart!
 
I'm replying to you after a long time. First of all, I just wanted to say Happy New Year to you. Thank you for the file you uploaded. I have a personal problem. For example, after a domesticated monster uses abilities like Walking Bomb, ThrowExplosives, objects like fire or poison pits on the floor will also damage the domesticated monster and its owner who uses this spell. Could you please share your knowledge on how to modify it so that the domesticated monster and its owner who use this ability will not be harmed?
 
I'm replying to you after a long time. First of all, I just wanted to say Happy New Year to you. Thank you for the file you uploaded. I have a personal problem. For example, after a domesticated monster uses abilities like Walking Bomb, ThrowExplosives, objects like fire or poison pits on the floor will also damage the domesticated monster and its owner who uses this spell. Could you please share your knowledge on how to modify it so that the domesticated monster and its owner who use this ability will not be harmed?
Hey again, Bala, I appreciate your comments!

So, each of the abilities you mentioned drop a different item on the ground, so we'll have to edit each of the items rather than the abilities themselves and change it so if the creature is controlled, the items that drop select different targets to damage.
For the abilities that drop the acid pool, like toxic rain:
Go into AcidPool.cs and find this line:
Code:
else if (Active == true  && Owner.Controlled && m is BaseCreature )
simply change it to:
Code:
else if (Active == true  && Owner.Controlled && m is BaseCreature && m != Owner)
this will prevent the acid pool from damaging the tamed creature.

Second, for Walking bomb and Flame Burst, they use the item FlameItem.cs.
Find these lines: (should be around line 160)
Code:
Map map = m_Item.Map;
BaseCreature owner = m_Item.Owner;

then add this:
Code:
            Mobile master = null;
            if (owner.Controlled)
            master = owner.ControlMaster;
then find the code a few lines under it that have the foreach statement:
change everything from the lines "if (owner != null && !owner.Deleted)" to "eable.Free();" to look like this:
Code:
            if (owner != null && !owner.Deleted)
            {
                if (master != null && !master.Deleted)
                {
                    foreach (Mobile m in eable)
                    {
                        if (m != master && m != owner && !owner.IsFriend(m) && (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z )
                        m_Queue.Enqueue(m);
                    }

                }
                else
                {
                    foreach (Mobile m in eable)
                    {
                        if (m != owner && !owner.IsFriend(m) && (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z )
                        m_Queue.Enqueue(m);
                    }
                }
            }
            else
            {
                foreach (Mobile m in eable)
                {
                    if ((m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z )
                    m_Queue.Enqueue(m);
                }
            }

            eable.Free();
This is adding the extra 'if statement' to account for the control master of the caster.
This should make it so pet owners don't get damaged by the flames.

For throw explosives, you'll have to edit FireItem.cs
make sure not to confuse it with FlameItem (which is used in walking bomb and flame burst)

go under the line:
Code:
    private int m_Damage;
add
Code:
    private BaseCreature m_Owner;
    [CommandProperty(AccessLevel.GameMaster)]
    public BaseCreature Owner
    {
        get { return m_Owner; }
        set { m_Owner = value; }
    }


change the OnMoveOver method to look like this:
Code:
    public override bool OnMoveOver(Mobile m)
    {
        if(Owner != null && !Owner.Deleted)
        {
            if (!Owner.Controlled && Active == true && (m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile)))
            {
            int damage = m_Damage;

            if (!Core.AOS && m.CheckSkill(SkillName.MagicResist, 0.0, 30.0))
            {
               damage = 1;
                m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy.
            }

            AOS.Damage(m, damage, 0, 100, 0, 0, 0);
            m.PlaySound(0x22A);
        }
            else if (Active == true  && Owner.Controlled && m is BaseCreature && m != Owner)
            {
            int damage = m_Damage;

            if (!Core.AOS && m.CheckSkill(SkillName.MagicResist, 0.0, 30.0))
            {
               damage = 1;
                m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy.
            }

            AOS.Damage(m, damage, 0, 100, 0, 0, 0);
            m.PlaySound(0x208);
        }
        }
        else if (Active == true )
        {
        int damage = m_Damage/2;

        if (!Core.AOS && m.CheckSkill(SkillName.MagicResist, 0.0, 30.0))
        {
            damage = 1;

            m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy.
        }

        AOS.Damage(m, damage, 0, 100, 0, 0, 0);
        m.PlaySound(0x208);

        }

        return true;
    }
we're giving the fire item an Owner property which will keep track of the creature that casted the ability. if that creature or its master walks over the item, it won't do damage.

Then we go down to the OnTick method of FireItem's Timer, and do teh same thing we did with FlameItem:
Add this under the line "Map map = m_Item.Map;"
Code:
            BaseCreature owner = m_Item.Owner;
            if (owner.Controlled)
            master = owner.ControlMaster;
then, from the lines "IPooledEnumerable eable = m_Item.GetMobilesInRange(0);" to "eable.Free();",
Change the code in between to look like this:
Code:
            IPooledEnumerable eable = m_Item.GetMobilesInRange(0);

            if (owner != null && !owner.Deleted)
            {
                if (master != null && !master.Deleted)
                {
                    foreach (Mobile m in eable)
                    {
                        if (m != master && m != owner && !owner.IsFriend(m) && (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z )
                        m_Queue.Enqueue(m);
                    }

                }
                else
                {
                    foreach (Mobile m in eable)
                    {
                        if (m != owner && !owner.IsFriend(m) && (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z )
                        m_Queue.Enqueue(m);
                    }
                }
            }
            else
            {
                foreach (Mobile m in eable)
                {
                    if ((m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z )
                    m_Queue.Enqueue(m);
                }
            }
            eable.Free();
Then the last tihng,
in ThrowExplosves.cs, under the line " m_Item.Map = defender.Map;"
add:
Code:
m_Item.Owner = creature;

Those changes should make it so that the caster of each of the abilities no longer target itself if it's tamed or target its master
 
Last edited:
Hey again, Bala, I appreciate your comments!

So, each of the abilities you mentioned drop a different item on the ground, so we'll have to edit each of the items rather than the abilities themselves and change it so if the creature is controlled, the items that drop select different targets to damage.
For the abilities that drop the acid pool, like toxic rain:
Go into AcidPool.cs and find this line:
Code:
else if (Active == true  && Owner.Controlled && m is BaseCreature )
simply change it to:
Code:
else if (Active == true  && Owner.Controlled && m is BaseCreature && m != Owner)
this will prevent the acid pool from damaging the tamed creature.

Second, for Walking bomb and Flame Burst, they use the item FlameItem.cs.
Find these lines: (should be around line 160)
Code:
Map map = m_Item.Map;
BaseCreature owner = m_Item.Owner;

then add this:
Code:
            Mobile master = null;
            if (owner.Controlled)
            master = owner.ControlMaster;
then find the code a few lines under it that have the foreach statement:
change everything from the lines "if (owner != null && !owner.Deleted)" to "eable.Free();" to look like this:
Code:
            if (owner != null && !owner.Deleted)
            {
                if (master != null && !master.Deleted)
                {
                    foreach (Mobile m in eable)
                    {
                        if (m != master && m != owner && !owner.IsFriend(m) && (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z )
                        m_Queue.Enqueue(m);
                    }

                }
                else
                {
                    foreach (Mobile m in eable)
                    {
                        if (m != owner && !owner.IsFriend(m) && (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z )
                        m_Queue.Enqueue(m);
                    }
                }
            }
            else
            {
                foreach (Mobile m in eable)
                {
                    if ((m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z )
                    m_Queue.Enqueue(m);
                }
            }

            eable.Free();
This is adding the extra 'if statement' to account for the control master of the caster.
This should make it so pet owners don't get damaged by the flames.

For throw explosives, you'll have to edit FireItem.cs
make sure not to confuse it with FlameItem (which is used in walking bomb and flame burst)

go under the line:
Code:
    private int m_Damage;
add
Code:
    private BaseCreature m_Owner;
    [CommandProperty(AccessLevel.GameMaster)]
    public BaseCreature Owner
    {
        get { return m_Owner; }
        set { m_Owner = value; }
    }


change the OnMoveOver method to look like this:
Code:
    public override bool OnMoveOver(Mobile m)
    {
        if(Owner != null && !Owner.Deleted)
        {
            if (!Owner.Controlled && Active == true && (m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile)))
            {
            int damage = m_Damage;

            if (!Core.AOS && m.CheckSkill(SkillName.MagicResist, 0.0, 30.0))
            {
               damage = 1;
                m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy.
            }

            AOS.Damage(m, damage, 0, 100, 0, 0, 0);
            m.PlaySound(0x22A);
        }
            else if (Active == true  && Owner.Controlled && m is BaseCreature && m != Owner)
            {
            int damage = m_Damage;

            if (!Core.AOS && m.CheckSkill(SkillName.MagicResist, 0.0, 30.0))
            {
               damage = 1;
                m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy.
            }

            AOS.Damage(m, damage, 0, 100, 0, 0, 0);
            m.PlaySound(0x208);
        }
        }
        else if (Active == true )
        {
        int damage = m_Damage/2;

        if (!Core.AOS && m.CheckSkill(SkillName.MagicResist, 0.0, 30.0))
        {
            damage = 1;

            m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy.
        }

        AOS.Damage(m, damage, 0, 100, 0, 0, 0);
        m.PlaySound(0x208);

        }

        return true;
    }
we're giving the fire item an Owner property which will keep track of the creature that casted the ability. if that creature or its master walks over the item, it won't do damage.

Then we go down to the OnTick method of FireItem's Timer, and do teh same thing we did with FlameItem:
Add this under the line "Map map = m_Item.Map;"
Code:
            BaseCreature owner = m_Item.Owner;
            if (owner.Controlled)
            master = owner.ControlMaster;
then, from the lines "IPooledEnumerable eable = m_Item.GetMobilesInRange(0);" to "eable.Free();",
Change the code in between to look like this:
Code:
            IPooledEnumerable eable = m_Item.GetMobilesInRange(0);

            if (owner != null && !owner.Deleted)
            {
                if (master != null && !master.Deleted)
                {
                    foreach (Mobile m in eable)
                    {
                        if (m != master && m != owner && !owner.IsFriend(m) && (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z )
                        m_Queue.Enqueue(m);
                    }

                }
                else
                {
                    foreach (Mobile m in eable)
                    {
                        if (m != owner && !owner.IsFriend(m) && (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z )
                        m_Queue.Enqueue(m);
                    }
                }
            }
            else
            {
                foreach (Mobile m in eable)
                {
                    if ((m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z )
                    m_Queue.Enqueue(m);
                }
            }
            eable.Free();
Then the last tihng,
in ThrowExplosves.cs, under the line " m_Item.Map = defender.Map;"
add:
Code:
m_Item.Owner = creature;

Those changes should make it so that the caster of each of the abilities no longer target itself if it's tamed or target its master
+ Custrom/CustomAbilities-3.0/Custom Abilities/Items/FireItem.cs:
CS0103: Line 154: The name 'master' does not exist in the current context
CS0103: Line 162: The name 'master' does not exist in the current context
CS0103: Line 162: The name 'master' does not exist in the current context
CS0103: Line 166: The name 'master' does not exist in the current context
Scripts: One or more scripts failed to compile or no script files were found.

Thank you for always being nice! However, when I compile, I get the following error. Could you please help me a little bit more on how to fix the master error?
 
Thank you for always being nice! However, when I compile, I get the following error. Could you please help me a little bit more on how to fix the master error?
looks like FireItem.cs is missing this piece:
Code:
            BaseCreature owner = m_Item.Owner;
            Mobile master = null;
            if (owner.Controlled)
            master = owner.ControlMaster;
Looks like 'master' hasn't been declared in FireItem.cs.
I think I forgot to write the one line "Mobile master = null;" when describing the changes.
that line should fix everything.
 
looks like FireItem.cs is missing this piece:
Code:
            BaseCreature owner = m_Item.Owner;
            Mobile master = null;
            if (owner.Controlled)
            master = owner.ControlMaster;
Looks like 'master' hasn't been declared in FireItem.cs.
I think I forgot to write the one line "Mobile master = null;" when describing the changes.
that line should fix everything.
I've solved the problem perfectly. Thank you! And I'm so sorry. I just want to ask for one more help. While studying about the server, I happened to see a video of a server called Outland. Like the gif photo I posted, fire elemental monsters try their magic and then fireball in large numbers where they are designated. And there is a spark where it is launched and all the monsters within that range do the damage of the number of fireballs. I wanted to change it by applying the BarrageOfBolts magic from the ability you raised, but I think it's an area that I can't reach. Can you please share your knowledge of what modifications to go through to create a magic similar to the picture?gifit_1705148606928.gif
 
I've solved the problem perfectly. Thank you! And I'm so sorry. I just want to ask for one more help. While studying about the server, I happened to see a video of a server called Outland. Like the gif photo I posted, fire elemental monsters try their magic and then fireball in large numbers where they are designated. And there is a spark where it is launched and all the monsters within that range do the damage of the number of fireballs. I wanted to change it by applying the BarrageOfBolts magic from the ability you raised, but I think it's an area that I can't reach. Can you please share your knowledge of what modifications to go through to create a magic similar to the picture?View attachment 22859
Yeah, Outlands is great! They've done amazing work with UO.

Here's an ability that looks similar to the fireball attack in this gif.
I made it a different ability because it would be much easier than editing the existing code I have for Barrage of Bolts.
Code:
using System;
using Server;using System.Collections.Generic;
using System.Linq;
using Server.Items;
using Server.Network;
using System.Collections;
using Server.Spells;

namespace Server.Mobiles
{
    public class VolleyOfBolts : CustomAbility
    {

    public override int MaxRange{ get { return 12; } }
    public override double TriggerChance { get { return 1.0; } }
    public override TimeSpan CooldownDuration { get { return TimeSpan.FromSeconds(15); } }

    private static Hashtable Table = new Hashtable();


    private int m_ItemID;
    private int m_Hue;
    private int m_SoundID;
    private int m_Min;
    private int m_Max;


    public int ItemID
    {
        get { return m_ItemID; }
        set { m_ItemID = value; }
    }

    public int Hue
    {
        get { return m_Hue; }
        set { m_Hue = value; }
    }

    public int Sound
    {
        get { return m_SoundID; }
        set { m_SoundID = value; }
    }   

    public VolleyOfBolts()
    {
        m_ItemID = 0x36D4;
        m_Hue = 0;
        m_SoundID = 0x349;

        m_Min = 12;
        m_Max = 18;
    }

    public void SetDamage(int min, int max)
    {
        m_Min = min;
        m_Max = max;
    }

    public override void Trigger(BaseCreature creature, Mobile defender, int min, int max)
    {

        if(min == 0 && max == 0)
        {
            min = m_Min;
            max = m_Max;
        }

        if(creature.InRange(defender.Location, MaxRange) && TriggerChance >= Utility.RandomDouble() && !IsInCooldown(creature))
        {
            DoEffects(creature, defender, min, max);
            AddToCooldown(creature);
        }
    }

    public override void DoEffects(BaseCreature creature, Mobile defender, int min, int max)
    {
        if (defender == null || defender.Deleted || !defender.Alive || !creature.Alive || !creature.CanBeHarmful(defender))
        return;

        if( creature.Body == 0x191 || creature.Body == 0x190)
        creature.Animate(AnimationType.Spell, 0);

        Timer t = new BoltTimer(creature, defender, this, min, max);
        t.Start();
        Table[defender] = t;
    }

    public void DoVolley(BaseCreature creature, Point3D p, int min, int max)
    {

        Point3D random = new Point3D(p.X + Utility.RandomMinMax(-1, 1), p.Y + Utility.RandomMinMax(-1, 1), p.Z);
        TargetLocationItem r_Item = new TargetLocationItem();
        r_Item.MoveToWorld(random, creature.Map);

            //Effects.PlaySound(p.Location, p.Map, m_SoundID);
        Effects.PlaySound(creature.Location, creature.Map, m_SoundID);
            creature.MovingEffect(r_Item, m_ItemID, 1, 0, false, false, m_Hue, 0);

            IPooledEnumerable eable = r_Item.GetMobilesInRange(1);
            foreach (Mobile m in eable)
            {
            Timer.DelayCall(TimeSpan.FromSeconds(creature.GetDistanceToSqrt(r_Item) / 5.0), () =>
            {
            if (creature.Controlled && m is BaseCreature && !((BaseCreature)m).Controlled)
            {
           
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, d, 100, 0, 0, 0, 0);
            }
            else if (!creature.Controlled && ((m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile))))
            {
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, d, 100, 0, 0, 0, 0);
            }
            });
            }
            eable.Free();
    }

        public static void EndEffect(Mobile m, bool message)
        {
            Timer t = (Timer)Table[m];

        if (t != null)
        {
        t.Stop();
        Table.Remove(m);
        }
        }

    public override void Serialize(GenericWriter writer)
    {
        writer.Write(m_Min);
        writer.Write(m_Max);
    }
    public override void Deserialize(GenericReader reader)
    {
        m_Min = reader.ReadInt();
        m_Max = reader.ReadInt();
    }

    private class BoltTimer : Timer
    {
        private BaseCreature Creature;
        private Mobile Defender;
        private VolleyOfBolts Ability;
        private int Min;
        private int Max;
        private DateTime NextBolt;
        private DateTime Expire;   

        public BoltTimer(BaseCreature creature, Mobile defender, VolleyOfBolts vob, int min, int max)
        : base(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.1))
        {
        Creature = creature;
        Defender = defender;
        Ability = vob;
        Min = min;
        Max = max;

                Priority = TimerPriority.TwoFiftyMS;
        creature.Frozen = true;

                Expire = DateTime.UtcNow + TimeSpan.FromSeconds(3);
                NextBolt = DateTime.UtcNow + TimeSpan.FromSeconds(0.5);
        }

        protected override void OnTick()
        {
                if (!Defender.Alive || Defender.Deleted)
                {
                    EndEffect(Defender, true);
                }
                else if (DateTime.UtcNow < NextBolt)
        {
            return;
        }
                else if (DateTime.UtcNow >= NextBolt)
        {
            Ability.DoVolley(Creature, Defender.Location, Min, Max);
        }
       
        if (DateTime.UtcNow >= Expire)
        {
            Creature.Frozen = false;
                    EndEffect(Defender, true);
        }
        }
    }
    }
}
Just copy that and save it as VolleyOfBolts.cs in your folder and then update CustomAbility.cs to include this ability in the places that list all of the abilities:
chance the number of abilities to this:
Code:
                _Abilities = new CustomAbility[31];

Then under this line:
Code:
        _Abilities[29] = new Snare();
Add this:
Code:
        _Abilities[30] = new VolleyOfBolts();
Then under this:
Code:
        public static CustomAbility Snare
            {
                get
                {
                    return _Abilities[29];
                }
            }
add this:
Code:
        public static CustomAbility VolleyOfBolts
            {
                get
                {
                    return _Abilities[30];
                }
            }
 
Yeah, Outlands is great! They've done amazing work with UO.

Here's an ability that looks similar to the fireball attack in this gif.
I made it a different ability because it would be much easier than editing the existing code I have for Barrage of Bolts.
Code:
using System;
using Server;using System.Collections.Generic;
using System.Linq;
using Server.Items;
using Server.Network;
using System.Collections;
using Server.Spells;

namespace Server.Mobiles
{
    public class VolleyOfBolts : CustomAbility
    {

    public override int MaxRange{ get { return 12; } }
    public override double TriggerChance { get { return 1.0; } }
    public override TimeSpan CooldownDuration { get { return TimeSpan.FromSeconds(15); } }

    private static Hashtable Table = new Hashtable();


    private int m_ItemID;
    private int m_Hue;
    private int m_SoundID;
    private int m_Min;
    private int m_Max;


    public int ItemID
    {
        get { return m_ItemID; }
        set { m_ItemID = value; }
    }

    public int Hue
    {
        get { return m_Hue; }
        set { m_Hue = value; }
    }

    public int Sound
    {
        get { return m_SoundID; }
        set { m_SoundID = value; }
    } 

    public VolleyOfBolts()
    {
        m_ItemID = 0x36D4;
        m_Hue = 0;
        m_SoundID = 0x349;

        m_Min = 12;
        m_Max = 18;
    }

    public void SetDamage(int min, int max)
    {
        m_Min = min;
        m_Max = max;
    }

    public override void Trigger(BaseCreature creature, Mobile defender, int min, int max)
    {

        if(min == 0 && max == 0)
        {
            min = m_Min;
            max = m_Max;
        }

        if(creature.InRange(defender.Location, MaxRange) && TriggerChance >= Utility.RandomDouble() && !IsInCooldown(creature))
        {
            DoEffects(creature, defender, min, max);
            AddToCooldown(creature);
        }
    }

    public override void DoEffects(BaseCreature creature, Mobile defender, int min, int max)
    {
        if (defender == null || defender.Deleted || !defender.Alive || !creature.Alive || !creature.CanBeHarmful(defender))
        return;

        if( creature.Body == 0x191 || creature.Body == 0x190)
        creature.Animate(AnimationType.Spell, 0);

        Timer t = new BoltTimer(creature, defender, this, min, max);
        t.Start();
        Table[defender] = t;
    }

    public void DoVolley(BaseCreature creature, Point3D p, int min, int max)
    {

        Point3D random = new Point3D(p.X + Utility.RandomMinMax(-1, 1), p.Y + Utility.RandomMinMax(-1, 1), p.Z);
        TargetLocationItem r_Item = new TargetLocationItem();
        r_Item.MoveToWorld(random, creature.Map);

            //Effects.PlaySound(p.Location, p.Map, m_SoundID);
        Effects.PlaySound(creature.Location, creature.Map, m_SoundID);
            creature.MovingEffect(r_Item, m_ItemID, 1, 0, false, false, m_Hue, 0);

            IPooledEnumerable eable = r_Item.GetMobilesInRange(1);
            foreach (Mobile m in eable)
            {
            Timer.DelayCall(TimeSpan.FromSeconds(creature.GetDistanceToSqrt(r_Item) / 5.0), () =>
            {
            if (creature.Controlled && m is BaseCreature && !((BaseCreature)m).Controlled)
            {
         
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, d, 100, 0, 0, 0, 0);
            }
            else if (!creature.Controlled && ((m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile))))
            {
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, d, 100, 0, 0, 0, 0);
            }
            });
            }
            eable.Free();
    }

        public static void EndEffect(Mobile m, bool message)
        {
            Timer t = (Timer)Table[m];

        if (t != null)
        {
        t.Stop();
        Table.Remove(m);
        }
        }

    public override void Serialize(GenericWriter writer)
    {
        writer.Write(m_Min);
        writer.Write(m_Max);
    }
    public override void Deserialize(GenericReader reader)
    {
        m_Min = reader.ReadInt();
        m_Max = reader.ReadInt();
    }

    private class BoltTimer : Timer
    {
        private BaseCreature Creature;
        private Mobile Defender;
        private VolleyOfBolts Ability;
        private int Min;
        private int Max;
        private DateTime NextBolt;
        private DateTime Expire; 

        public BoltTimer(BaseCreature creature, Mobile defender, VolleyOfBolts vob, int min, int max)
        : base(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.1))
        {
        Creature = creature;
        Defender = defender;
        Ability = vob;
        Min = min;
        Max = max;

                Priority = TimerPriority.TwoFiftyMS;
        creature.Frozen = true;

                Expire = DateTime.UtcNow + TimeSpan.FromSeconds(3);
                NextBolt = DateTime.UtcNow + TimeSpan.FromSeconds(0.5);
        }

        protected override void OnTick()
        {
                if (!Defender.Alive || Defender.Deleted)
                {
                    EndEffect(Defender, true);
                }
                else if (DateTime.UtcNow < NextBolt)
        {
            return;
        }
                else if (DateTime.UtcNow >= NextBolt)
        {
            Ability.DoVolley(Creature, Defender.Location, Min, Max);
        }
     
        if (DateTime.UtcNow >= Expire)
        {
            Creature.Frozen = false;
                    EndEffect(Defender, true);
        }
        }
    }
    }
}
Just copy that and save it as VolleyOfBolts.cs in your folder and then update CustomAbility.cs to include this ability in the places that list all of the abilities:
chance the number of abilities to this:
Code:
                _Abilities = new CustomAbility[31];

Then under this line:
Code:
        _Abilities[29] = new Snare();
Add this:
Code:
        _Abilities[30] = new VolleyOfBolts();
Then under this:
Code:
        public static CustomAbility Snare
            {
                get
                {
                    return _Abilities[29];
                }
            }
add this:
Code:
        public static CustomAbility VolleyOfBolts
            {
                get
                {
                    return _Abilities[30];
                }
            }
Outland is great, but to me, you're an even greater person. It works perfectly and it's the best! While using these abilities, I got a question. Can I find out why when a tame monster uses these abilities, such as a newly created magic and acidpool item, it doesn't show damage when attacking an opponent? Damage is applied without a problem, but no attack damage is shown.
And when I suffer damage from ImpaleAoe's ability and bleed, I only get a message of abnormal condition and it seems that the damage doesn't come in continuously. If you don't mind, can I ask you to check it?
 
Last edited:
Outland is great, but to me, you're an even greater person. It works perfectly and it's the best! While using these abilities, I got a question. Can I find out why when a tame monster uses these abilities, such as a newly created magic and acidpool item, it doesn't show damage when attacking an opponent? Damage is applied without a problem, but no attack damage is shown.
And when I suffer damage from ImpaleAoe's ability and bleed, I only get a message of abnormal condition and it seems that the damage doesn't come in continuously. If you don't mind, can I ask you to check it?
Well, I've got another problem as I keep experimenting. When the tame monster uses the VolleyOfBolts ability, there is no damage in the player-to-player battle. I'm sorry for asking too much..
 
Outland is great, but to me, you're an even greater person. It works perfectly and it's the best! While using these abilities, I got a question. Can I find out why when a tame monster uses these abilities, such as a newly created magic and acidpool item, it doesn't show damage when attacking an opponent? Damage is applied without a problem, but no attack damage is shown.
And when I suffer damage from ImpaleAoe's ability and bleed, I only get a message of abnormal condition and it seems that the damage doesn't come in continuously. If you don't mind, can I ask you to check it?
Thank you! And yes I think I can help you with that.
To make the damage visible to you when your tamed creature uses those abilities, you'll have to look at the items themselves again (FireItem, FlameItem, and AcidPoolItem )
in the statements that describe if the Owner is controlled, change the "AOS.Damage" section to look something like this:
Code:
AOS.Damage(m, m_Owner, damage, 0, 100, 0, 0, 0);

or , for AcidPoolItem:
Code:
AOS.Damage(m, m_Owner, damage, 0, 0, 0, 100, 0);
For the parts outside of the owner clause, keep them the same.
Like that, it shows that the damage is coming from the teamed animal, and not just the item.
Well, I've got another problem as I keep experimenting. When the tame monster uses the VolleyOfBolts ability, there is no damage in the player-to-player battle. I'm sorry for asking too much..
sure!
find this section is VolleyOfBolts:
Code:
            if (creature.Controlled && m is BaseCreature && !((BaseCreature)m).Controlled)
            {
            
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, d, 100, 0, 0, 0, 0);
            }

change it to something like this:
Code:
            if (creature.Controlled && (m is BaseCreature && !((BaseCreature)m).Controlled) || m is PlayerMobile && m != ((BaseCreature)m).ControlMaster )
            {
            
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, d, 100, 0, 0, 0, 0);
            }

I coded it quickly, so I just made it so that if the creature is tamed, it won't work on players. that extra 'Or' section should cover it though. it's just saying "or, if the target 'm', is a PlayerMobile, make sure it's not the caster's Control Master."
 
Thank you! And yes I think I can help you with that.
To make the damage visible to you when your tamed creature uses those abilities, you'll have to look at the items themselves again (FireItem, FlameItem, and AcidPoolItem )
in the statements that describe if the Owner is controlled, change the "AOS.Damage" section to look something like this:
Code:
AOS.Damage(m, m_Owner, damage, 0, 100, 0, 0, 0);

or , for AcidPoolItem:
Code:
AOS.Damage(m, m_Owner, damage, 0, 0, 0, 100, 0);
For the parts outside of the owner clause, keep them the same.
Like that, it shows that the damage is coming from the teamed animal, and not just the item.

sure!
find this section is VolleyOfBolts:
Code:
            if (creature.Controlled && m is BaseCreature && !((BaseCreature)m).Controlled)
            {
          
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, d, 100, 0, 0, 0, 0);
            }

change it to something like this:
Code:
            if (creature.Controlled && (m is BaseCreature && !((BaseCreature)m).Controlled) || m is PlayerMobile && m != ((BaseCreature)m).ControlMaster )
            {
          
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, d, 100, 0, 0, 0, 0);
            }

I coded it quickly, so I just made it so that if the creature is tamed, it won't work on players. that extra 'Or' section should cover it though. it's just saying "or, if the target 'm', is a PlayerMobile, make sure it's not the caster's Control Master."
I really appreciate your help, but I get the following and above errors.
+ Custrom/CustomAbilities-3.0/Custom Abilities/Items/AcidPoolItem.cs:
CS0120: Line 216: An object reference is required for the non-static field, method, or property 'AcidPoolItem.m_Owner'
+ Custrom/CustomAbilities-3.0/Custom Abilities/Items/FireItem.cs:
CS0120: Line 199: An object reference is required for the non-static field, method, or property 'FireItem.m_Owner'
+ Custrom/CustomAbilities-3.0/Custom Abilities/Items/FlameItem.cs:
CS0120: Line 202: An object reference is required for the non-static field, method, or property 'FlameItem.m_Owner'
Scripts: One or more scripts failed to compile or no script files were found.
And the server will reboot when the monster attempts to place an order for the ValleyOfBolts to another player or yourself. Below is the crash log.
Mobiles: 77
Items: 2903
Exception:
System.InvalidCastException: Cannot cast an object of type 'Server.Mobiles.PlayerMobile' in type 'Server.Mobiles.BaseCreature'.
Location: Server.Mobiles.VolleyOfBolts.<>c__DisplayClass25_1.<DoVolley>b__0()
Location: Server.Timer.DelayCallTimer.OnTick()
Location: Server.Timer.Slice()
Location: Server.Core.Main(String[] args)
And can you please share the knowledge of what I need to add to show damage even when tame monsters use ValleyOfBolts orders?
 
Last edited:
I really appreciate your help, but I get the following and above errors.

And the server will reboot when the monster attempts to place an order for the ValleyOfBolts to another player or yourself. Below is the crash log.

And can you please share the knowledge of what I need to add to show damage even when tame monsters use ValleyOfBolts orders?
Alright, I think I got the fixes for both of your issues.
The fist one, with the object reference in FireItem, FlameItem and AdicPoolItem:
Are those lines mentioned in the error report in the OnTick() method of the Timer?
Your version of those items seem to be slightly different from mine, but the OnTick method seems to be in the same general area as the liens that are causing you problems.

If that's the case, you should be able to look a few lines up and see this line:
Code:
BaseCreature owner = m_Item.Owner;
Your object reference is the 'm_Item.Owner'
If that line is with in the same scope, make the damage line look like this:
Code:
AOS.Damage(m, owner, damage, 0, 100, 0, 0, 0);

And for the volleyofBolts:

I mssed up this one reference in this line of code.
This is what the "if creature.Controlled" statement should look like:
Code:
         if (creature.Controlled && (m is BaseCreature && !((BaseCreature)m).Controlled) || m is PlayerMobile && m != ((BaseCreature)creature).ControlMaster)
I wrote ((BaseCreature)m).ControlMaster, and it's supposed to be "((BaseCreature)creature).ControlMaster)". That was the issue.
That's what happens when I don't proof read my work lol

in VolleyOfBolts, the damage line should look like this then:
Code:
AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
Adding that will make the damage come from the pet that's casting the ability. Then it'll show up on your end as your pet doing the damage.
Cheers!
 
Alright, I think I got the fixes for both of your issues.
The fist one, with the object reference in FireItem, FlameItem and AdicPoolItem:
Are those lines mentioned in the error report in the OnTick() method of the Timer?
Your version of those items seem to be slightly different from mine, but the OnTick method seems to be in the same general area as the liens that are causing you problems.

If that's the case, you should be able to look a few lines up and see this line:
Code:
BaseCreature owner = m_Item.Owner;
Your object reference is the 'm_Item.Owner'
If that line is with in the same scope, make the damage line look like this:
Code:
AOS.Damage(m, owner, damage, 0, 100, 0, 0, 0);

And for the volleyofBolts:

I mssed up this one reference in this line of code.
This is what the "if creature.Controlled" statement should look like:
Code:
         if (creature.Controlled && (m is BaseCreature && !((BaseCreature)m).Controlled) || m is PlayerMobile && m != ((BaseCreature)creature).ControlMaster)
I wrote ((BaseCreature)m).ControlMaster, and it's supposed to be "((BaseCreature)creature).ControlMaster)". That was the issue.
That's what happens when I don't proof read my work lol

in VolleyOfBolts, the damage line should look like this then:
Code:
AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
Adding that will make the damage come from the pet that's casting the ability. Then it'll show up on your end as your pet doing the damage.
Cheers!

public static void DoRain(Mobile m, Mobile from, int damage)
{
if (m.Alive && !m.IsDeadBondedPet)
{

if (!m.Player)
damage *= 2;

//rain effect
//Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x9F89, 10, 30, hue, 0, 5052, 0);

//dmg
//m.PlaySound(0x11F); //original sound
m.PlaySound(0x011);
m.FixedParticles(0x9F89, 10, 30, 5030, 64, 0, EffectLayer.Waist);
AOS.Damage(m, from, damage, false, 0, 0, 0, 0, 0, 0, 100, false, false, false);



//acid pool on ground
AcidPoolItem acid = new AcidPoolItem();
acid.MoveToWorld(m.Location, m.Map);
if (from is BaseCreature)
{
BaseCreature bc = from as BaseCreature;
acid.Owner = bc;
}

}
else
{
EndRain(m, true);
}
}
public static void DoBleed(Mobile m, Mobile from, int damage)
{
if (m.Alive && !m.IsDeadBondedPet)
{
if (!m.Player)
damage *= 2;

m.PlaySound(0x133);
AOS.Damage(m, from, damage, false, 0, 0, 0, 0, 0, 0, 100, false, false, false);

Blood blood = new Blood();
blood.ItemID = Utility.Random(0x122A, 5);
blood.MoveToWorld(m.Location, m.Map);
}
else
{
EndBleed(m, false);
}
}
Cheers!! It works perfectly! It may be boring to say the same thing all the time, but you are really the best and awesome. I have some free time, so I did a little more testing and found a few more problems. Sorry to bother you.. When a tame monster attempts a ToxicRain and ImpaleAoe order, the tame monster gets damaged together when the script part above is working. And ImpaleAoe with this ability, it seems that the bleeding disorder is not working properly. Thank you for always taking your time to me..
 
Cheers!! It works perfectly! It may be boring to say the same thing all the time, but you are really the best and awesome. I have some free time, so I did a little more testing and found a few more problems. Sorry to bother you.. When a tame monster attempts a ToxicRain and ImpaleAoe order, the tame monster gets damaged together when the script part above is working. And ImpaleAoe with this ability, it seems that the bleeding disorder is not working properly. Thank you for always taking your time to me..
Animation.gif
gifit_1705407550918.gif

I'm sorry.. I'm very sorry, but.. I once again made an additional request. If a monster uses the VolleyOfBolts order as shown in the picture, the fireball follows even if it runs away. What I'm hoping is that when a monster uses the VolleyOfBolts ability, it will select a target and have the Firebolt effect and damage sequentially in the 6x6 space. Like in the second image, it selects a target and a range attack unfolds around the target. I think it's similar to the "FlameStrikeAoe" ability among the abilities. It's a way to test the FlameStrikeAoe ability on the opponent, not on yourself, and the fireball is randomly fired around the target. To make it a little easier, firebolt fires into the 6x6 space, but firebolt fires into the 6x6 space even if the target specified there leaves the space. I'm translating, so my explanation may seem very difficult and stupid. And the VolleyOfBolts magic you created is the best magic. But it's my big mistake for not explaining the ability I want properly. If I explained it properly from the beginning, I wouldn't have made you uncomfortable, but I'm really sorry..
 
View attachment 22922
View attachment 22926

I'm sorry.. I'm very sorry, but.. I once again made an additional request. If a monster uses the VolleyOfBolts order as shown in the picture, the fireball follows even if it runs away. What I'm hoping is that when a monster uses the VolleyOfBolts ability, it will select a target and have the Firebolt effect and damage sequentially in the 6x6 space. Like in the second image, it selects a target and a range attack unfolds around the target. I think it's similar to the "FlameStrikeAoe" ability among the abilities. It's a way to test the FlameStrikeAoe ability on the opponent, not on yourself, and the fireball is randomly fired around the target. To make it a little easier, firebolt fires into the 6x6 space, but firebolt fires into the 6x6 space even if the target specified there leaves the space. I'm translating, so my explanation may seem very difficult and stupid. And the VolleyOfBolts magic you created is the best magic. But it's my big mistake for not explaining the ability I want properly. If I explained it properly from the beginning, I wouldn't have made you uncomfortable, but I'm really sorry..
I'm gonna look into toxic rain and impale aoe later today or tomorrow, but for the valley of bolts ability, you want the fireballs to remain in the starting area instead of following the target around, right?
That shouldn't be too hard to change. I'll see what I can do.
 
I'm gonna look into toxic rain and impale aoe later today or tomorrow, but for the valley of bolts ability, you want the fireballs to remain in the starting area instead of following the target around, right?
That shouldn't be too hard to change. I'll see what I can do.
It doesn't matter if it takes a long time. I can wait with appreciation, no matter how long it takes. The VolleyOfBolts ability I wanted allows monsters to demonstrate the VolleyOfBolts ability and fly extensive fireballs in the location where the target stood. Even if the target suddenly disappears while using the ability, the fireball still spills out in the location you set once. If you think that the MeteorShower ability is attacking by pouring fireballs into a range similar to the picture above, I think you'll probably get a similar result. I'm sorry for not being able to convey my thoughts in detail because of the limitations of the translation. And I'm always making up the server feeling grateful to you. Thank you so much from the bottom of my heart.
 
It doesn't matter if it takes a long time. I can wait with appreciation, no matter how long it takes. The VolleyOfBolts ability I wanted allows monsters to demonstrate the VolleyOfBolts ability and fly extensive fireballs in the location where the target stood. Even if the target suddenly disappears while using the ability, the fireball still spills out in the location you set once. If you think that the MeteorShower ability is attacking by pouring fireballs into a range similar to the picture above, I think you'll probably get a similar result. I'm sorry for not being able to convey my thoughts in detail because of the limitations of the translation. And I'm always making up the server feeling grateful to you. Thank you so much from the bottom of my heart.
Okay, so for the volley of bolts ability, you just have to add a few changes to the Timer.
look for this line:
Code:
    private class BoltTimer : Timer
Under that you'll see a number of private variables like "private BaseCreature Creature"
At the bottom of that group, add this one:
Code:
        private Point3D Loc;
Then in the constructor of the Timer, where it says things like:
Code:
        Creature = creature;
        Defender = defender;
        Ability = vob;
        Min = min;
        Max = max;
Add this line under it:
Code:
        Loc = defender.Location;
Then go down to this line:
Code:
            Ability.DoVolley(Creature, Defender.Location, Min, Max);
And change it to look like this:
Code:
            Ability.DoVolley(Creature, Loc, Min, Max);
That changes the functionality so that the Location doesn't update with each fireball shot.

You may also want to change this line too:
Code:
Timer.DelayCall(TimeSpan.FromSeconds(creature.GetDistanceToSqrt(r_Item) / 5.0),
make it divided by a larger number so that the time delay is shorter. (maybe / 10.0 or something).

edit:
I took a quick look at the code for impale and toxic rain that you posted. I assume the creature is being damaged by the main attack and not just the item left on the ground?
if that is what is happening, change this line:
Code:
if (m.Alive && !m.IsDeadBondedPet)
include this:
Code:
if (m.Alive && !m.IsDeadBondedPet && (m != from))
That should eliminate the casting creature from the pool of potentially affected creatures
 
Last edited:
Okay, so for the volley of bolts ability, you just have to add a few changes to the Timer.
look for this line:
Code:
    private class BoltTimer : Timer
Under that you'll see a number of private variable like "private BaseCreature Creature"
At the bottom of that group, add this one:
Code:
        private Point3D Loc;
Then in the constructor of the Timer, where it says things like:
Code:
        Creature = creature;
        Defender = defender;
        Ability = vob;
        Min = min;
        Max = max;
Add this line under it:
Code:
        Loc = defender.Location;
Then go down to this line:
Code:
            Ability.DoVolley(Creature, Defender.Location, Min, Max);
And change it to look like this:
Code:
            Ability.DoVolley(Creature, Loc, Min, Max);
That changes the functionality so that the Location doesn't update with each fireball shot.

You may also want to change this line too:
Code:
Timer.DelayCall(TimeSpan.FromSeconds(creature.GetDistanceToSqrt(r_Item) / 5.0),
make it divided by a larger number so that the time delay is shorter. (maybe / 10.0 or something).
I just finished testing. It works exactly as I wanted it to. Thank you so much for helping me with the incredible knowledge and abilities you have. I know it's boring because I'm saying it every time, but I just want to say it again. To me, you are truly respectful and the most wonderful person.
 
I just finished testing. It works exactly as I wanted it to. Thank you so much for helping me with the incredible knowledge and abilities you have. I know it's boring because I'm saying it every time, but I just want to say it again. To me, you are truly respectful and the most wonderful person.

I made a few edits to ImpaleAoe, and it looks like it's working properly now.
tamed creatures seem to damage the right target and don't target themselves.
Here it the new code, just copy and paste it:
Code:
using System;
using Server;using System.Collections.Generic;
using System.Linq;
using Server.Items;
using Server.Network;
using System.Collections;
using Server.Spells;

namespace Server.Mobiles
{
    public class ImpaleAoe : CustomAbility
    {
        public override double TriggerChance { get { return 0.2; } }
            public override int MaxRange { get { return 5; } }
            public override TimeSpan CooldownDuration { get { return TimeSpan.FromSeconds(25); } }

            private static readonly Dictionary<Mobile, BleedTimer> m_BleedTable = new Dictionary<Mobile, BleedTimer>();

        public static bool IsBleeding(Mobile m)
            {
                return m_BleedTable.ContainsKey(m);
            }

        private int m_ItemID;
        private int m_Hue;

        private int m_Min;
        private int m_Max;

        public int ItemID
        {
        get { return m_ItemID; }
        set { m_ItemID = value; }
        }

        public int Hue
        {
        get { return m_Hue; }
        set { m_Hue = value; }
        }

        public ImpaleAoe()
        {
        m_ItemID = Utility.RandomList(0x8E0, 0x8E7, 0x8E1);
        m_Hue = 0;

        m_Min = 11;
        m_Max = 29;
        }

        public void SetDamage(int min, int max)
        {
        m_Min = min;
        m_Max = max;
        }

        public int GetDamage()
        {
        return Utility.RandomMinMax(m_Min, m_Max);
        }

        public override void Trigger(BaseCreature creature, Mobile defender, int min, int max)
        {

        if(min == 0 && max == 0)
        {
            min = m_Min;
            max = m_Max;
        }

        if(creature.InRange(defender.Location, MaxRange) && TriggerChance >= Utility.RandomDouble() && !IsInCooldown(creature))
        {
            DoEffects(creature, defender, min, max);
                    AddToCooldown(creature);
        }
        }

        public override void DoEffects(BaseCreature creature, Mobile defender, int min, int max)
        {   
        if( creature.Body == 0x191 || creature.Body == 0x190)
            creature.Animate(AnimationType.Spell, 0);
        else
            creature.Animate(AnimationType.Attack, 0);

        if (!creature.Alive || creature.Map == null)
            return;

            BeginBleed(defender, creature, this);

        }

        public static void BeginBleed(Mobile defender, Mobile creature, ImpaleAoe ability)
        {
        BeginBleed(defender, creature, ability, false);
        }

        public static void BeginBleed(Mobile defender, Mobile creature, ImpaleAoe ability, bool splintering)
        {
                BleedTimer timer = null;

        Effects.PlaySound(defender.Location, defender.Map, 0x21D);
        BaseCreature bc = creature as BaseCreature;

                IPooledEnumerable eable = creature.GetMobilesInRange(ability.MaxRange);

                foreach (Mobile m in eable)
                {
                    if (!bc.Controlled && (m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile)) && creature.CanBeHarmful(m)
            || bc.Controlled && (m is BaseCreature && !((BaseCreature)m).Controlled))
            {

                        if (m_BleedTable.ContainsKey(m))
                        {
                if (splintering)
                {
                    timer = m_BleedTable[m];
                    timer.Stop();
                }
                else
                {
                    return;
                }
                        }

                Effects.SendLocationEffect(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), m.Map, ability.ItemID, 150, 10, ability.Hue, 0); //0xAA8 is ice

                            Timer.DelayCall(TimeSpan.FromSeconds(0.75), () =>
                {
                    int d = ability.GetDamage();
                            AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);

                            timer = new BleedTimer(creature, m);
                            m_BleedTable[m] = timer;
                            timer.Start();

                            m.SendLocalizedMessage(1060160); // You are bleeding!

                            if (m is PlayerMobile)
                            {
                        m.LocalOverheadMessage(MessageType.Regular, 0x21, 1060757); // You are bleeding profusely
                                  m.NonlocalOverheadMessage(MessageType.Regular, 0x21, 1060758, m.Name); // ~1_NAME~ is bleeding profusely   
                            }
                            m.FixedParticles(0x377A, 244, 25, 9950, 31, 0, EffectLayer.Waist);
                    });
            }
                }

                eable.Free();
        }


            public static void DoBleed(Mobile m, Mobile from, int damage)
            {
                if (m.Alive && !m.IsDeadBondedPet && m != from)
                {
                    if (!m.Player)
                        damage *= 2;

                    m.PlaySound(0x133);
                    AOS.Damage(m, from, damage, false, 0, 0, 0, 0, 0, 0, 100, false, false, false);

                    Blood blood = new Blood();
                    blood.ItemID = Utility.Random(0x122A, 5);
                    blood.MoveToWorld(m.Location, m.Map);
                }
                else
                {
            EndBleed(m, false);
                }
            }

            public static void EndBleed(Mobile m, bool message)
            {
                Timer t = null;

                if (m_BleedTable.ContainsKey(m))
                {
            t = m_BleedTable[m];
                    m_BleedTable.Remove(m);
                }

                if (t == null)
                    return;

                t.Stop();

                if (message)
            m.SendLocalizedMessage(1060167); // The bleeding wounds have healed, you are no longer bleeding!
            }

            private class BleedTimer : Timer
            {
                private readonly Mobile m_From;
                private readonly Mobile m_Mobile;
                private int m_Count;
                private int m_MaxCount;

                public BleedTimer(Mobile from, Mobile m)
                : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0))
                {
                    m_From = from;
                    m_Mobile = m;
                    Priority = TimerPriority.TwoFiftyMS;

                    m_MaxCount = 5;
            }

                protected override void OnTick()
                {
                    if (!m_Mobile.Alive || m_Mobile.Deleted )
                    {
                        EndBleed(m_Mobile, true);
                    }
                    else
                    {
                        int damage = 0;

                        if (!Server.Spells.SkillMasteries.WhiteTigerFormSpell.HasBleedMod(m_From, out damage))
                            damage = Math.Max(1, Utility.RandomMinMax(5 - m_Count, (5 - m_Count) * 2));

                        DoBleed(m_Mobile, m_From, damage);

                        if (++m_Count == m_MaxCount)
                            EndBleed(m_Mobile, true);
                    }
                }
            }
        public override void Serialize(GenericWriter writer)
        {
        writer.Write(m_ItemID);
        writer.Write(m_Hue);

        writer.Write(m_Min);
        writer.Write(m_Max);
        }
        public override void Deserialize(GenericReader reader)
        {
        m_ItemID = reader.ReadInt();
        m_Hue = reader.ReadInt();

        m_Min = reader.ReadInt();
        m_Max = reader.ReadInt();
        }
    }
}
Also, one more thing I noticed, is that both examples of you showed had damage lines that looked like this: "AOS.Damage(m, from, damage, false, 0, 0, 0, 0, 0, 0, 100, false, false, false);"
This makes the damage direct. all of the 0s are elemental damage types in order, and the last is untyped direct damage. Idk if it was a mistake or intentional.
AOS.Damage(m, from, damage, false, physical , fire , cold , poison, energy , chaos , direct , false, false, false);
 
I made a few edits to ImpaleAoe, and it looks like it's working properly now.
tamed creatures seem to damage the right target and don't target themselves.
Here it the new code, just copy and paste it:
Code:
using System;
using Server;using System.Collections.Generic;
using System.Linq;
using Server.Items;
using Server.Network;
using System.Collections;
using Server.Spells;

namespace Server.Mobiles
{
    public class ImpaleAoe : CustomAbility
    {
        public override double TriggerChance { get { return 0.2; } }
            public override int MaxRange { get { return 5; } }
            public override TimeSpan CooldownDuration { get { return TimeSpan.FromSeconds(25); } }

            private static readonly Dictionary<Mobile, BleedTimer> m_BleedTable = new Dictionary<Mobile, BleedTimer>();

        public static bool IsBleeding(Mobile m)
            {
                return m_BleedTable.ContainsKey(m);
            }

        private int m_ItemID;
        private int m_Hue;

        private int m_Min;
        private int m_Max;

        public int ItemID
        {
        get { return m_ItemID; }
        set { m_ItemID = value; }
        }

        public int Hue
        {
        get { return m_Hue; }
        set { m_Hue = value; }
        }

        public ImpaleAoe()
        {
        m_ItemID = Utility.RandomList(0x8E0, 0x8E7, 0x8E1);
        m_Hue = 0;

        m_Min = 11;
        m_Max = 29;
        }

        public void SetDamage(int min, int max)
        {
        m_Min = min;
        m_Max = max;
        }

        public int GetDamage()
        {
        return Utility.RandomMinMax(m_Min, m_Max);
        }

        public override void Trigger(BaseCreature creature, Mobile defender, int min, int max)
        {

        if(min == 0 && max == 0)
        {
            min = m_Min;
            max = m_Max;
        }

        if(creature.InRange(defender.Location, MaxRange) && TriggerChance >= Utility.RandomDouble() && !IsInCooldown(creature))
        {
            DoEffects(creature, defender, min, max);
                    AddToCooldown(creature);
        }
        }

        public override void DoEffects(BaseCreature creature, Mobile defender, int min, int max)
        {  
        if( creature.Body == 0x191 || creature.Body == 0x190)
            creature.Animate(AnimationType.Spell, 0);
        else
            creature.Animate(AnimationType.Attack, 0);

        if (!creature.Alive || creature.Map == null)
            return;

            BeginBleed(defender, creature, this);

        }

        public static void BeginBleed(Mobile defender, Mobile creature, ImpaleAoe ability)
        {
        BeginBleed(defender, creature, ability, false);
        }

        public static void BeginBleed(Mobile defender, Mobile creature, ImpaleAoe ability, bool splintering)
        {
                BleedTimer timer = null;

        Effects.PlaySound(defender.Location, defender.Map, 0x21D);
        BaseCreature bc = creature as BaseCreature;

                IPooledEnumerable eable = creature.GetMobilesInRange(ability.MaxRange);

                foreach (Mobile m in eable)
                {
                    if (!bc.Controlled && (m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile)) && creature.CanBeHarmful(m)
            || bc.Controlled && (m is BaseCreature && !((BaseCreature)m).Controlled))
            {

                        if (m_BleedTable.ContainsKey(m))
                        {
                if (splintering)
                {
                    timer = m_BleedTable[m];
                    timer.Stop();
                }
                else
                {
                    return;
                }
                        }

                Effects.SendLocationEffect(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), m.Map, ability.ItemID, 150, 10, ability.Hue, 0); //0xAA8 is ice

                            Timer.DelayCall(TimeSpan.FromSeconds(0.75), () =>
                {
                    int d = ability.GetDamage();
                            AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);

                            timer = new BleedTimer(creature, m);
                            m_BleedTable[m] = timer;
                            timer.Start();

                            m.SendLocalizedMessage(1060160); // You are bleeding!

                            if (m is PlayerMobile)
                            {
                        m.LocalOverheadMessage(MessageType.Regular, 0x21, 1060757); // You are bleeding profusely
                                  m.NonlocalOverheadMessage(MessageType.Regular, 0x21, 1060758, m.Name); // ~1_NAME~ is bleeding profusely  
                            }
                            m.FixedParticles(0x377A, 244, 25, 9950, 31, 0, EffectLayer.Waist);
                    });
            }
                }

                eable.Free();
        }


            public static void DoBleed(Mobile m, Mobile from, int damage)
            {
                if (m.Alive && !m.IsDeadBondedPet && m != from)
                {
                    if (!m.Player)
                        damage *= 2;

                    m.PlaySound(0x133);
                    AOS.Damage(m, from, damage, false, 0, 0, 0, 0, 0, 0, 100, false, false, false);

                    Blood blood = new Blood();
                    blood.ItemID = Utility.Random(0x122A, 5);
                    blood.MoveToWorld(m.Location, m.Map);
                }
                else
                {
            EndBleed(m, false);
                }
            }

            public static void EndBleed(Mobile m, bool message)
            {
                Timer t = null;

                if (m_BleedTable.ContainsKey(m))
                {
            t = m_BleedTable[m];
                    m_BleedTable.Remove(m);
                }

                if (t == null)
                    return;

                t.Stop();

                if (message)
            m.SendLocalizedMessage(1060167); // The bleeding wounds have healed, you are no longer bleeding!
            }

            private class BleedTimer : Timer
            {
                private readonly Mobile m_From;
                private readonly Mobile m_Mobile;
                private int m_Count;
                private int m_MaxCount;

                public BleedTimer(Mobile from, Mobile m)
                : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0))
                {
                    m_From = from;
                    m_Mobile = m;
                    Priority = TimerPriority.TwoFiftyMS;

                    m_MaxCount = 5;
            }

                protected override void OnTick()
                {
                    if (!m_Mobile.Alive || m_Mobile.Deleted )
                    {
                        EndBleed(m_Mobile, true);
                    }
                    else
                    {
                        int damage = 0;

                        if (!Server.Spells.SkillMasteries.WhiteTigerFormSpell.HasBleedMod(m_From, out damage))
                            damage = Math.Max(1, Utility.RandomMinMax(5 - m_Count, (5 - m_Count) * 2));

                        DoBleed(m_Mobile, m_From, damage);

                        if (++m_Count == m_MaxCount)
                            EndBleed(m_Mobile, true);
                    }
                }
            }
        public override void Serialize(GenericWriter writer)
        {
        writer.Write(m_ItemID);
        writer.Write(m_Hue);

        writer.Write(m_Min);
        writer.Write(m_Max);
        }
        public override void Deserialize(GenericReader reader)
        {
        m_ItemID = reader.ReadInt();
        m_Hue = reader.ReadInt();

        m_Min = reader.ReadInt();
        m_Max = reader.ReadInt();
        }
    }
}
Also, one more thing I noticed, is that both examples of you showed had damage lines that looked like this: "AOS.Damage(m, from, damage, false, 0, 0, 0, 0, 0, 0, 100, false, false, false);"
This makes the damage direct. all of the 0s are elemental damage types in order, and the last is untyped direct damage. Idk if it was a mistake or intentional.
AOS.Damage(m, from, damage, false, physical , fire , cold , poison, energy , chaos , direct , false, false, false);
22121.gif11212.gif
foreach (Mobile m in eable)
{
Timer.DelayCall(TimeSpan.FromSeconds(creature.GetDistanceToSqrt(r_Item) / 20.0), () =>
{
if (creature.Controlled && (m is BaseCreature && !((BaseCreature)m).Controlled) || m is PlayerMobile && m != ((BaseCreature)creature).ControlMaster)
{

int d = Utility.RandomMinMax(min, max);
AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
}
else if (!creature.Controlled && ((m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile))))
{
int d = Utility.RandomMinMax(min, max);
AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
}
});
}
eable.Free();
}
Thank you so much for always responding so kindly. I found two more problems with the VolleyOfBolts. I think this is probably really the last problem. As shown in the pictures above, when the subpoena monster uses the VolleyOfBolts ability for other monsters, an innocent player nearby takes damage together. It's the same when you form a party and try it. And when the subpoenaed monsters used their ability, it didn't cause any damage as well. I tried to solve it using my knowledge as much as I could because I think I need to fix it in the script above, but I couldn't get the correct answer. I wonder if it's possible to fix it so that damage can be done to criminals, not innocent players. And I'm also curious about why the subpoenaed monsters don't have damage. I'm sorry I'm too greedy..
 
View attachment 22933View attachment 22934

Thank you so much for always responding so kindly. I found two more problems with the VolleyOfBolts. I think this is probably really the last problem. As shown in the pictures above, when the subpoena monster uses the VolleyOfBolts ability for other monsters, an innocent player nearby takes damage together. It's the same when you form a party and try it. And when the subpoenaed monsters used their ability, it didn't cause any damage as well. I tried to solve it using my knowledge as much as I could because I think I need to fix it in the script above, but I couldn't get the correct answer. I wonder if it's possible to fix it so that damage can be done to criminals, not innocent players. And I'm also curious about why the subpoenaed monsters don't have damage. I'm sorry I'm too greedy..

Okay, yes, I think I figured out how to get the damage to the way you want it.
Change the lines dealing with the damage, under the delay timer to this:
Code:
                    if (!creature.Controlled && (m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile)) && creature.CanBeHarmful(m)) 
            {
            //creature is wild, m is player or pet of player
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
            }
            else if (creature.Controlled && (m is BaseCreature && !((BaseCreature)m).Controlled && m.Karma < 0) || (m.Criminal || m.Murderer))
            {
            //creature is tamed, m is not a tamed pet and m's karma is less than 0, or m is a criminal or murderer (players)
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
            }
            else if (creature.Controlled && (m is BaseCreature && ((BaseCreature)m).Controlled && (((BaseCreature)m).ControlMaster.Criminal || ((BaseCreature)m).ControlMaster.Murderer))) 
            {
            // creature is tamed, m is pet of criminal or murderer
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
            }
So, according to this script:
if the creature using the ability is not tamed - it damages only players and pets of players
if the creature is tamed - it damages:
1) Criminals and Murderers (includes players)
2) non-tamed creatures with karma less than 0.
3) pets of Criminals and Murderers

One drawback to this is that the ability won't deal damage to creatures like the Lord Oaks champ, or other fey because their karma is above 0.
 
Okay, yes, I think I figured out how to get the damage to the way you want it.
Change the lines dealing with the damage, under the delay timer to this:
Code:
                    if (!creature.Controlled && (m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile)) && creature.CanBeHarmful(m))
            {
            //creature is wild, m is player or pet of player
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
            }
            else if (creature.Controlled && (m is BaseCreature && !((BaseCreature)m).Controlled && m.Karma < 0) || (m.Criminal || m.Murderer))
            {
            //creature is tamed, m is not a tamed pet and m's karma is less than 0, or m is a criminal or murderer (players)
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
            }
            else if (creature.Controlled && (m is BaseCreature && ((BaseCreature)m).Controlled && (((BaseCreature)m).ControlMaster.Criminal || ((BaseCreature)m).ControlMaster.Murderer)))
            {
            // creature is tamed, m is pet of criminal or murderer
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
            }
So, according to this script:
if the creature using the ability is not tamed - it damages only players and pets of players
if the creature is tamed - it damages:
1) Criminals and Murderers (includes players)
2) non-tamed creatures with karma less than 0.
3) pets of Criminals and Murderers

One drawback to this is that the ability won't deal damage to creatures like the Lord Oaks champ, or other fey because their karma is above 0.
It's a disadvantage that I can overcome and solve enough. I really appreciate your help for a long time. I'm truly happy. I always bless you.
Okay, yes, I think I figured out how to get the damage to the way you want it.
Change the lines dealing with the damage, under the delay timer to this:
Code:
                    if (!creature.Controlled && (m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile)) && creature.CanBeHarmful(m))
            {
            //creature is wild, m is player or pet of player
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
            }
            else if (creature.Controlled && (m is BaseCreature && !((BaseCreature)m).Controlled && m.Karma < 0) || (m.Criminal || m.Murderer))
            {
            //creature is tamed, m is not a tamed pet and m's karma is less than 0, or m is a criminal or murderer (players)
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
            }
            else if (creature.Controlled && (m is BaseCreature && ((BaseCreature)m).Controlled && (((BaseCreature)m).ControlMaster.Criminal || ((BaseCreature)m).ControlMaster.Murderer)))
            {
            // creature is tamed, m is pet of criminal or murderer
            int d = Utility.RandomMinMax(min, max);
            AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
            }
So, according to this script:
if the creature using the ability is not tamed - it damages only players and pets of players
if the creature is tamed - it damages:
1) Criminals and Murderers (includes players)
2) non-tamed creatures with karma less than 0.
3) pets of Criminals and Murderers

One drawback to this is that the ability won't deal damage to creatures like the Lord Oaks champ, or other fey because their karma is above 0.
An error was encountered while loading a saved object
- Type: Server.Mobiles.HighFireElemental
- Serial: 0x000000EB
Delete the object? (y/n)
Oh, my God. One fatal error has occurred. If you apply the new script you told me, create a monster that gives the VolleyOfBolts ability on the map, save it, and run the server, you will get a message to delete the monster as follows. I tested if other abilities were experiencing the same problem, but it didn't. The existing VolleyOfBolts script didn't have a problem, but I think it's happening in the script you told me at the end.
 
Last edited:
It's a disadvantage that I can overcome and solve enough. I really appreciate your help for a long time. I'm truly happy. I always bless you.


Oh, my God. One fatal error has occurred. If you apply the new script you told me, create a monster that gives the VolleyOfBolts ability on the map, save it, and run the server, you will get a message to delete the monster as follows. I tested if other abilities were experiencing the same problem, but it didn't. The existing VolleyOfBolts script didn't have a problem, but I think it's happening in the script you told me at the end.
That's strange. What else did you add to the script around that time?
I have the same code in regard to the damage script and the server saves and restarts without error.


That error occurs when there's a difference between the saved data and the load data, Also known as Serialization and Deserialization.
Did you change anything in these lines?
Code:
    public override void Serialize(GenericWriter writer)
    {
        writer.Write(m_Min);
        writer.Write(m_Max);
    }
    public override void Deserialize(GenericReader reader)
    {
        m_Min = reader.ReadInt();
        m_Max = reader.ReadInt();
    }
 
That's strange. What else did you add to the script around that time?
I have the same code in regard to the damage script and the server saves and restarts without error.


That error occurs when there's a difference between the saved data and the load data, Also known as Serialization and Deserialization.
Did you change anything in these lines?
Code:
    public override void Serialize(GenericWriter writer)
    {
        writer.Write(m_Min);
        writer.Write(m_Max);
    }
    public override void Deserialize(GenericReader reader)
    {
        m_Min = reader.ReadInt();
        m_Max = reader.ReadInt();
    }
using System;
using Server;using System.Collections.Generic;
using System.Linq;
using Server.Items;
using Server.Network;
using System.Collections;
using Server.Spells;

namespace Server.Mobiles
{
public class VolleyOfBolts : CustomAbility
{

public override int MaxRange{ get { return 12; } }
public override double TriggerChance { get { return 1.0; } }
public override TimeSpan CooldownDuration { get { return TimeSpan.FromSeconds(15); } }

private static Hashtable Table = new Hashtable();


private int m_ItemID;
private int m_Hue;
private int m_SoundID;
private int m_Min;
private int m_Max;


public int ItemID
{
get { return m_ItemID; }
set { m_ItemID = value; }
}

public int Hue
{
get { return m_Hue; }
set { m_Hue = value; }
}

public int Sound
{
get { return m_SoundID; }
set { m_SoundID = value; }
}

public VolleyOfBolts()
{
m_ItemID = 0x36D4;
m_Hue = 0;
m_SoundID = 0x349;

m_Min = 12;
m_Max = 18;
}

public void SetDamage(int min, int max)
{
m_Min = min;
m_Max = max;
}

public override void Trigger(BaseCreature creature, Mobile defender, int min, int max)
{

if(min == 0 && max == 0)
{
min = m_Min;
max = m_Max;
}

if(creature.InRange(defender.Location, MaxRange) && TriggerChance >= Utility.RandomDouble() && !IsInCooldown(creature))
{
DoEffects(creature, defender, min, max);
AddToCooldown(creature);
}
}

public override void DoEffects(BaseCreature creature, Mobile defender, int min, int max)
{
if (defender == null || defender.Deleted || !defender.Alive || !creature.Alive || !creature.CanBeHarmful(defender))
return;

if( creature.Body == 0x191 || creature.Body == 0x190)
creature.Animate(AnimationType.Spell, 0);

Timer t = new BoltTimer(creature, defender, this, min, max);
t.Start();
Table[defender] = t;
}

public void DoVolley(BaseCreature creature, Point3D p, int min, int max)
{

Point3D random = new Point3D(p.X + Utility.RandomMinMax(-1, 1), p.Y + Utility.RandomMinMax(-1, 1), p.Z);
TargetLocationItem r_Item = new TargetLocationItem();
r_Item.MoveToWorld(random, creature.Map);

//Effects.PlaySound(p.Location, p.Map, m_SoundID);
Effects.PlaySound(creature.Location, creature.Map, m_SoundID);
creature.MovingEffect(r_Item, m_ItemID, 7, 100, false, false, m_Hue, 0);

IPooledEnumerable eable = r_Item.GetMobilesInRange(2);
foreach (Mobile m in eable)
{
Timer.DelayCall(TimeSpan.FromSeconds(creature.GetDistanceToSqrt(r_Item) / 20.0), () =>
{
if (!creature.Controlled && (m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile)) && creature.CanBeHarmful(m))
{
//creature is wild, m is player or pet of player
int d = Utility.RandomMinMax(min, max);
AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
}
else if (creature.Controlled && (m is BaseCreature && !((BaseCreature)m).Controlled && m.Karma < 0) || (m.Criminal || m.Murderer))
{
//creature is tamed, m is not a tamed pet and m's karma is less than 0, or m is a criminal or murderer (players)
int d = Utility.RandomMinMax(min, max);
AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
}
else if (creature.Controlled && (m is BaseCreature && ((BaseCreature)m).Controlled && (((BaseCreature)m).ControlMaster.Criminal || ((BaseCreature)m).ControlMaster.Murderer)))
{
// creature is tamed, m is pet of criminal or murderer
int d = Utility.RandomMinMax(min, max);
AOS.Damage(m, creature, d, 100, 0, 0, 0, 0);
}
});
}
eable.Free();
}

public static void EndEffect(Mobile m, bool message)
{
Timer t = (Timer)Table[m];

if (t != null)
{
t.Stop();
Table.Remove(m);
}
}

public override void Serialize(GenericWriter writer)
{
writer.Write(m_Min);
writer.Write(m_Max);
}
public override void Deserialize(GenericReader reader)
{
m_Min = reader.ReadInt();
m_Max = reader.ReadInt();
}

private class BoltTimer : Timer
{
private BaseCreature Creature;
private Mobile Defender;
private VolleyOfBolts Ability;
private int Min;
private int Max;
private DateTime NextBolt;
private DateTime Expire;
private Point3D Loc;

public BoltTimer(BaseCreature creature, Mobile defender, VolleyOfBolts vob, int min, int max)
: base(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.1))
{
Creature = creature;
Defender = defender;
Ability = vob;
Min = min;
Max = max;
Loc = defender.Location;

Priority = TimerPriority.TwoFiftyMS;
creature.Animate( 12, 5, 1, true, false, 0 );
creature.Frozen = true;

Expire = DateTime.UtcNow + TimeSpan.FromSeconds(3);
NextBolt = DateTime.UtcNow + TimeSpan.FromSeconds(0.2);
}

protected override void OnTick()
{
if (!Defender.Alive || Defender.Deleted)
{
EndEffect(Defender, true);
}
else if (DateTime.UtcNow < NextBolt)
{
return;
}
else if (DateTime.UtcNow >= NextBolt)
{
Ability.DoVolley(Creature, Loc, Min, Max);
}

if (DateTime.UtcNow >= Expire)
{
Creature.Frozen = false;
EndEffect(Defender, true);
}
}
}
}
}
I didn't touch what you said at all. The script above is what I'm currently applying and using. I'm not sure what I did wrong..
 
I didn't touch what you said at all. The script above is what I'm currently applying and using. I'm not sure what I did wrong..
I can't find anything in your code that would cause that issue.
You can try changing the damage portion of the script to see if that changes things.
Try altering the damage section to something simple to see if it changes things.
Code:
                    if ((m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile)) && creature.CanBeHarmful(m))
          {
//// damage goes here ////
          }

However, I don't think changing that part of the code will solve the problem. Try looking at the creature itself maybe?
 
I can't find anything in your code that would cause that issue.
You can try changing the damage portion of the script to see if that changes things.
Try altering the damage section to something simple to see if it changes things.
Code:
                    if ((m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile)) && creature.CanBeHarmful(m))
          {
//// damage goes here ////
          }

However, I don't think changing that part of the code will solve the problem. Try looking at the creature itself maybe?
Seriously, I was stupid. I made a very simple mistake. I made a mistake not to add the VolleyOfBolts ability to the CustomAbility.cs script. I solved it perfectly. I'm so sorry. I'm so, so, so, so stupid. I'm sorry to take your precious time away from my stupidity. And thank you so much from the bottom of my heart.
 
Seriously, I was stupid. I made a very simple mistake. I made a mistake not to add the VolleyOfBolts ability to the CustomAbility.cs script. I solved it perfectly. I'm so sorry. I'm so, so, so, so stupid. I'm sorry to take your precious time away from my stupidity. And thank you so much from the bottom of my heart.
Ohhh! Yup, that'll do it lol. No worries, mistakes like this happen all the time. I'm glad we could figure it out though.
Cheers!
 
fireele.gif
using System;
using Server;using System.Collections.Generic;
using System.Linq;
using Server.Items;
using Server.Network;
using System.Collections;
using Server.Spells;

namespace Server.Mobiles
{
public class VolleyOfBolts : CustomAbility
{

public override int MaxRange{ get { return 12; } }
public override double TriggerChance { get { return 1.0; } }
public override TimeSpan CooldownDuration { get { return TimeSpan.FromSeconds(15); } }

private static Hashtable Table = new Hashtable();


private int m_ItemID;
private int m_Hue;
private int m_SoundID;
private int m_Min;
private int m_Max;


public int ItemID
{
get { return m_ItemID; }
set { m_ItemID = value; }
}

public int Hue
{
get { return m_Hue; }
set { m_Hue = value; }
}

public int Sound
{
get { return m_SoundID; }
set { m_SoundID = value; }
}

public VolleyOfBolts()
{
m_ItemID = 0x36D4;
m_Hue = 0;
m_SoundID = 0x349;

m_Min = 12;
m_Max = 18;
}

public void SetDamage(int min, int max)
{
m_Min = min;
m_Max = max;
}

public override void Trigger(BaseCreature creature, Mobile defender, int min, int max)
{

if(min == 0 && max == 0)
{
min = m_Min;
max = m_Max;
}

if(creature.InRange(defender.Location, MaxRange) && TriggerChance >= Utility.RandomDouble() && !IsInCooldown(creature))
{
DoEffects(creature, defender, min, max);
AddToCooldown(creature);
}
}

public override void DoEffects(BaseCreature creature, Mobile defender, int min, int max)
{
if (defender == null || defender.Deleted || !defender.Alive || !creature.Alive || !creature.CanBeHarmful(defender))
return;

if( creature.Body == 0x191 || creature.Body == 0x190)
creature.Animate(AnimationType.Spell, 0);

creature.Animate( 12, 5, 1, true, false, 0 );
creature.Frozen = true;
Timer.DelayCall(TimeSpan.FromSeconds(1.5), () =>
{
creature.Frozen = false;
Timer t = new BoltTimer(creature, defender, this, min, max);
t.Start();
Table[defender] = t;

});


}

public void DoVolley(BaseCreature creature, Point3D p, int min, int max)
{

Point3D random = new Point3D(p.X + Utility.RandomMinMax(-1, 1), p.Y + Utility.RandomMinMax(-1, 1), p.Z);
TargetLocationItem r_Item = new TargetLocationItem();
r_Item.MoveToWorld(random, creature.Map);

//Effects.PlaySound(p.Location, p.Map, m_SoundID);
Effects.PlaySound(creature.Location, creature.Map, m_SoundID);
creature.MovingEffect(r_Item, m_ItemID, 6, 100, true, true, m_Hue, 0);

IPooledEnumerable eable = r_Item.GetMobilesInRange(2);
foreach (Mobile m in eable)
{
Timer.DelayCall(TimeSpan.FromSeconds(creature.GetDistanceToSqrt(r_Item) / 20.0), () =>
{
if (!creature.Controlled && (m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile)) && creature.CanBeHarmful(m))
{
//creature is wild, m is player or pet of player
int d = Utility.RandomMinMax(min, max);
AOS.Damage(m, creature, d, 0, 100, 0, 0, 0);
}
else if (creature.Controlled && (m is BaseCreature && !((BaseCreature)m).Controlled && m.Karma < 50000) || (m.Criminal || m.Murderer))
{
//creature is tamed, m is not a tamed pet and m's karma is less than 0, or m is a criminal or murderer (players)
int d = Utility.RandomMinMax(min, max);
AOS.Damage(m, creature, d, 0, 100, 0, 0, 0);
}
else if (creature.Controlled && (m is BaseCreature && ((BaseCreature)m).Controlled && (((BaseCreature)m).ControlMaster.Criminal || ((BaseCreature)m).ControlMaster.Murderer)))
{
// creature is tamed, m is pet of criminal or murderer
int d = Utility.RandomMinMax(min, max);
AOS.Damage(m, creature, d, 0, 100, 0, 0, 0);
}
});
}
eable.Free();
}

public static void EndEffect(Mobile m, bool message)
{
Timer t = (Timer)Table[m];

if (t != null)
{
t.Stop();
Table.Remove(m);
}
}

public override void Serialize(GenericWriter writer)
{
writer.Write(m_Min);
writer.Write(m_Max);
}
public override void Deserialize(GenericReader reader)
{
m_Min = reader.ReadInt();
m_Max = reader.ReadInt();
}

private class BoltTimer : Timer
{
private BaseCreature Creature;
private Mobile Defender;
private VolleyOfBolts Ability;
private int Min;
private int Max;
private DateTime NextBolt;
private DateTime Expire;
private Point3D Loc;

public BoltTimer(BaseCreature creature, Mobile defender, VolleyOfBolts vob, int min, int max)
: base(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.1))
{
Creature = creature;
Defender = defender;
Ability = vob;
Min = min;
Max = max;
Loc = defender.Location;

Priority = TimerPriority.TwoFiftyMS;


Expire = DateTime.UtcNow + TimeSpan.FromSeconds(3);
NextBolt = DateTime.UtcNow + TimeSpan.FromSeconds(0.2);

}

protected override void OnTick()
{
if (!Defender.Alive || Defender.Deleted)
{
EndEffect(Defender, true);
}
else if (DateTime.UtcNow < NextBolt)
{
return;
}
else if (DateTime.UtcNow >= NextBolt)
{
Ability.DoVolley(Creature, Loc, Min, Max);
}

if (DateTime.UtcNow >= Expire)
{
EndEffect(Defender, true);
}
}
}
}
}
Oh my god.. I found a new problem using the VolleyOfBolts capability. If there are multiple monsters using the VolleyOfBolts capability as shown in the picture above, the capability will continue to be used until the opponent dies or is deleted. Both the monsters you summoned and the monsters you created in the field work the same. I post the scrip I'm using together. Can someone help me with what I did wrong?
 
View attachment 23050

Oh my god.. I found a new problem using the VolleyOfBolts capability. If there are multiple monsters using the VolleyOfBolts capability as shown in the picture above, the capability will continue to be used until the opponent dies or is deleted. Both the monsters you summoned and the monsters you created in the field work the same. I post the scrip I'm using together. Can someone help me with what I did wrong?
Oh man, that's not good lol.

So, it seems like that, in the TonTick method, the code isn't getting to the part that says 'Expire'.
Try changing the first 'if' statement in the OnTick method to look like this:
Code:
if (!Defender.Alive || Defender.Deleted || DateTime.UtcNow >= Expire)
{
            Creature.Frozen = false;
            EndEffect(Defender, true);

}

That seemed to work on my end
 
Oh man, that's not good lol.

So, it seems like that, in the TonTick method, the code isn't getting to the part that says 'Expire'.
Try changing the first 'if' statement in the OnTick method to look like this:
Code:
if (!Defender.Alive || Defender.Deleted || DateTime.UtcNow >= Expire)
{
            Creature.Frozen = false;
            EndEffect(Defender, true);

}

That seemed to work on my end
Perfectly solved! You are the best who always offer solutions. Thank you always!
 
Back