This commit is contained in:
commit
47711d616e
2644 changed files with 479454 additions and 0 deletions
594
Scripts/Mobiles/Townfolk/BaseEscortable.cs
Normal file
594
Scripts/Mobiles/Townfolk/BaseEscortable.cs
Normal file
|
|
@ -0,0 +1,594 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Server;
|
||||
using Server.Items;
|
||||
using Server.Network;
|
||||
using Server.ContextMenus;
|
||||
using EDI = Server.Mobiles.EscortDestinationInfo;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class BaseEscortable : BaseCreature
|
||||
{
|
||||
private EDI m_Destination;
|
||||
private string m_DestinationString;
|
||||
|
||||
private DateTime m_DeleteTime;
|
||||
private Timer m_DeleteTimer;
|
||||
|
||||
public override bool Commandable{ get{ return false; } } // Our master cannot boss us around!
|
||||
|
||||
[CommandProperty( AccessLevel.GameMaster )]
|
||||
public string Destination
|
||||
{
|
||||
get{ return m_Destination == null ? null : m_Destination.Name; }
|
||||
set{ m_DestinationString = value; m_Destination = EDI.Find( value ); }
|
||||
}
|
||||
|
||||
private static string[] m_TownNames = new string[]
|
||||
{
|
||||
"Cove", "Britain", "Jhelom",
|
||||
"Minoc", "Ocllo", "Trinsic",
|
||||
"Vesper", "Yew", "Skara Brae",
|
||||
"Nujel'm", "Moonglow", "Magincia"
|
||||
};
|
||||
|
||||
[Constructable]
|
||||
public BaseEscortable() : base( AIType.AI_Melee, FightMode.Aggressor, 22, 1, 0.2, 1.0 )
|
||||
{
|
||||
InitBody();
|
||||
InitOutfit();
|
||||
}
|
||||
|
||||
public virtual void InitBody()
|
||||
{
|
||||
SetStr( 90, 100 );
|
||||
SetDex( 90, 100 );
|
||||
SetInt( 15, 25 );
|
||||
|
||||
Hue = Utility.RandomSkinHue();
|
||||
|
||||
if ( Female = Utility.RandomBool() )
|
||||
{
|
||||
Body = 401;
|
||||
Name = NameList.RandomName( "female" );
|
||||
}
|
||||
else
|
||||
{
|
||||
Body = 400;
|
||||
Name = NameList.RandomName( "male" );
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void InitOutfit()
|
||||
{
|
||||
AddItem( new FancyShirt( Utility.RandomNeutralHue() ) );
|
||||
AddItem( new ShortPants( Utility.RandomNeutralHue() ) );
|
||||
AddItem( new Boots( Utility.RandomNeutralHue() ) );
|
||||
|
||||
Utility.AssignRandomHair( this );
|
||||
|
||||
PackGold( 200, 250 );
|
||||
}
|
||||
|
||||
public virtual bool SayDestinationTo( Mobile m )
|
||||
{
|
||||
EDI dest = GetDestination();
|
||||
|
||||
if ( dest == null || !m.Alive )
|
||||
return false;
|
||||
|
||||
Mobile escorter = GetEscorter();
|
||||
|
||||
if ( escorter == null )
|
||||
{
|
||||
Say( "I am looking to go to {0}, will you take me?", (dest.Name == "Ocllo" && m.Map == Map.Trammel) ? "Haven" : dest.Name );
|
||||
return true;
|
||||
}
|
||||
else if ( escorter == m )
|
||||
{
|
||||
Say( "Lead on! Payment will be made when we arrive in {0}.", (dest.Name == "Ocllo" && m.Map == Map.Trammel) ? "Haven" : dest.Name );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Hashtable m_EscortTable = new Hashtable();
|
||||
|
||||
public static Hashtable EscortTable
|
||||
{
|
||||
get{ return m_EscortTable; }
|
||||
}
|
||||
|
||||
private static TimeSpan m_EscortDelay = TimeSpan.FromMinutes( 5.0 );
|
||||
|
||||
public virtual bool AcceptEscorter( Mobile m )
|
||||
{
|
||||
EDI dest = GetDestination();
|
||||
|
||||
if ( dest == null )
|
||||
return false;
|
||||
|
||||
Mobile escorter = GetEscorter();
|
||||
|
||||
if ( escorter != null || !m.Alive )
|
||||
return false;
|
||||
|
||||
BaseEscortable escortable = (BaseEscortable)m_EscortTable[m];
|
||||
|
||||
if ( escortable != null && !escortable.Deleted && escortable.GetEscorter() == m )
|
||||
{
|
||||
Say( "I see you already have an escort." );
|
||||
return false;
|
||||
}
|
||||
else if ( m is PlayerMobile && (((PlayerMobile)m).LastEscortTime + m_EscortDelay) >= DateTime.Now )
|
||||
{
|
||||
int minutes = (int)Math.Ceiling( ((((PlayerMobile)m).LastEscortTime + m_EscortDelay) - DateTime.Now).TotalMinutes );
|
||||
|
||||
Say( "You must rest {0} minute{1} before we set out on this journey.", minutes, minutes == 1 ? "" : "s" );
|
||||
return false;
|
||||
}
|
||||
else if ( SetControlMaster( m ) )
|
||||
{
|
||||
m_LastSeenEscorter = DateTime.Now;
|
||||
|
||||
if ( m is PlayerMobile )
|
||||
((PlayerMobile)m).LastEscortTime = DateTime.Now;
|
||||
|
||||
Say( "Lead on! Payment will be made when we arrive in {0}.", (dest.Name == "Ocllo" && m.Map == Map.Trammel) ? "Haven" : dest.Name );
|
||||
m_EscortTable[m] = this;
|
||||
StartFollow();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool HandlesOnSpeech( Mobile from )
|
||||
{
|
||||
if ( from.InRange( this.Location, 3 ) )
|
||||
return true;
|
||||
|
||||
return base.HandlesOnSpeech( from );
|
||||
}
|
||||
|
||||
public override void OnSpeech( SpeechEventArgs e )
|
||||
{
|
||||
base.OnSpeech( e );
|
||||
|
||||
EDI dest = GetDestination();
|
||||
|
||||
if ( dest != null && !e.Handled && e.Mobile.InRange( this.Location, 3 ) )
|
||||
{
|
||||
if ( e.HasKeyword( 0x1D ) ) // *destination*
|
||||
e.Handled = SayDestinationTo( e.Mobile );
|
||||
else if ( e.HasKeyword( 0x1E ) ) // *i will take thee*
|
||||
e.Handled = AcceptEscorter( e.Mobile );
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
if ( m_DeleteTimer != null )
|
||||
m_DeleteTimer.Stop();
|
||||
|
||||
m_DeleteTimer = null;
|
||||
|
||||
base.OnAfterDelete();
|
||||
}
|
||||
|
||||
public override void OnThink()
|
||||
{
|
||||
base.OnThink();
|
||||
CheckAtDestination();
|
||||
}
|
||||
|
||||
protected override bool OnMove( Direction d )
|
||||
{
|
||||
if ( !base.OnMove( d ) )
|
||||
return false;
|
||||
|
||||
CheckAtDestination();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void StartFollow()
|
||||
{
|
||||
StartFollow( GetEscorter() );
|
||||
}
|
||||
|
||||
public virtual void StartFollow( Mobile escorter )
|
||||
{
|
||||
if ( escorter == null )
|
||||
return;
|
||||
|
||||
ActiveSpeed = 0.1;
|
||||
PassiveSpeed = 0.2;
|
||||
|
||||
ControlOrder = OrderType.Follow;
|
||||
ControlTarget = escorter;
|
||||
|
||||
CurrentSpeed = 0.1;
|
||||
}
|
||||
|
||||
public virtual void StopFollow()
|
||||
{
|
||||
ActiveSpeed = 0.2;
|
||||
PassiveSpeed = 1.0;
|
||||
|
||||
ControlOrder = OrderType.None;
|
||||
ControlTarget = null;
|
||||
|
||||
CurrentSpeed = 1.0;
|
||||
}
|
||||
|
||||
private DateTime m_LastSeenEscorter;
|
||||
|
||||
public virtual Mobile GetEscorter()
|
||||
{
|
||||
if ( !Controlled )
|
||||
return null;
|
||||
|
||||
Mobile master = ControlMaster;
|
||||
|
||||
if ( master == null )
|
||||
return null;
|
||||
|
||||
if ( master.Deleted || master.Map != this.Map || !master.InRange( Location, 30 ) || !master.Alive )
|
||||
{
|
||||
StopFollow();
|
||||
|
||||
TimeSpan lastSeenDelay = DateTime.Now - m_LastSeenEscorter;
|
||||
|
||||
if ( lastSeenDelay >= TimeSpan.FromMinutes( 2.0 ) )
|
||||
{
|
||||
master.SendLocalizedMessage( 1042473 ); // You have lost the person you were escorting.
|
||||
Say( 1005653 ); // Hmmm. I seem to have lost my master.
|
||||
|
||||
SetControlMaster( null );
|
||||
m_EscortTable.Remove( master );
|
||||
|
||||
Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerCallback( Delete ) );
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
ControlOrder = OrderType.Stay;
|
||||
return master;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ControlOrder != OrderType.Follow )
|
||||
StartFollow( master );
|
||||
|
||||
m_LastSeenEscorter = DateTime.Now;
|
||||
return master;
|
||||
}
|
||||
|
||||
public virtual void BeginDelete()
|
||||
{
|
||||
if ( m_DeleteTimer != null )
|
||||
m_DeleteTimer.Stop();
|
||||
|
||||
m_DeleteTime = DateTime.Now + TimeSpan.FromSeconds( 30.0 );
|
||||
|
||||
m_DeleteTimer = new DeleteTimer( this, m_DeleteTime - DateTime.Now );
|
||||
m_DeleteTimer.Start();
|
||||
}
|
||||
|
||||
public virtual bool CheckAtDestination()
|
||||
{
|
||||
EDI dest = GetDestination();
|
||||
|
||||
if ( dest == null )
|
||||
return false;
|
||||
|
||||
Mobile escorter = GetEscorter();
|
||||
|
||||
if ( escorter == null )
|
||||
return false;
|
||||
|
||||
if ( dest.Contains( Location ) )
|
||||
{
|
||||
Say( 1042809, escorter.Name ); // We have arrived! I thank thee, ~1_PLAYER_NAME~! I have no further need of thy services. Here is thy pay.
|
||||
|
||||
// not going anywhere
|
||||
m_Destination = null;
|
||||
m_DestinationString = null;
|
||||
|
||||
Container cont = escorter.Backpack;
|
||||
|
||||
if ( cont == null )
|
||||
cont = escorter.BankBox;
|
||||
|
||||
Gold gold = new Gold( 500, 1000 );
|
||||
|
||||
if ( cont == null || !cont.TryDropItem( escorter, gold, false ) )
|
||||
gold.MoveToWorld( escorter.Location, escorter.Map );
|
||||
|
||||
StopFollow();
|
||||
SetControlMaster( null );
|
||||
m_EscortTable.Remove( escorter );
|
||||
BeginDelete();
|
||||
|
||||
Misc.Titles.AwardFame( escorter, 10, true );
|
||||
|
||||
bool gainedPath = false;
|
||||
|
||||
PlayerMobile pm = escorter as PlayerMobile;
|
||||
|
||||
if ( pm != null )
|
||||
{
|
||||
if ( pm.CompassionGains > 0 && DateTime.Now > pm.NextCompassionDay )
|
||||
{
|
||||
pm.NextCompassionDay = DateTime.MinValue;
|
||||
pm.CompassionGains = 0;
|
||||
}
|
||||
|
||||
if ( pm.CompassionGains >= 5 ) // have already gained 5 times in one day, can gain no more
|
||||
{
|
||||
pm.SendLocalizedMessage( 1053004 ); // You must wait about a day before you can gain in compassion again.
|
||||
}
|
||||
else if ( VirtueHelper.Award( pm, VirtueName.Compassion, 200, ref gainedPath ) )
|
||||
{
|
||||
if ( gainedPath )
|
||||
pm.SendLocalizedMessage( 1053005 ); // You have achieved a path in compassion!
|
||||
else
|
||||
pm.SendLocalizedMessage( 1053002 ); // You have gained in compassion.
|
||||
|
||||
pm.NextCompassionDay = DateTime.Now + TimeSpan.FromDays( 1.0 ); // in one day CompassionGains gets reset to 0
|
||||
++pm.CompassionGains;
|
||||
}
|
||||
else
|
||||
{
|
||||
pm.SendLocalizedMessage( 1053003 ); // You have achieved the highest path of compassion and can no longer gain any further.
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public BaseEscortable( Serial serial ) : base( serial )
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize( GenericWriter writer )
|
||||
{
|
||||
base.Serialize( writer );
|
||||
|
||||
writer.Write( (int) 0 ); // version
|
||||
|
||||
EDI dest = GetDestination();
|
||||
|
||||
writer.Write( dest != null );
|
||||
|
||||
if ( dest != null )
|
||||
writer.Write( dest.Name );
|
||||
|
||||
writer.Write( m_DeleteTimer != null );
|
||||
|
||||
if ( m_DeleteTimer != null )
|
||||
writer.WriteDeltaTime( m_DeleteTime );
|
||||
}
|
||||
|
||||
public override void Deserialize( GenericReader reader )
|
||||
{
|
||||
base.Deserialize( reader );
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
if ( reader.ReadBool() )
|
||||
m_DestinationString = reader.ReadString(); // NOTE: We cannot EDI.Find here, regions have not yet been loaded :-(
|
||||
|
||||
if ( reader.ReadBool() )
|
||||
{
|
||||
m_DeleteTime = reader.ReadDeltaTime();
|
||||
m_DeleteTimer = new DeleteTimer( this, m_DeleteTime - DateTime.Now );
|
||||
m_DeleteTimer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanBeRenamedBy( Mobile from )
|
||||
{
|
||||
return ( from.AccessLevel >= AccessLevel.GameMaster );
|
||||
}
|
||||
|
||||
public override void AddCustomContextEntries( Mobile from, List<ContextMenuEntry> list )
|
||||
{
|
||||
EDI dest = GetDestination();
|
||||
|
||||
if ( dest != null && from.Alive )
|
||||
{
|
||||
Mobile escorter = GetEscorter();
|
||||
|
||||
if ( escorter == null || escorter == from )
|
||||
list.Add( new AskDestinationEntry( this, from ) );
|
||||
|
||||
if ( escorter == null )
|
||||
list.Add( new AcceptEscortEntry( this, from ) );
|
||||
else if ( escorter == from )
|
||||
list.Add( new AbandonEscortEntry( this, from ) );
|
||||
}
|
||||
|
||||
base.AddCustomContextEntries( from, list );
|
||||
}
|
||||
|
||||
public virtual string[] GetPossibleDestinations()
|
||||
{
|
||||
return m_TownNames;
|
||||
}
|
||||
|
||||
public virtual string PickRandomDestination()
|
||||
{
|
||||
if ( Map.Felucca.Regions.Count == 0 || Map == null || Map == Map.Internal || Location == Point3D.Zero )
|
||||
return null; // Not yet fully initialized
|
||||
|
||||
string[] possible = GetPossibleDestinations();
|
||||
string picked = null;
|
||||
|
||||
while ( picked == null )
|
||||
{
|
||||
picked = possible[Utility.Random( possible.Length )];
|
||||
EDI test = EDI.Find( picked );
|
||||
|
||||
if ( test != null && test.Contains( Location ) )
|
||||
picked = null;
|
||||
}
|
||||
|
||||
return picked;
|
||||
}
|
||||
|
||||
public EDI GetDestination()
|
||||
{
|
||||
if ( m_DestinationString == null && m_DeleteTimer == null )
|
||||
m_DestinationString = PickRandomDestination();
|
||||
|
||||
if ( m_Destination != null && m_Destination.Name == m_DestinationString )
|
||||
return m_Destination;
|
||||
|
||||
if ( Map.Felucca.Regions.Count > 0 )
|
||||
return ( m_Destination = EDI.Find( m_DestinationString ) );
|
||||
|
||||
return ( m_Destination = null );
|
||||
}
|
||||
|
||||
private class DeleteTimer : Timer
|
||||
{
|
||||
private Mobile m_Mobile;
|
||||
|
||||
public DeleteTimer( Mobile m, TimeSpan delay ) : base( delay )
|
||||
{
|
||||
m_Mobile = m;
|
||||
|
||||
Priority = TimerPriority.OneSecond;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
m_Mobile.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class EscortDestinationInfo
|
||||
{
|
||||
private string m_Name;
|
||||
private Region m_Region;
|
||||
//private Rectangle2D[] m_Bounds;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get{ return m_Name; }
|
||||
}
|
||||
|
||||
public Region Region
|
||||
{
|
||||
get{ return m_Region; }
|
||||
}
|
||||
|
||||
/*public Rectangle2D[] Bounds
|
||||
{
|
||||
get{ return m_Bounds; }
|
||||
}*/
|
||||
|
||||
public bool Contains( Point3D p )
|
||||
{
|
||||
return m_Region.Contains( p );
|
||||
}
|
||||
|
||||
public EscortDestinationInfo( string name, Region region )
|
||||
{
|
||||
m_Name = name;
|
||||
m_Region = region;
|
||||
}
|
||||
|
||||
private static Hashtable m_Table;
|
||||
|
||||
public static void LoadTable()
|
||||
{
|
||||
ICollection list = Map.Felucca.Regions.Values;
|
||||
|
||||
if ( list.Count == 0 )
|
||||
return;
|
||||
|
||||
m_Table = new Hashtable();
|
||||
|
||||
foreach ( Region r in list )
|
||||
{
|
||||
if ( r.Name == null )
|
||||
continue;
|
||||
|
||||
if ( r is Regions.DungeonRegion || r is Regions.TownRegion )
|
||||
m_Table[r.Name] = new EscortDestinationInfo( r.Name, r );
|
||||
}
|
||||
}
|
||||
|
||||
public static EDI Find( string name )
|
||||
{
|
||||
if ( m_Table == null )
|
||||
LoadTable();
|
||||
|
||||
if ( name == null || m_Table == null )
|
||||
return null;
|
||||
|
||||
return (EscortDestinationInfo)m_Table[name];
|
||||
}
|
||||
}
|
||||
|
||||
public class AskDestinationEntry : ContextMenuEntry
|
||||
{
|
||||
private BaseEscortable m_Mobile;
|
||||
private Mobile m_From;
|
||||
|
||||
public AskDestinationEntry( BaseEscortable m, Mobile from ) : base( 6100, 3 )
|
||||
{
|
||||
m_Mobile = m;
|
||||
m_From = from;
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
m_Mobile.SayDestinationTo( m_From );
|
||||
}
|
||||
}
|
||||
|
||||
public class AcceptEscortEntry : ContextMenuEntry
|
||||
{
|
||||
private BaseEscortable m_Mobile;
|
||||
private Mobile m_From;
|
||||
|
||||
public AcceptEscortEntry( BaseEscortable m, Mobile from ) : base( 6101, 3 )
|
||||
{
|
||||
m_Mobile = m;
|
||||
m_From = from;
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
m_Mobile.AcceptEscorter( m_From );
|
||||
}
|
||||
}
|
||||
|
||||
public class AbandonEscortEntry : ContextMenuEntry
|
||||
{
|
||||
private BaseEscortable m_Mobile;
|
||||
private Mobile m_From;
|
||||
|
||||
public AbandonEscortEntry( BaseEscortable m, Mobile from ) : base( 6102, 3 )
|
||||
{
|
||||
m_Mobile = m;
|
||||
m_From = from;
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
m_Mobile.Delete(); // OSI just seems to delete instantly
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue