560 lines
No EOL
14 KiB
C#
560 lines
No EOL
14 KiB
C#
using System;
|
|
using System.Text;
|
|
using System.Collections.Generic;
|
|
using Server;
|
|
using Server.Prompts;
|
|
using Server.Gumps;
|
|
using Server.Network;
|
|
using Server.Items;
|
|
using Server.Misc;
|
|
using Server.Commands;
|
|
|
|
namespace Server.Mobiles
|
|
{
|
|
public interface ITownCrierEntryList
|
|
{
|
|
List<TownCrierEntry> Entries{ get; }
|
|
TownCrierEntry GetRandomEntry();
|
|
TownCrierEntry AddEntry( string[] lines, TimeSpan duration );
|
|
void RemoveEntry( TownCrierEntry entry );
|
|
}
|
|
|
|
public class GlobalTownCrierEntryList : ITownCrierEntryList
|
|
{
|
|
private static GlobalTownCrierEntryList m_Instance;
|
|
|
|
public static void Initialize()
|
|
{
|
|
CommandSystem.Register( "TownCriers", AccessLevel.GameMaster, new CommandEventHandler( TownCriers_OnCommand ) );
|
|
}
|
|
|
|
[Usage( "TownCriers" )]
|
|
[Description( "Manages the global town crier list." )]
|
|
public static void TownCriers_OnCommand( CommandEventArgs e )
|
|
{
|
|
e.Mobile.SendGump( new TownCrierGump( e.Mobile, Instance ) );
|
|
}
|
|
|
|
public static GlobalTownCrierEntryList Instance
|
|
{
|
|
get
|
|
{
|
|
if ( m_Instance == null )
|
|
m_Instance = new GlobalTownCrierEntryList();
|
|
|
|
return m_Instance;
|
|
}
|
|
}
|
|
|
|
public bool IsEmpty{ get{ return ( m_Entries == null || m_Entries.Count == 0 ); } }
|
|
|
|
public GlobalTownCrierEntryList()
|
|
{
|
|
}
|
|
|
|
private List<TownCrierEntry> m_Entries;
|
|
|
|
public List<TownCrierEntry> Entries
|
|
{
|
|
get{ return m_Entries; }
|
|
}
|
|
|
|
public TownCrierEntry GetRandomEntry()
|
|
{
|
|
if ( m_Entries == null || m_Entries.Count == 0 )
|
|
return null;
|
|
|
|
for ( int i = m_Entries.Count - 1; m_Entries != null && i >= 0; --i )
|
|
{
|
|
if ( i >= m_Entries.Count )
|
|
continue;
|
|
|
|
TownCrierEntry tce = m_Entries[i];
|
|
|
|
if ( tce.Expired )
|
|
RemoveEntry( tce );
|
|
}
|
|
|
|
if ( m_Entries == null || m_Entries.Count == 0 )
|
|
return null;
|
|
|
|
return m_Entries[Utility.Random( m_Entries.Count )];
|
|
}
|
|
|
|
public TownCrierEntry AddEntry( string[] lines, TimeSpan duration )
|
|
{
|
|
if ( m_Entries == null )
|
|
m_Entries = new List<TownCrierEntry>();
|
|
|
|
TownCrierEntry tce = new TownCrierEntry( lines, duration );
|
|
|
|
m_Entries.Add( tce );
|
|
|
|
List<TownCrier> instances = TownCrier.Instances;
|
|
|
|
for ( int i = 0; i < instances.Count; ++i )
|
|
instances[i].ForceBeginAutoShout();
|
|
|
|
return tce;
|
|
}
|
|
|
|
public void RemoveEntry( TownCrierEntry tce )
|
|
{
|
|
if ( m_Entries == null )
|
|
return;
|
|
|
|
m_Entries.Remove( tce );
|
|
|
|
if ( m_Entries.Count == 0 )
|
|
m_Entries = null;
|
|
}
|
|
}
|
|
|
|
public class TownCrierEntry
|
|
{
|
|
private string[] m_Lines;
|
|
private DateTime m_ExpireTime;
|
|
|
|
public string[] Lines{ get{ return m_Lines; } }
|
|
public DateTime ExpireTime{ get{ return m_ExpireTime; } }
|
|
public bool Expired{ get{ return ( DateTime.Now >= m_ExpireTime ); } }
|
|
|
|
public TownCrierEntry( string[] lines, TimeSpan duration )
|
|
{
|
|
m_Lines = lines;
|
|
|
|
if ( duration < TimeSpan.Zero )
|
|
duration = TimeSpan.Zero;
|
|
else if ( duration > TimeSpan.FromDays( 365.0 ) )
|
|
duration = TimeSpan.FromDays( 365.0 );
|
|
|
|
m_ExpireTime = DateTime.Now + duration;
|
|
}
|
|
}
|
|
|
|
public class TownCrierDurationPrompt : Prompt
|
|
{
|
|
private ITownCrierEntryList m_Owner;
|
|
|
|
public TownCrierDurationPrompt( ITownCrierEntryList owner )
|
|
{
|
|
m_Owner = owner;
|
|
}
|
|
|
|
public override void OnResponse( Mobile from, string text )
|
|
{
|
|
TimeSpan ts;
|
|
|
|
if( !TimeSpan.TryParse( text, out ts ) )
|
|
{
|
|
from.SendMessage( "Value was not properly formatted. Use: <hours:minutes:seconds>" );
|
|
from.SendGump( new TownCrierGump( from, m_Owner ) );
|
|
return;
|
|
}
|
|
|
|
if ( ts < TimeSpan.Zero )
|
|
ts = TimeSpan.Zero;
|
|
|
|
from.SendMessage( "Duration set to: {0}", ts );
|
|
from.SendMessage( "Enter the first line to shout:" );
|
|
|
|
from.Prompt = new TownCrierLinesPrompt( m_Owner, null, new List<String>(), ts );
|
|
}
|
|
|
|
public override void OnCancel( Mobile from )
|
|
{
|
|
from.SendLocalizedMessage( 502980 ); // Message entry cancelled.
|
|
from.SendGump( new TownCrierGump( from, m_Owner ) );
|
|
}
|
|
}
|
|
|
|
public class TownCrierLinesPrompt : Prompt
|
|
{
|
|
private ITownCrierEntryList m_Owner;
|
|
private TownCrierEntry m_Entry;
|
|
private List<String> m_Lines;
|
|
private TimeSpan m_Duration;
|
|
|
|
public TownCrierLinesPrompt( ITownCrierEntryList owner, TownCrierEntry entry, List<String> lines, TimeSpan duration )
|
|
{
|
|
m_Owner = owner;
|
|
m_Entry = entry;
|
|
m_Lines = lines;
|
|
m_Duration = duration;
|
|
}
|
|
|
|
public override void OnResponse( Mobile from, string text )
|
|
{
|
|
m_Lines.Add( text );
|
|
|
|
from.SendMessage( "Enter the next line to shout, or press <ESC> if the message is finished." );
|
|
from.Prompt = new TownCrierLinesPrompt( m_Owner, m_Entry, m_Lines, m_Duration );
|
|
}
|
|
|
|
public override void OnCancel( Mobile from )
|
|
{
|
|
if ( m_Entry != null )
|
|
m_Owner.RemoveEntry( m_Entry );
|
|
|
|
if ( m_Lines.Count > 0 )
|
|
{
|
|
m_Owner.AddEntry( m_Lines.ToArray(), m_Duration );
|
|
from.SendMessage( "Message has been set." );
|
|
}
|
|
else
|
|
{
|
|
if ( m_Entry != null )
|
|
from.SendMessage( "Message deleted." );
|
|
else
|
|
from.SendLocalizedMessage( 502980 ); // Message entry cancelled.
|
|
}
|
|
|
|
from.SendGump( new TownCrierGump( from, m_Owner ) );
|
|
}
|
|
}
|
|
|
|
public class TownCrierGump : Gump
|
|
{
|
|
private Mobile m_From;
|
|
private ITownCrierEntryList m_Owner;
|
|
|
|
public override void OnResponse( NetState sender, RelayInfo info )
|
|
{
|
|
if ( info.ButtonID == 1 )
|
|
{
|
|
m_From.SendMessage( "Enter the duration for the new message. Format: <hours:minutes:seconds>" );
|
|
m_From.Prompt = new TownCrierDurationPrompt( m_Owner );
|
|
}
|
|
else if ( info.ButtonID > 1 )
|
|
{
|
|
List<TownCrierEntry> entries = m_Owner.Entries;
|
|
int index = info.ButtonID - 2;
|
|
|
|
if ( entries != null && index < entries.Count )
|
|
{
|
|
TownCrierEntry tce = entries[index];
|
|
TimeSpan ts = tce.ExpireTime - DateTime.Now;
|
|
|
|
if ( ts < TimeSpan.Zero )
|
|
ts = TimeSpan.Zero;
|
|
|
|
m_From.SendMessage( "Editing entry #{0}.", index + 1 );
|
|
m_From.SendMessage( "Enter the first line to shout:" );
|
|
m_From.Prompt = new TownCrierLinesPrompt( m_Owner, tce, new List<String>(), ts );
|
|
}
|
|
}
|
|
}
|
|
|
|
public TownCrierGump( Mobile from, ITownCrierEntryList owner ) : base( 50, 50 )
|
|
{
|
|
m_From = from;
|
|
m_Owner = owner;
|
|
|
|
from.CloseGump( typeof( TownCrierGump ) );
|
|
|
|
AddPage( 0 );
|
|
|
|
List<TownCrierEntry> entries = owner.Entries;
|
|
|
|
owner.GetRandomEntry(); // force expiration checks
|
|
|
|
int count = 0;
|
|
|
|
if ( entries != null )
|
|
count = entries.Count;
|
|
|
|
AddImageTiled( 0, 0, 300, 38 + (count == 0 ? 20 : (count * 85)), 0xA40 );
|
|
AddAlphaRegion( 1, 1, 298, 36 + (count == 0 ? 20 : (count * 85)) );
|
|
|
|
AddHtml( 8, 8, 300 - 8 - 30, 20, "<basefont color=#FFFFFF><center>TOWN CRIER MESSAGES</center></basefont>", false, false );
|
|
|
|
AddButton( 300 - 8 - 30, 8, 0xFAB, 0xFAD, 1, GumpButtonType.Reply, 0 );
|
|
|
|
if ( count == 0 )
|
|
{
|
|
AddHtml( 8, 30, 284, 20, "<basefont color=#FFFFFF>The crier has no news.</basefont>", false, false );
|
|
}
|
|
else
|
|
{
|
|
for ( int i = 0; i < entries.Count; ++i )
|
|
{
|
|
TownCrierEntry tce = (TownCrierEntry)entries[i];
|
|
|
|
TimeSpan toExpire = tce.ExpireTime - DateTime.Now;
|
|
|
|
if ( toExpire < TimeSpan.Zero )
|
|
toExpire = TimeSpan.Zero;
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
sb.Append( "[Expires: " );
|
|
|
|
if ( toExpire.TotalHours >= 1 )
|
|
{
|
|
sb.Append( (int)toExpire.TotalHours );
|
|
sb.Append( ':' );
|
|
sb.Append( toExpire.Minutes.ToString( "D2" ) );
|
|
}
|
|
else
|
|
{
|
|
sb.Append( toExpire.Minutes );
|
|
}
|
|
|
|
sb.Append( ':' );
|
|
sb.Append( toExpire.Seconds.ToString( "D2" ) );
|
|
|
|
sb.Append( "] " );
|
|
|
|
for ( int j = 0; j < tce.Lines.Length; ++j )
|
|
{
|
|
if ( j > 0 )
|
|
sb.Append( "<br>" );
|
|
|
|
sb.Append( tce.Lines[j] );
|
|
}
|
|
|
|
AddHtml( 8, 35 + (i * 85), 254, 80, sb.ToString(), true, true );
|
|
|
|
AddButton( 300 - 8 - 26, 35 + (i * 85), 0x15E1, 0x15E5, 2 + i, GumpButtonType.Reply, 0 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public class TownCrier : Mobile, ITownCrierEntryList
|
|
{
|
|
private List<TownCrierEntry> m_Entries;
|
|
private Timer m_NewsTimer;
|
|
private Timer m_AutoShoutTimer;
|
|
|
|
public List<TownCrierEntry> Entries
|
|
{
|
|
get{ return m_Entries; }
|
|
}
|
|
|
|
public TownCrierEntry GetRandomEntry()
|
|
{
|
|
if ( m_Entries == null || m_Entries.Count == 0 )
|
|
return GlobalTownCrierEntryList.Instance.GetRandomEntry();
|
|
|
|
for ( int i = m_Entries.Count - 1; m_Entries != null && i >= 0; --i )
|
|
{
|
|
if ( i >= m_Entries.Count )
|
|
continue;
|
|
|
|
TownCrierEntry tce = m_Entries[i];
|
|
|
|
if ( tce.Expired )
|
|
RemoveEntry( tce );
|
|
}
|
|
|
|
if ( m_Entries == null || m_Entries.Count == 0 )
|
|
return GlobalTownCrierEntryList.Instance.GetRandomEntry();
|
|
|
|
TownCrierEntry entry = GlobalTownCrierEntryList.Instance.GetRandomEntry();
|
|
|
|
if ( entry == null || Utility.RandomBool() )
|
|
entry = m_Entries[Utility.Random( m_Entries.Count )];
|
|
|
|
return entry;
|
|
}
|
|
|
|
public void ForceBeginAutoShout()
|
|
{
|
|
if ( m_AutoShoutTimer == null )
|
|
m_AutoShoutTimer = Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromMinutes( 1.0 ), new TimerCallback( AutoShout_Callback ) );
|
|
}
|
|
|
|
public TownCrierEntry AddEntry( string[] lines, TimeSpan duration )
|
|
{
|
|
if ( m_Entries == null )
|
|
m_Entries = new List<TownCrierEntry>();
|
|
|
|
TownCrierEntry tce = new TownCrierEntry( lines, duration );
|
|
|
|
m_Entries.Add( tce );
|
|
|
|
if ( m_AutoShoutTimer == null )
|
|
m_AutoShoutTimer = Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromMinutes( 1.0 ), new TimerCallback( AutoShout_Callback ) );
|
|
|
|
return tce;
|
|
}
|
|
|
|
public void RemoveEntry( TownCrierEntry tce )
|
|
{
|
|
if ( m_Entries == null )
|
|
return;
|
|
|
|
m_Entries.Remove( tce );
|
|
|
|
if ( m_Entries.Count == 0 )
|
|
m_Entries = null;
|
|
|
|
if ( m_Entries == null && GlobalTownCrierEntryList.Instance.IsEmpty )
|
|
{
|
|
if ( m_AutoShoutTimer != null )
|
|
m_AutoShoutTimer.Stop();
|
|
|
|
m_AutoShoutTimer = null;
|
|
}
|
|
}
|
|
|
|
private void AutoShout_Callback()
|
|
{
|
|
TownCrierEntry tce = GetRandomEntry();
|
|
|
|
if ( tce == null )
|
|
{
|
|
if ( m_AutoShoutTimer != null )
|
|
m_AutoShoutTimer.Stop();
|
|
|
|
m_AutoShoutTimer = null;
|
|
}
|
|
else if ( m_NewsTimer == null )
|
|
{
|
|
m_NewsTimer = Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 3.0 ), new TimerStateCallback( ShoutNews_Callback ), new object[]{ tce, 0 } );
|
|
|
|
PublicOverheadMessage( MessageType.Regular, 0x3B2, 502976 ); // Hear ye! Hear ye!
|
|
}
|
|
}
|
|
|
|
private void ShoutNews_Callback( object state )
|
|
{
|
|
object[] states = (object[])state;
|
|
TownCrierEntry tce = (TownCrierEntry)states[0];
|
|
int index = (int)states[1];
|
|
|
|
if ( index < 0 || index >= tce.Lines.Length )
|
|
{
|
|
if ( m_NewsTimer != null )
|
|
m_NewsTimer.Stop();
|
|
|
|
m_NewsTimer = null;
|
|
}
|
|
else
|
|
{
|
|
PublicOverheadMessage( MessageType.Regular, 0x3B2, false, tce.Lines[index] );
|
|
states[1] = index + 1;
|
|
}
|
|
}
|
|
|
|
public override void OnDoubleClick( Mobile from )
|
|
{
|
|
if ( from.AccessLevel >= AccessLevel.GameMaster )
|
|
from.SendGump( new TownCrierGump( from, this ) );
|
|
else
|
|
base.OnDoubleClick( from );
|
|
}
|
|
|
|
public override bool HandlesOnSpeech( Mobile from )
|
|
{
|
|
return ( m_NewsTimer == null && from.Alive && InRange( from, 12 ) );
|
|
}
|
|
|
|
public override void OnSpeech( SpeechEventArgs e )
|
|
{
|
|
if ( m_NewsTimer == null && e.HasKeyword( 0x30 ) && e.Mobile.Alive && InRange( e.Mobile, 12 ) ) // *news*
|
|
{
|
|
Direction = GetDirectionTo( e.Mobile );
|
|
|
|
TownCrierEntry tce = GetRandomEntry();
|
|
|
|
if ( tce == null )
|
|
{
|
|
PublicOverheadMessage( MessageType.Regular, 0x3B2, 1005643 ); // I have no news at this time.
|
|
}
|
|
else
|
|
{
|
|
m_NewsTimer = Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 3.0 ), new TimerStateCallback( ShoutNews_Callback ), new object[]{ tce, 0 } );
|
|
|
|
PublicOverheadMessage( MessageType.Regular, 0x3B2, 502978 ); // Some of the latest news!
|
|
}
|
|
}
|
|
}
|
|
|
|
private static List<TownCrier> m_Instances = new List<TownCrier>();
|
|
|
|
public static List<TownCrier> Instances
|
|
{
|
|
get{ return m_Instances; }
|
|
}
|
|
|
|
[Constructable]
|
|
public TownCrier()
|
|
{
|
|
m_Instances.Add( this );
|
|
|
|
InitStats( 100, 100, 25 );
|
|
|
|
Title = "the town crier";
|
|
Hue = Utility.RandomSkinHue();
|
|
Invulnerable = true;
|
|
|
|
NameHue = 0x35;
|
|
|
|
if ( this.Female = Utility.RandomBool() )
|
|
{
|
|
this.Body = 0x191;
|
|
this.Name = NameList.RandomName( "female" );
|
|
}
|
|
else
|
|
{
|
|
this.Body = 0x190;
|
|
this.Name = NameList.RandomName( "male" );
|
|
}
|
|
|
|
AddItem( new FancyShirt( Utility.RandomBlueHue() ) );
|
|
|
|
Item skirt;
|
|
|
|
switch ( Utility.Random( 2 ) )
|
|
{
|
|
case 0: skirt = new Skirt(); break;
|
|
default: case 1: skirt = new Kilt(); break;
|
|
}
|
|
|
|
skirt.Hue = Utility.RandomGreenHue();
|
|
|
|
AddItem( skirt );
|
|
|
|
AddItem( new FeatheredHat( Utility.RandomGreenHue() ) );
|
|
|
|
Item boots;
|
|
|
|
switch ( Utility.Random( 2 ) )
|
|
{
|
|
case 0: boots = new Boots(); break;
|
|
default: case 1: boots = new ThighBoots(); break;
|
|
}
|
|
|
|
AddItem( boots );
|
|
|
|
Utility.AssignRandomHair( this );
|
|
}
|
|
|
|
public override void OnDelete()
|
|
{
|
|
m_Instances.Remove( this );
|
|
base.OnDelete();
|
|
}
|
|
|
|
public TownCrier( Serial serial ) : base( serial )
|
|
{
|
|
m_Instances.Add( this );
|
|
}
|
|
|
|
public override void Serialize( GenericWriter writer )
|
|
{
|
|
base.Serialize( writer );
|
|
|
|
writer.Write( (int) 0 ); // version
|
|
}
|
|
|
|
public override void Deserialize( GenericReader reader )
|
|
{
|
|
base.Deserialize( reader );
|
|
|
|
int version = reader.ReadInt();
|
|
}
|
|
}
|
|
} |