ModernUO/Scripts/Skills/Tracking.cs
asayre ce54fe8635 Bug fix for :
skillcaps and things that exceed it
Possible threading issue
Addition of Generic FindItemsByType  - List<T> findItemsByType<T>()
Change to make polymorph not have a timer and instead a toggle skill
KiAttack no longer works with ranged weapons
Poison strike speed and damage changed
Necro spells now affected by FC
Must have atleast 50 weapon skill if no shield equipped to use Evasion
Stalking bonus capped at 10 + skill/10
Stalking bonus now Clears
Bugfix w/Guilds
Crashguard Exception message moved closer to the top of the file.
Character creation of Pallys and necros using advanced skills now gives skill items 
Honor no longer works on Players
Pre-ML area HitArea attacks nolonger require LoS
Serialization fix for BladeOfTheRighteous
RidingSwipe now has paralyzation immunity as with NerveStrike and ParaBlow
AnkhEast renamed to AnkhNorth
LeggingsOfBane no longer have 510 HP
ElvenWashBasinEastAddon Fixed
AnsellaGryen won't be renamed each time the server Restarts
DiseasedCats are properly named
Localization fixes in DefBlacksmithy
BearMasks/DearMAsks and things that extend from them now can be repaired
2006-08-19 23:24:47 +00:00

404 lines
No EOL
10 KiB
C#

using System;
using System.Collections.Generic;
using Server;
using Server.Gumps;
using Server.Network;
using Server.Spells.Necromancy;
using Server.Spells;
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 )
{
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 Dictionary<Mobile, TrackingInfo> m_Table = new Dictionary<Mobile, TrackingInfo>();
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 )
{
TrackingInfo info = null;
m_Table.TryGetValue( tracker, out info );
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<Mobile>
{
private Mobile m_From;
public InternalSorter( Mobile from )
{
m_From = from;
}
public int Compare( Mobile x, Mobile y )
{
if ( x == null && y == null )
return 0;
else if ( x == null )
return -1;
else if ( y == null )
return 1;
return m_From.GetDistanceToSqrt( x ).CompareTo( m_From.GetDistanceToSqrt( y ) );
}
}
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 / 10);
List<Mobile> list = new List<Mobile>();
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 ) )
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 )
{
if ( !Core.AOS || !m.Player )
return true;
int tracking = from.Skills[SkillName.Tracking].Fixed;
int detectHidden = from.Skills[SkillName.DetectHidden].Fixed;
if( Core.ML && m.Race == Race.Elf )
tracking /= 2; //The 'Guide' says that it requires twice as Much tracking SKILL to track an elf. Not the total difficulty to track.
int hiding = m.Skills[SkillName.Hiding].Fixed;
int stealth = m.Skills[SkillName.Stealth].Fixed;
int divisor = hiding + stealth;
// Necromancy forms affect tracking difficulty
if ( TransformationSpell.UnderTransformation( m, typeof( HorrificBeastSpell ) ) )
divisor -= 200;
else if ( TransformationSpell.UnderTransformation( m, typeof( VampiricEmbraceSpell ) ) && divisor < 500 )
divisor = 500;
else if ( TransformationSpell.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 List<Mobile> m_List;
private TrackWhoGump( Mobile from, List<Mobile> 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 = list[i];
AddItem( 20 + ((i % 4) * 100), 20 + ((i / 4) * 155), ShrinkTable.Lookup( m ) );
AddButton( 20 + ((i % 4) * 100), 130 + ((i / 4) * 155), 4005, 4007, i + 1, GumpButtonType.Reply, 0 );
if ( m.Name != null )
AddHtml( 20 + ((i % 4) * 100), 90 + ((i / 4) * 155), 90, 40, m.Name, 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 = 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 )
{
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 TrackTimer : Timer
{
private Mobile m_From, m_Target;
private int m_Range;
private int m_LastX, m_LastY;
private QuestArrow m_Arrow;
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;
}
protected override void OnTick()
{
if ( !m_Arrow.Running )
{
Stop();
return;
}
else if ( m_From.NetState == null || m_From.Deleted || m_Target.Deleted || m_From.Map != m_Target.Map || !m_From.InRange( m_Target, m_Range ) )
{
m_From.Send( new CancelArrow() );
m_From.SendLocalizedMessage( 503177 ); // You have lost your quarry.
Tracking.ClearTrackingInfo( m_From );
Stop();
return;
}
if ( m_LastX != m_Target.X || m_LastY != m_Target.Y )
{
m_LastX = m_Target.X;
m_LastY = m_Target.Y;
m_Arrow.Update( m_LastX, m_LastY );
}
}
}
}