A player cast Fire field, then field hits a mob, every ''tick'' every time it damages the mob, the player target switch and target that mob, is there a way to fix this? is very annoying
 

Attachments

  • FireField.cs
    11.9 KB · Views: 5
I guess it could be either because of:
Caster.DoHarmful(m);

Or:
((BaseCreature)m).OnHarmfulSpell(Caster);

It would have to be tested with/without to see the effects ingame, and also checking where those are actually called and what piece of code they call.
I suspect one of them to set the ControlTarget or something like that, which, if i'm right, the actual targeted creature.
 
Yes, thats the issue,
if i delete those methods it FIX the problem but then players can cast field , kill players and dont earn a killcount or even became gray because theres like ''no agressor'', is there a way around?


----edit------
I used the servuo firefield.cs and theres the same issue, so i guess the problem is somewhere else :(
 
Last edited:
Will try, thank you @Po0ka


----------edit-------------



Code:
using System;
using System.Collections;
using System.Collections.Generic;
using Server.Items;
using Server.Misc;
using Server.Mobiles;
using Server.Targeting;

namespace Server.Spells.Fourth
{
    public class FireFieldSpell : MagerySpell
    {
        public override SpellCircle Circle { get { return SpellCircle.Fourth; } }
        public override int Sound { get { return 477; } }

        public override bool CanTargetGround { get { return true; } }

        private static readonly SpellInfo m_Info = new SpellInfo(
                "Fire Field", "In Flam Grav",
                263,
                9041,
                Reagent.BlackPearl,
                Reagent.SpidersSilk,
                Reagent.SulfurousAsh
            );

        public FireFieldSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
        {
        }

        public override bool Cast()
        {
            if (Caster is PlayerMobile && ((PlayerMobile)Caster).Young)
            {
                Caster.SendAsciiMessage("You cannot cast this as a young player");
                return false;
            }

            return base.Cast();
        }

        public override void OnPlayerCast()
        {
            Target((IPoint3D)SphereSpellTarget);
        }

        public override void OnCast()
        {
            Caster.Target = new InternalTarget( this );
        }

        public void Target( IPoint3D p )
        {
            if ( !Caster.CanSee( p ) )
            {
                Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
            }
            else if (SphereSpellTarget is BaseWand)
            {
                BaseWand bw = SphereSpellTarget as BaseWand;
                bw.RechargeWand(Caster, this);
            }
            else if (/*SpellHelper.CheckTown(p, Caster) && */CheckSequence())
            {


                //if (CheckSequence())

                SpellHelper.GetSurfaceTop( ref p );

                int dx = Caster.Location.X - p.X;
                int dy = Caster.Location.Y - p.Y;
                int rx = (dx - dy) * 44;
                int ry = (dx + dy) * 44;

                bool eastToWest;

                if ( rx >= 0 && ry >= 0 )
                {
                    eastToWest = false;
                }
                else if ( rx >= 0 )
                {
                    eastToWest = true;
                }
                else if ( ry >= 0 )
                {
                    eastToWest = true;
                }
                else
                {
                    eastToWest = false;
                }

                Effects.PlaySound(p, Caster.Map, Sound);

                int itemID = eastToWest ? 0x398C : 0x3996;

                TimeSpan duration;

                if ( Core.AOS )
                    duration = TimeSpan.FromSeconds( (15 + (Caster.Skills.Magery.Fixed / 5)) / 4 );
                else
                    duration = TimeSpan.FromSeconds( 4.0 + (Caster.Skills[SkillName.Magery].Value * 0.5) );

                List<InternalItem> itemList = new List<InternalItem>();
                for ( int i = -3; i <= 3; ++i )
                {
                    Point3D loc = new Point3D( eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z );
                  
                    //bool canFit = SpellHelper.AdjustField(ref loc, Caster.Map, 12, false);

                    //if (!canFit)
                    //    continue;

                    IPooledEnumerable eable = Caster.Map.GetMobilesInRange(loc, 0);

                    foreach (Mobile m in eable)
                    {
                        if (m.AccessLevel != AccessLevel.Player || !m.Alive || (m is PlayerMobile && ((PlayerMobile)m).Young))
                            continue;
                   

                        //Taran: The whole field counts as a harmful action, not just the target
                        if (m.Location.Z - loc.Z < 18 && m.Location.Z - loc.Z > -10)
                            Caster.DoHarmful(m, true);

                        if (m is BaseCreature)
                            ((BaseCreature)m).OnHarmfulSpell(Caster);
                    }

                    InternalItem toAdd = new InternalItem( itemID, loc, Caster, Caster.Map, duration, i );
                    itemList.Add(toAdd);
                 
                }

                if (itemList.Count > 0)
                    new SoundTimer(itemList, Sound).Start();

                if (SphereSpellTarget is Mobile)
                {
                    InternalItem castItem = new InternalItem(itemID, (SphereSpellTarget as Mobile).Location, Caster, Caster.Map, duration, 3);
                    castItem.OnMoveOver(SphereSpellTarget as Mobile);
                    //Caster.DoHarmful(SphereSpellTarget as Mobile); - This check is now made for each field tile
                    castItem.Delete();
                }
            }

            FinishSequence();
        }

        private class SoundTimer : Timer
        {
            private readonly List<InternalItem> m_ItemList;
            private readonly int m_SoundId;

            public SoundTimer(List<InternalItem> itemList, int soundId)
                : base(TimeSpan.FromSeconds(2.0))
            {
                Priority = TimerPriority.OneSecond;
                m_SoundId = soundId;

                m_ItemList = itemList;
            }

            protected override void OnTick()
            {
                if (m_ItemList.Count > 0)
                {
                    InternalItem playFrom;

                    do
                    {
                        if (m_ItemList.Count > 1)
                            playFrom = m_ItemList[Utility.Random(m_ItemList.Count)];
                        else
                            playFrom = m_ItemList[0];

                        if (playFrom.Deleted)
                            m_ItemList.Remove(playFrom);

                    } while (m_ItemList.Count > 0 && playFrom.Deleted);

                    if (!playFrom.Deleted)
                    {
                        try
                        {

                            bool playSound = false;
                            foreach (InternalItem i in m_ItemList)
                            {
                                IPooledEnumerable ipe = i.GetMobilesInRange(0);
                                foreach (Mobile m in ipe)
                                {
                                    if (m.AccessLevel != AccessLevel.Player || !m.Alive || (m is PlayerMobile && ((PlayerMobile)m).Young))
                                        continue;

                                    i.OnMoveOver(m);
                                    if (!playSound)
                                        playSound = true;
                                }

                                ipe.Free();
                            }

                            if (playSound)
                            {
                                IPooledEnumerable ipe = playFrom.GetMobilesInRange(12);
                                foreach (Mobile m in ipe)
                                    m.PlaySound(m_SoundId);

                                ipe.Free();
                            }

                            new SoundTimer(m_ItemList, m_SoundId).Start();
                        }
                        catch
                        {
                        }
                    }
                }
            }
        }


        [DispellableField]
        public class InternalItem : Item
        {
            private Timer m_Timer;
            private DateTime m_End;
            private Mobile m_Caster;

            public override bool BlocksFit{ get{ return true; } }

            public InternalItem( int itemID, Point3D loc, Mobile caster, Map map, TimeSpan duration, int val ) : base( itemID )
            {
                bool canFit = SpellHelper.AdjustField( ref loc, map, 12, false );

                Visible = true;
                Movable = false;
                Light = LightType.Circle300;

                MoveToWorld( loc, map );

                m_Caster = caster;

                m_End = DateTime.Now + duration;

                int timespan = Utility.Random(60, 120);

                m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( timespan ), caster.InLOS( this ), canFit );
                m_Timer.Start();
            }

            public override void OnAfterDelete()
            {
                base.OnAfterDelete();

                if ( m_Timer != null )
                    m_Timer.Stop();
            }

            public InternalItem( Serial serial ) : base( serial )
            {
            }

            public override void Serialize( GenericWriter writer )
            {
                base.Serialize( writer );

                writer.Write( 1 ); // version

                writer.Write( m_Caster );
                writer.WriteDeltaTime( m_End );
            }

            public override void Deserialize( GenericReader reader )
            {
                base.Deserialize( reader );

                int version = reader.ReadInt();

                switch ( version )
                {
                    case 1:
                    {
                        m_Caster = reader.ReadMobile();

                        goto case 0;
                    }
                    case 0:
                    {
                        m_End = reader.ReadDeltaTime();

                        m_Timer = new InternalTimer( this, TimeSpan.Zero, true, true );
                        m_Timer.Start();

                        break;
                    }
                }
            }

            public override bool OnMoveOver( Mobile m )
            {
                //if (Visible && m_Caster != null && m_Caster.CanBeHarmful(m, false))
                //{
                if (m.AccessLevel != AccessLevel.Player || !m.Alive || (m is PlayerMobile && ((PlayerMobile)m).Young))
                    return true;
                if( m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned ))
                    return true;

                //if (SpellHelper.CanRevealCaster(m))
                //    m_Caster.RevealingAction();
                   
                if (Map != m.Map || !(m.Location.Z >= Location.Z && (m.Location.Z <= (Location.Z + 15))))
                    return true;

                int damage = 3;
                m_Caster.DoHarmful(m, true);

                if (m.CheckSkill(SkillName.MagicResist, 0.0, 30.0))
                {
                    damage = 3;
                    m_Caster.DoHarmful(m, true);
                    m.SendMessage("You feel yourself resisting magic"); // You feel yourself resisting magical energy.
                }

                AOS.Damage(m, m_Caster, damage, 0, 100, 0, 0, 0);
                //}

                return true;
            }

            private class InternalTimer : Timer
            {
                private readonly InternalItem m_Item;
                private bool m_InLOS, m_CanFit;

                private static readonly Queue m_Queue = new Queue();

                public InternalTimer( InternalItem item, TimeSpan delay, bool inLOS, bool canFit ) : base( delay, TimeSpan.FromSeconds( 1.0 ) )
                {
                    m_Item = item;
                    m_InLOS = inLOS;
                    m_CanFit = canFit;

                    Priority = TimerPriority.FiftyMS;
                }

                protected override void OnTick()
                {
                    if ( m_Item.Deleted )
                        return;

                    if ( !m_Item.Visible )
                    {
                        //if ( m_InLOS && m_CanFit )
                        //    m_Item.Visible = true;
                        //else
                        //    m_Item.Delete();

                        if ( !m_Item.Deleted )
                        {
                            m_Item.ProcessDelta();
                            Effects.SendLocationParticles( EffectItem.Create( m_Item.Location, m_Item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 5029 );
                        }
                    }
                    else if ( DateTime.Now > m_Item.m_End )
                    {
                        m_Item.Delete();
                        Stop();
                    }
                    else
                    {
                        Map map = m_Item.Map;
                        Mobile caster = m_Item.m_Caster;

                        if ( map != null && caster != null )
                        {
                            foreach ( Mobile m in m_Item.GetMobilesInRange( 0 ) )
                            {
                                if (m.AccessLevel != AccessLevel.Player || !m.Alive)
                                    continue;

                                if ( (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z )// && SpellHelper.ValidIndirectTarget( caster, m ) && caster.CanBeHarmful( m, false ) )
                                    m_Queue.Enqueue( m );
                            }

                            while (m_Queue.Count > 0)
                            {
                                Mobile m = (Mobile)m_Queue.Dequeue();

                                //if (SpellHelper.CanRevealCaster(m))
                                //    caster.RevealingAction();

                                int damage = 2;

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

                                    m.SendMessage("You feel yourself resisting magic"); // You feel yourself resisting magical energy.
                                }

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

        private class InternalTarget : Target
        {
            private readonly FireFieldSpell m_Owner;

            public InternalTarget( FireFieldSpell owner ) : base( 12, true, TargetFlags.None )
            {
                m_Owner = owner;
            }

            protected override void OnTarget( Mobile from, object o )
            {
                if ( o is IPoint3D )
                    m_Owner.Target( (IPoint3D)o );
            }

            protected override void OnTargetFinish( Mobile from )
            {
                m_Owner.FinishSequence();
            }
        }
    }
}

Fixed both problems target doesn switch anymore, when a mobile or player takes damage, but caster doesnt earn a kill count when someone steps into field and die.
Thanks !
 
Last edited:
The "true" bool should be interpreted as indirect damage, so i really wonder why it's not giving a kill...
Have you tried using false?
 
In every method? change true to false?


I dont get it either, the caster became gray, the bounty gump shows up on victim, the kill broadcast that i have says That the caster killed him, and still doesnt earn a kill count xD
 
Last edited:
Hm.
Then this could be a bigger problem...
Without specifying true or false, it goes as wanted? Or no murder count increments?
 
Without specifying the true or false, it gives kill count but the switch target problem appears and

The issue apply to every field, when someone steps into para field the caster target switch to the player too.
I can disable the spell :/ ,what shame, fields are a big part of mages
 
Do you have Mobile.cs?

This is in ServUO:
Code:
        public virtual void DoHarmful(Mobile target, bool indirect)
        {
            if (target == null || m_Deleted)
            {
                return;
            }

            bool isCriminal = IsHarmfulCriminal(target);

            OnHarmfulAction(target, isCriminal);
            target.AggressiveAction(this, isCriminal);

            Region.OnDidHarmful(this, target);
            target.Region.OnGotHarmful(this, target);

            if (!indirect)
            {
                Combatant = target;
            }

            if (m_ExpireCombatant == null)
            {
                m_ExpireCombatant = new ExpireCombatantTimer(this);
            }
            else
            {
                m_ExpireCombatant.Stop();
            }

            m_ExpireCombatant.Start();
        }

This is in RunUO 2.0 RC1
Code:
public virtual void DoHarmful( Mobile target, bool indirect )
        {
            if( target == null || m_Deleted )
                return;

            bool isCriminal = IsHarmfulCriminal( target );

            OnHarmfulAction( target, isCriminal );
            target.AggressiveAction( this, isCriminal );

            this.Region.OnDidHarmful( this, target );
            target.Region.OnGotHarmful( this, target );

            if( !indirect )
                Combatant = target;

            if( m_ExpireCombatant == null )
                m_ExpireCombatant = new ExpireCombatantTimer( this );
            else
                m_ExpireCombatant.Stop();

            m_ExpireCombatant.Start();
        }

Setting this to true should not have such effect...
Have you made any modification to stock scripts that are related to the murder reporting system?
 
Code:
public virtual void DoHarmful( Mobile target, bool indirect )
        {
            if( target == null || m_Deleted )
                return;

            bool isCriminal = IsHarmfulCriminal( target );

            OnHarmfulAction( target, isCriminal );
            target.AggressiveAction( this, isCriminal );

            this.Region.OnDidHarmful( this, target );
            target.Region.OnGotHarmful( this, target );

            if( !indirect )
                Combatant = target;

            if( m_ExpireCombatant == null )
                m_ExpireCombatant = new ExpireCombatantTimer( this );
            else
                m_ExpireCombatant.Stop();

            m_ExpireCombatant.Start();
        }
 
I checked the get/set of the Combatant field, and it seems to be setting some stuffs:
Code:
[CommandProperty( AccessLevel.GameMaster )]
        public virtual Mobile Combatant
        {
            get
            {
                return m_Combatant;
            }
            set
            {
                if( m_Deleted )
                    return;

                if( m_Combatant != value && value != this )
                {
                    Mobile old = m_Combatant;

                    ++m_ChangingCombatant;
                    m_Combatant = value;

                    if( (m_Combatant != null && !CanBeHarmful( m_Combatant, false )) || !Region.OnCombatantChange( this, old, m_Combatant ) )
                    {
                        m_Combatant = old;
                        --m_ChangingCombatant;
                        return;
                    }

                    if( m_NetState != null )
                        m_NetState.Send( new ChangeCombatant( m_Combatant ) );

                    if( m_Combatant == null )
                    {
                        if( m_ExpireCombatant != null )
                            m_ExpireCombatant.Stop();

                        if( m_CombatTimer != null )
                            m_CombatTimer.Stop();

                        m_ExpireCombatant = null;
                        m_CombatTimer = null;
                    }
                    else
                    {
                        if( m_ExpireCombatant == null )
                            m_ExpireCombatant = new ExpireCombatantTimer( this );

                        m_ExpireCombatant.Start();

                        if( m_CombatTimer == null )
                            m_CombatTimer = new CombatTimer( this );

                        m_CombatTimer.Start();
                    }

                    if( m_Combatant != null && CanBeHarmful( m_Combatant, false ) )
                    {
                        DoHarmful( m_Combatant );

                        if( m_Combatant != null )
                            m_Combatant.PlaySound( m_Combatant.GetAngerSound() );
                    }

                    OnCombatantChange();
                    --m_ChangingCombatant;
                }
            }
        }

This here:
m_NetState.Send( new ChangeCombatant( m_Combatant ) );

Is what moves the attention toward the player/creature, but sadly, since it's a get/set, i would strongly disagree to modify that directly.
If RunUO would have been opened i would have checked there, but right now i have no clue how to fix that.
 
Hold on

It gives murder! i disabled it LONG ago, because i emulate a Sphere server, they dont have murder gump xD.

Ill re-enable the gump, worth it.


Thank you so much once again po0ka
 
Back