Hi Guys, I Apologize for my bad english and for my bad Code XD

I'm trying to customize the Tracking skill for an RPG shard.
Compile and i Obtain the info relative to the mobile, however when I put on track on a mobile and I kill it, the client crashes for unknown packet: 0xff...
Code:
using System;
using System.Collections;
using Server;
using Server.Gumps;
using Server.Network;
using Server.Spells;
using Server.Spells.Necromancy;
using Server.Mobiles;
using Server.Misc;
using Server.Items;

namespace Server.SkillHandlers
{
   public class Tracking
   {
     public static void Initialize()
     {
       SkillInfo.Table[(int)SkillName.Tracking].Callback = new SkillUseCallback( OnUse );
     }

     public static TimeSpan OnUse( Mobile m )
     {
     

       if (m.Hidden == true && (m is PlayerMobile))
       {
         PlayerMobile playa = (PlayerMobile)m;
         int skillsum = (int)(playa.Skills.Hiding.Value);
         skillsum += (int)(playa.Skills.Stealth.Value);
         skillsum = (int)(skillsum / 2);
         skillsum += (int)(playa.RawDex / 10);
         if (playa.ClasseType == ClasseType.Rogue)
           skillsum += 64;
         if (playa.ClasseType == ClasseType.Ranger)
           skillsum += 21;
         if (skillsum > Utility.Random (175))
         {
           m.SendLocalizedMessage( 1011350 ); // What do you wish to track?

           m.CloseGump( typeof( TrackWhatGump ) );
           m.CloseGump( typeof( TrackWhoGump ) );
           m.SendGump( new TrackWhatGump( m ) );       
           m.SendMessage ("Riesci a non rivelare la tua posizione");
         }
         else
         {
           m.RevealingAction ();
           m.SendMessage ("Riveli la tua posizione!");
         m.Emote ("*Cerca qualcosa*");

         m.SendLocalizedMessage( 1011350 ); // What do you wish to track?

         m.CloseGump( typeof( TrackWhatGump ) );
         m.CloseGump( typeof( TrackWhoGump ) );
         m.SendGump( new TrackWhatGump( m ) );
         }
       }
       else
       {
         m.Emote ("*Cerca qualcosa*");

         m.SendLocalizedMessage( 1011350 ); // What do you wish to track?

         m.CloseGump( typeof( TrackWhatGump ) );
         m.CloseGump( typeof( TrackWhoGump ) );
         m.SendGump( new TrackWhatGump( m ) );
       }

       return TimeSpan.FromSeconds( 10.0 ); // 10 second delay before beign able to re-use a skill
     }

     public class TrackingInfo
     {
       public Mobile m_Tracker;
       public Mobile m_Target;
       public Point2D m_Location;
       public Map m_Map;

       public TrackingInfo( Mobile tracker, Mobile target )
       {
         m_Tracker = tracker;
         m_Target = target;
         m_Location = new Point2D( target.X, target.Y );
         m_Map = target.Map;
       }
     }

     private static Hashtable m_Table = new Hashtable();

     public static void AddInfo( Mobile tracker, Mobile target )
     {
       TrackingInfo info = new TrackingInfo( tracker, target );
       m_Table[tracker] = info;
     }

     public static double GetStalkingBonus( Mobile tracker, Mobile target )
     {
       // Note: This is not reset as of publish 35.

       TrackingInfo info = m_Table[tracker] as TrackingInfo;
     
       if ( info == null || info.m_Target != target || info.m_Map != target.Map )
         return 0.0;

       int xDelta = info.m_Location.X - target.X;
       int yDelta = info.m_Location.Y - target.Y;

        double bonus = Math.Sqrt((xDelta * xDelta) + (yDelta * yDelta));

  m_Table.Remove(tracker);   //Reset as of Pub 40, counting it as bug for Core.SE.

  if (Core.ML)
  return Math.Min(bonus, 10 + tracker.Skills.Tracking.Value / 10);

  return bonus;
     }

     public static void ClearTrackingInfo( Mobile tracker )
     {
       m_Table.Remove( tracker );
     }
   }

   public class TrackWhatGump : Gump
   {
     private Mobile m_From;
     private bool m_Success;

     public TrackWhatGump( Mobile from ) : base( 20, 30 )
     {
       m_From = from;
       m_Success = from.CheckSkill( SkillName.Tracking, 0.0, 21.1 );

       AddPage( 0 );

       AddBackground( 0, 0, 440, 135, 5054 );

       AddBackground( 10, 10, 420, 75, 2620 );
       AddBackground( 10, 85, 420, 25, 3000 );

       AddItem( 20, 20, 9682 );
       AddButton( 20, 110, 4005, 4007, 1, GumpButtonType.Reply, 0 );
       AddHtmlLocalized( 20, 90, 100, 20, 1018087, false, false ); // Animals

       AddItem( 120, 20, 9607 );
       AddButton( 120, 110, 4005, 4007, 2, GumpButtonType.Reply, 0 );
       AddHtmlLocalized( 120, 90, 100, 20, 1018088, false, false ); // Monsters

       AddItem( 220, 20, 8454 );
       AddButton( 220, 110, 4005, 4007, 3, GumpButtonType.Reply, 0 );
       AddHtmlLocalized( 220, 90, 100, 20, 1018089, false, false ); // Human NPCs

       AddItem( 320, 20, 8455 );
       AddButton( 320, 110, 4005, 4007, 4, GumpButtonType.Reply, 0 );
       AddHtmlLocalized( 320, 90, 100, 20, 1018090, false, false ); // Players
     }

     public override void OnResponse( NetState state, RelayInfo info )
     {
       if ( info.ButtonID >= 1 && info.ButtonID <= 4 )
         TrackWhoGump.DisplayTo( m_Success, m_From, info.ButtonID - 1 );
     }
   }

   public delegate bool TrackTypeDelegate( Mobile m );

   public class TrackWhoGump : Gump
   {
     private Mobile m_From;
     private int m_Range;

     private static TrackTypeDelegate[] m_Delegates = new TrackTypeDelegate[]
       {
         new TrackTypeDelegate( IsAnimal ),
         new TrackTypeDelegate( IsMonster ),
         new TrackTypeDelegate( IsHumanNPC ),
         new TrackTypeDelegate( IsPlayer )
       };

     private class InternalSorter : IComparer
     {
       private Mobile m_From;

       public InternalSorter( Mobile from )
       {
         m_From = from;
       }

       public int Compare( object x, object y )
       {
         if ( x == null && y == null )
           return 0;
         else if ( x == null )
           return -1;
         else if ( y == null )
           return 1;

         Mobile a = x as Mobile;
         Mobile b = y as Mobile;

         if ( a == null || b == null )
           throw new ArgumentException();

         return m_From.GetDistanceToSqrt( a ).CompareTo( m_From.GetDistanceToSqrt( b ) );
       }
     }

     public static void DisplayTo( bool success, Mobile from, int type )
     {
       if ( !success )
       {
         from.SendLocalizedMessage( 1018092 ); // You see no evidence of those in the area.
         return;
       }

       Map map = from.Map;

       if ( map == null )
         return;

       TrackTypeDelegate check = m_Delegates[type];

       from.CheckSkill( SkillName.Tracking, 21.1, 100.0 ); // Passive gain

       int range = 10 + (int)(from.Skills[SkillName.Tracking].Value / 3);
     
       PlayerMobile pm = (PlayerMobile) from;
     
       if (pm.ClasseType == ClasseType.Ranger && type == 0)
         range += (int)(from.Skills[SkillName.AnimalTaming].Value / 5);
     
       if (pm.ClasseType == ClasseType.Rogue)
         range += (int)(from.Skills[SkillName.Tracking].Value / 10);

       bool canide = false;

       ArrayList listino = new ArrayList();

       foreach ( Mobile animale in pm.GetMobilesInRange( 4 ) )
       {
         // Ghosts can no longer be tracked
         if ( animale.Alive && animale is BaseCreature )
         {
           if ( ((BaseCreature)animale).Controlled )
             listino.Add(animale);
         }
       }
     
       for (int i = 0; i < listino.Count; i++)
       {
         Mobile ora = listino as Mobile;
         if ( ((BaseCreature)ora).ControlMaster == pm && ((BaseCreature)ora).TipoPet == PetType.Canide)
         {
           canide = true;
           ora.Emote ("*Fiuta*");
         }
  
        
       }


       if (pm.Hidden == true)
       {
         if (pm.ClasseType == ClasseType.Rogue)
           range -= 10;
         else if (pm.ClasseType == ClasseType.Ranger)
           range -= 20;
         else
           range -= 30;
       }
      
       ArrayList list = new ArrayList();

       foreach ( Mobile m in from.GetMobilesInRange( range ) )
       {
         // Ghosts can no longer be tracked
         if ( m != from && (!Core.AOS || m.Alive) && (!m.Hidden || m.AccessLevel == AccessLevel.Player || from.AccessLevel > m.AccessLevel) && check( m ) && CheckDifficulty( from, m, canide ) )
           list.Add( m );
       }

       if ( list.Count > 0 )
       {
         list.Sort( new InternalSorter( from ) );

         from.SendGump( new TrackWhoGump( from, list, range ) );
         from.SendLocalizedMessage( 1018093 ); // Select the one you would like to track.
       }
       else
       {
         if ( type == 0 )
           from.SendLocalizedMessage( 502991 ); // You see no evidence of animals in the area.
         else if ( type == 1 )
           from.SendLocalizedMessage( 502993 ); // You see no evidence of creatures in the area.
         else
           from.SendLocalizedMessage( 502995 ); // You see no evidence of people in the area.
       }
     }

     // Tracking players uses tracking and detect hidden vs. hiding and stealth
     private static bool CheckDifficulty( Mobile from, Mobile m, bool hasdog )
     {
       if ( !Core.AOS || !m.Player )
         return true;

       int tracking = from.Skills[SkillName.Tracking].Fixed;
       int detectHidden = from.Skills[SkillName.DetectHidden].Fixed;

       if (hasdog)
         tracking += 50;

       int hiding = m.Skills[SkillName.Hiding].Fixed;
       int stealth = m.Skills[SkillName.Stealth].Fixed;

       if (m is PlayerMobile)
       {
         hiding += ( PlayerMobile.BonusHidingRogue( m ));
       }

       if ( m is BaseCreature )
       {
         hiding += ( 12 * (3 - (int)((BaseCreature)m).Stazza ) );
       }

       int divisor = hiding + stealth;

       // Necromancy forms affect tracking difficulty
       if (TransformationSpellHelper.UnderTransformation(m, typeof(HorrificBeastSpell)))
  divisor -= 200;
  else if (TransformationSpellHelper.UnderTransformation(m, typeof(VampiricEmbraceSpell)) && divisor < 500)
  divisor = 500;
  else if (TransformationSpellHelper.UnderTransformation(m, typeof(WraithFormSpell)) && divisor <= 2000)
  divisor += 200;

       int chance;
       if ( divisor > 0 )
       {
         if ( Core.SE )
           chance = 50 * (tracking * 2 + detectHidden) / divisor;
         else
           chance = 50 * (tracking + detectHidden + 10 * Utility.RandomMinMax( 1, 20 )) / divisor;
       }
       else
         chance = 100;

       return chance > Utility.Random( 100 );
     }

     private static bool IsAnimal( Mobile m )
     {
       return ( !m.Player && m.Body.IsAnimal );
     }

     private static bool IsMonster( Mobile m )
     {
       return ( !m.Player && m.Body.IsMonster );
     }

     private static bool IsHumanNPC( Mobile m )
     {
       return ( !m.Player && m.Body.IsHuman );
     }

     private static bool IsPlayer( Mobile m )
     {
       return m.Player;
     }

     private int ArrowDir( Direction d )
     {
       switch ( d )
       {
         case Direction.North: return 0x1195; break;
         case Direction.Right: return 0x1196; break;
         case Direction.East: return 0x1197; break;
         case Direction.Down: return 0x1198; break;
         case Direction.South: return 0x1199; break;
         case Direction.Left: return 0x119A; break;
         case Direction.West: return 0x119B; break;
         case Direction.Up: return 0x1194; break;
       }
    
       return 0;
     }

     private string getDistanzaHue( Mobile one, Mobile two, int range )
     {
       int dis = -1;

       if ( !one.InRange(two, range / 2) )
         dis = 0; //fuga
       else
       {
         int rBase = range / 2;
         int distanza = Math.Max( Math.Abs( one.X - two.X ), Math.Abs( one.Y - two.Y ) );
         dis = (int)( 4.0 - ( ( (double)distanza / (double)rBase ) * 3 ) );
       }

       if ( dis >= 3 )
         return "008706";
       else
       if ( dis == 2 )
         return "D27C00";
       else
         return "BF0000";
     }

     private ArrayList m_List;

     private TrackWhoGump( Mobile from, ArrayList list, int range ) : base( 20, 30 )
     {
       m_From = from;
       m_List = list;
       m_Range = range;

       AddPage( 0 );

       AddBackground( 0, 0, 440, 155, 5054 );

       AddBackground( 10, 10, 420, 75, 2620 );
       AddBackground( 10, 85, 420, 45, 3000 );

       if ( list.Count > 4 )
       {
         AddBackground( 0, 155, 440, 155, 5054 );

         AddBackground( 10, 165, 420, 75, 2620 );
         AddBackground( 10, 240, 420, 45, 3000 );

         if ( list.Count > 8 )
         {
           AddBackground( 0, 310, 440, 155, 5054 );

           AddBackground( 10, 320, 420, 75, 2620 );
           AddBackground( 10, 395, 420, 45, 3000 );
         }
       }

       for ( int i = 0; i < list.Count && i < 12; ++i )
       {
         Mobile m = (Mobile)list;

         AddItem( 20 + ((i % 4) * 100), 20 + ((i / 4) * 155), ShrinkTable.Lookup( m ) );

         Direction d = from.GetDirectionTo( m );
         AddImage( 40 + ((i % 4) * 100), 20 + ((i / 4) * 155), ArrowDir( d ));

         AddButton( 20 + ((i % 4) * 100), 130 + ((i / 4) * 155), 4005, 4007, i + 1, GumpButtonType.Reply, 0 );

         string name = "*Tracce*";
         if ( m.Name != null )
         {
           if ( NotorietyHandlers.GildaOrParty( m_From, m ) )
             name = m.Name;
           else
           {
             if ( IsHumanNPC( m ) || IsPlayer( m ) )
             {
               if ( BaseArmor.GetMaxArmor( m ) >= ArmorMaterialType.Chainmail )
                 name = "*Tracce marcate*";
               else
                 name = "*Tracce lievi*";
             }
             else
             {
               if ( m is BaseCreature )
               {
                 if ( ((BaseCreature)m).ControlMaster != null && ((BaseCreature)m).ControlMaster == m_From )
                   name = m.Name;
                 else
                 if ( (int)((BaseCreature)m).Stazza > 3 )
                 {
                   if ( (int)((BaseCreature)m).Stazza > 5 )
                     name = "*Tracce ovvie*";
                   else
                     name = "*Tracce prominenti*";
                 }
               }
             }
           }
         }
            
           AddHtml( 20 + ((i % 4) * 100), 90 + ((i / 4) * 155), 90, 40, "<BASEFONT COLOR=#" + getDistanzaHue( m, m_From, m_Range ) + ">" + name + "</BASEFONT>", false, false );
       }
     }

     public override void OnResponse( NetState state, RelayInfo info )
     {
       int index = info.ButtonID - 1;

       if ( index >= 0 && index < m_List.Count && index < 12 )
       {
         Mobile m = (Mobile)m_List[index];

         m_From.QuestArrow = new TrackArrow( m_From, m, m_Range * 2 );

         if ( Core.SE )
           Tracking.AddInfo( m_From, m );
       }
     }
   }

   public class TrackArrow : QuestArrow
   {
     private Mobile m_From;
     private Timer m_Timer;

     public TrackArrow( Mobile from, Mobile target, int range ) : base( from, target )
     {
       m_From = from;
       m_Timer = new TrackTimer( from, target, range, this );
       m_Timer.Start();
     }

     public override void OnClick( bool rightClick )
     {
       if ( rightClick )
       {
         Tracking.ClearTrackingInfo( m_From );

         m_From = null;

         Stop();
       }
     }

     public override void OnStop()
     {
       m_Timer.Stop();

       if ( m_From != null )
       {
         Tracking.ClearTrackingInfo( m_From );

         m_From.SendLocalizedMessage( 503177 ); // You have lost your quarry.
       }
     }
   }

   public class TrackInfoGump : Gump
   {
     private string ConvertiArmor( ArmorMaterialType amt )
     {
       if (amt >= ArmorMaterialType.Plate )
         return "Armatura pesante";

       else
       if (amt >= ArmorMaterialType.Ringmail )
         return "Armatura metallica";
       else
       if (amt >= ArmorMaterialType.Leather )
         return "Armatura leggera";
       else
         return "Senza armatura";
     }

     private string ConvertiCondizione( int cond )
     {
       if ( cond == 5 )
         return "In salute e vigore";
       else
       if ( cond == 4 )
         return "Lieve affaticamento";
       else
       if ( cond == 3 )
         return "In difficolta`";
       else
       if ( cond == 2 )
         return "In seria difficolta`";
       else
       if ( cond == 1 )
         return "Gravissimi problemi";
       else
       if ( cond == 0 )
         return "Morente";
       else
         return "Non definibile";
     }

     private string ConvertiDist( int dist )
     {
       if ( dist >= 3 )
         return "Vicine";
       else
       if ( dist == 2 )
         return "Media freschezza";
       else
       if ( dist == 1 )
         return "Vecchie";
       else
       if ( dist == 0 )
         return "In perdita...";
       else
         return "non valutabili";
     }

     private int ConvertiDistHue( int dist )
     {
       if ( dist >= 3 )
         return 66;
       else
       if ( dist == 2 )
         return 43;
       else
         return 32;
     }

     public TrackInfoGump( Mobile hunt, Mobile quarry, int displayCond, int dist ) : base ( 450, 50 )
     {
       Closable=true;
       Disposable=true;
       Dragable=true;
       Resizable=false;
       AddPage(0);
       AddBackground(0, 0, 250,150, 0x2422);
       AddLabel(40, 30, 43, @"Dati sulle tracce");
       String data = "";

       double punteggio = hunt.Skills.Tracking.Value + ( hunt.Skills.Camping.Value / 2.0 );

       if ( quarry is BaseCreature && ((BaseCreature)quarry).Tamable )
         punteggio += ( hunt.Skills.AnimalLore. Value / 3.0 );

       if ( punteggio >= 130 )
       {
         if ( quarry is BaseCreature )
         {
           if ( !quarry.Body.IsHuman )
             data = "Tipologia: " + ((BaseCreature)quarry).TrackName;
           else
             data = "Tipologia: Umanoide - " + ConvertiArmor( BaseArmor.GetMaxArmor( quarry ) );
         }
         else
         if ( quarry.Player )
         {
           if ( ((PlayerMobile)quarry).ClasseType != ClasseType.Rogue )
             data = "Tipologia: Umanoide - " + ConvertiArmor( BaseArmor.GetMaxArmor( quarry ) );
           else
           {
             data = "Tipologia: Umanoide - Armatura leggera";
           }
         }
      
  
         AddLabel(40, 50, 50, @data);
       }

       if ( punteggio >= 150 )
       {
         data = "Condizioni: " + ConvertiCondizione( displayCond );
         AddLabel(40,70, 50, @data);
       }
      
       data = "Tracce: " + ConvertiDist( dist );
       AddLabel(40, 90, ConvertiDistHue( dist ), @data);
     }
   }


   public class TrackTimer : Timer
   {
     private Mobile m_From, m_Target;
     private int m_Range;
     private int m_LastX, m_LastY;
     private QuestArrow m_Arrow;
     private bool isescaping = false;
     private int beforerun;
     private PlayerMobile pm;

     private int lastKnownCond;
     private double condDist;

     private int getCondition( Mobile mob )
     {
       double percent = ( (double)mob.Hits / (double)mob.HitsMax );
       percent *= 0.75;

       percent += ( ( (double)mob.Stam / (double)mob.StamMax ) / 4.0 );
       percent *= 5.0;

       return (int)(percent);


     }

     private int getDistanza( Mobile one, Mobile two, int range )
     {
       if ( !one.InRange(two, range / 2) )
         return 0; //fuga
       else
       {
         int rBase = range / 2;
         int distanza = Math.Max( Math.Abs( one.X - two.X ), Math.Abs( one.Y - two.Y ) );
         return (int)( 4.0 - ( ( (double)distanza / (double)rBase ) * 3 ) );
       }
     }

     private bool AllowCondizioni( Mobile hunt, Mobile quarry )
     {
       double punteggio = hunt.Skills.Tracking.Value + ( hunt.Skills.Camping.Value / 2.0 );

       if ( quarry is BaseCreature && ((BaseCreature)quarry).Tamable )
         punteggio += ( hunt.Skills.AnimalLore. Value / 3.0 );

       return ( punteggio >= 150 );
     }
      

     public TrackTimer( Mobile from, Mobile target, int range, QuestArrow arrow ) : base( TimeSpan.FromSeconds( 0.25 ), TimeSpan.FromSeconds( 2.5 ) )
     {
       m_From = from;
       m_Target = target;
       m_Range = range;

       m_Arrow = arrow;
       pm = (PlayerMobile) m_From;

       if ( AllowCondizioni( m_From, target ) )
         lastKnownCond = getCondition( target );
       else
         lastKnownCond = -1;

       condDist = Math.Sqrt( (Math.Abs( m_From.X - target.X ))^2 + (Math.Abs( m_From.Y - target.Y ))^2 );
      
     }

     protected override void OnTick()
     {
       if ( !m_Arrow.Running )
       {
         Stop();
         return;
       }
       else if (this.m_From.NetState == null || this.m_From.Deleted || this.m_Target.Deleted || this.m_From.Map != this.m_Target.Map || !this.m_From.InRange(this.m_Target, this.m_Range) || this.m_Target is Mobile && (((Mobile)this.m_Target).Hidden && ((Mobile)this.m_Target).AccessLevel > this.m_From.AccessLevel) || beforerun > 60)
       {
         m_From.Send( new CancelArrow() );
         m_From.SendLocalizedMessage( 503177 ); // You have lost your quarry.


         Tracking.ClearTrackingInfo( m_From );

         m_From.CloseGump( typeof( TrackInfoGump ) );

         Stop();
         return;
       }
      
       if (!m_From.InRange(m_Target, m_Range / 2) && !isescaping)
       {
         isescaping = true;
         m_From.SendMessage ("Le tracce si fanno poco visibili, fatichi a seguirle...");
         beforerun = 0;
         lastKnownCond = -1;
       }

       if (!m_From.InRange(m_Target, m_Range / 2) && isescaping && beforerun <= 60)
       {
         if (pm.ClasseType == ClasseType.Rogue)
           beforerun +=2;
         else
         {
           beforerun += 3;
         }
       }

       if (m_From.InRange(m_Target, m_Range / 2) && isescaping)
       {
         isescaping = false;
         m_From.SendMessage ("Ritrovi la pista");
         beforerun = 0;
       }
      

       if ( m_LastX != m_Target.X || m_LastY != m_Target.Y )
       {
         if ( Math.Sqrt( (Math.Abs( m_From.X - m_Target.X ))^2 + (Math.Abs( m_From.Y - m_Target.Y ))^2 ) < condDist && AllowCondizioni( m_From, m_Target ) )
           lastKnownCond = getCondition( m_Target );

         m_LastX = m_Target.X;
         m_LastY = m_Target.Y;

         m_Arrow.Update( m_LastX, m_LastY );
       }

       m_From.CloseGump( typeof( TrackInfoGump ) );

       if ( AllowCondizioni( m_From, m_Target ) )
       {
         m_From.SendGump( new TrackInfoGump( m_From, m_Target, lastKnownCond, getDistanza( m_From, m_Target, m_Range ) ) );
       }
       else
         m_From.SendGump( new TrackInfoGump( m_From, m_Target, -1, getDistanza( m_From, m_Target, m_Range ) ) );
     }
   }
}
I think I'm wrong in pointing out the closing of the gump as well as the arrow, but honestly I can not fix
 
Last edited by a moderator:
Code:
            foreach (Mobile animale in pm.GetMobilesInRange(4))
            {
                // Ghosts can no longer be tracked
                if (animale.Alive && animale is BaseCreature)
                {
                    if (((BaseCreature)animale).Controlled)
                        listino.Add(animale);
                }
            }

that check not work correctly, becouse BaseCreature always Alive == true while IsBonded.
It turns out that you track killed the bonded animals the same way.

and this maybe wrong:
Code:
            if (pm.Hidden == true)
            {
                if (pm.ClasseType == ClasseType.Rogue)
                    range -= 10;
                else if (pm.ClasseType == ClasseType.Ranger)
                    range -= 20;
                else
                    range -= 30;
            }
What happens if you have negative range ?

Perhaps you have after the death of the characters somewhere moved? For example, as is the case with Young characters, then your calculations for which then sent a tracking package may be incorrect, which can also be reduced to the crush of the client.

To understand, you need to know at least the exact ID of the package, which falls client. I can also advise you to start the server in debug mode and step by step monitor at what stage the tracking code will cause the client to fall.
 
CancelArrow packet provokes a crash.
You need change it:
Code:
              m_From.Send( new CancelArrow() );
                m_Arrow.Stop();
                m_From.SendLocalizedMessage( 503177 ); // You have lost your quarry.

                Tracking.ClearTrackingInfo( m_From );

                m_From.CloseGump( typeof( TrackInfoGump ) );

                Stop();
                return;
to:
Code:
                this.m_Arrow.Stop();
                this.Stop();
 m_From.CloseGump(typeof( TrackInfoGump ));
                return;
After that, the OnStop() method is called automatically, which you tried to do manually again.
Code:
        public override void OnStop()
        {
            m_Timer.Stop();

            if ( m_From != null )
            {
                Tracking.ClearTrackingInfo( m_From );

                m_From.SendLocalizedMessage( 503177 ); // You have lost your quarry.
            }
        }
 
Last edited:
Back