ModernUO/Scripts/Items/Misc/BulletinBoards.cs
mark 177eb4c6ff Cleanup Expansions
WorldPacketSA should not be used yet. There is much more work to be done and that version has not been looked at in quite some time.
2010-06-17 07:11:43 +00:00

620 lines
No EOL
15 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Server;
using Server.Network;
namespace Server.Items
{
[Flipable( 0x1E5E, 0x1E5F )]
public class BulletinBoard : BaseBulletinBoard
{
[Constructable]
public BulletinBoard() : base( 0x1E5E )
{
}
public BulletinBoard( Serial serial ) : base( serial )
{
}
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();
}
}
public abstract class BaseBulletinBoard : Item
{
private string m_BoardName;
[CommandProperty( AccessLevel.GameMaster )]
public string BoardName
{
get{ return m_BoardName; }
set{ m_BoardName = value; }
}
public BaseBulletinBoard( int itemID ) : base( itemID )
{
m_BoardName = "bulletin board";
Movable = false;
}
// Threads will be removed six hours after the last post was made
private static TimeSpan ThreadDeletionTime = TimeSpan.FromHours( 6.0 );
// A player may only create a thread once every two minutes
private static TimeSpan ThreadCreateTime = TimeSpan.FromMinutes( 2.0 );
// A player may only reply once every thirty seconds
private static TimeSpan ThreadReplyTime = TimeSpan.FromSeconds( 30.0 );
public static bool CheckTime( DateTime time, TimeSpan range )
{
return (time + range) < DateTime.Now;
}
public static string FormatTS( TimeSpan ts )
{
int totalSeconds = (int)ts.TotalSeconds;
int seconds = totalSeconds % 60;
int minutes = totalSeconds / 60;
if ( minutes != 0 && seconds != 0 )
return String.Format( "{0} minute{1} and {2} second{3}", minutes, minutes==1?"":"s", seconds, seconds==1?"":"s" );
else if ( minutes != 0 )
return String.Format( "{0} minute{1}", minutes, minutes==1?"":"s" );
else
return String.Format( "{0} second{1}", seconds, seconds==1?"":"s" );
}
public virtual void Cleanup()
{
List<Item> items = this.Items;
for ( int i = items.Count - 1; i >= 0; --i )
{
if ( i >= items.Count )
continue;
BulletinMessage msg = items[i] as BulletinMessage;
if ( msg == null )
continue;
if ( msg.Thread == null && CheckTime( msg.LastPostTime, ThreadDeletionTime ) )
{
msg.Delete();
RecurseDelete( msg ); // A root-level thread has expired
}
}
}
private void RecurseDelete( BulletinMessage msg )
{
List<Item> found = new List<Item>();
List<Item> items = this.Items;
for ( int i = items.Count - 1; i >= 0; --i )
{
if ( i >= items.Count )
continue;
BulletinMessage check = items[i] as BulletinMessage;
if ( check == null )
continue;
if ( check.Thread == msg )
{
check.Delete();
found.Add( check );
}
}
for ( int i = 0; i < found.Count; ++i )
RecurseDelete( (BulletinMessage)found[i] );
}
public virtual bool GetLastPostTime( Mobile poster, bool onlyCheckRoot, ref DateTime lastPostTime )
{
List<Item> items = this.Items;
bool wasSet = false;
for ( int i = 0; i < items.Count; ++i )
{
BulletinMessage msg = items[i] as BulletinMessage;
if ( msg == null || msg.Poster != poster )
continue;
if ( onlyCheckRoot && msg.Thread != null )
continue;
if ( msg.Time > lastPostTime )
{
wasSet = true;
lastPostTime = msg.Time;
}
}
return wasSet;
}
public override void OnDoubleClick( Mobile from )
{
if ( CheckRange( from ) )
{
Cleanup();
NetState state = from.NetState;
state.Send( new BBDisplayBoard( this ) );
if ( state.ContainerGridLines )
state.Send( new ContainerContent6017( from, this ) );
else
state.Send( new ContainerContent( from, this ) );
}
else
{
from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that.
}
}
public virtual bool CheckRange( Mobile from )
{
if ( from.AccessLevel >= AccessLevel.GameMaster )
return true;
return ( from.Map == this.Map && from.InRange( GetWorldLocation(), 2 ) );
}
public void PostMessage( Mobile from, BulletinMessage thread, string subject, string[] lines )
{
if ( thread != null )
thread.LastPostTime = DateTime.Now;
AddItem( new BulletinMessage( from, thread, subject, lines ) );
}
public BaseBulletinBoard( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int) 0 ); // version
writer.Write( (string) m_BoardName );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
switch ( version )
{
case 0:
{
m_BoardName = reader.ReadString();
break;
}
}
}
public static void Initialize()
{
PacketHandlers.Register( 0x71, 0, true, new OnPacketReceive( BBClientRequest ) );
}
public static void BBClientRequest( NetState state, PacketReader pvSrc )
{
Mobile from = state.Mobile;
int packetID = pvSrc.ReadByte();
BaseBulletinBoard board = World.FindItem( pvSrc.ReadInt32() ) as BaseBulletinBoard;
if ( board == null || !board.CheckRange( from ) )
return;
switch ( packetID )
{
case 3: BBRequestContent( from, board, pvSrc ); break;
case 4: BBRequestHeader( from, board, pvSrc ); break;
case 5: BBPostMessage( from, board, pvSrc ); break;
case 6: BBRemoveMessage( from, board, pvSrc ); break;
}
}
public static void BBRequestContent( Mobile from, BaseBulletinBoard board, PacketReader pvSrc )
{
BulletinMessage msg = World.FindItem( pvSrc.ReadInt32() ) as BulletinMessage;
if ( msg == null || msg.Parent != board )
return;
from.Send( new BBMessageContent( board, msg ) );
}
public static void BBRequestHeader( Mobile from, BaseBulletinBoard board, PacketReader pvSrc )
{
BulletinMessage msg = World.FindItem( pvSrc.ReadInt32() ) as BulletinMessage;
if ( msg == null || msg.Parent != board )
return;
from.Send( new BBMessageHeader( board, msg ) );
}
public static void BBPostMessage( Mobile from, BaseBulletinBoard board, PacketReader pvSrc )
{
BulletinMessage thread = World.FindItem( pvSrc.ReadInt32() ) as BulletinMessage;
if ( thread != null && thread.Parent != board )
thread = null;
int breakout = 0;
while ( thread != null && thread.Thread != null && breakout++ < 10 )
thread = thread.Thread;
DateTime lastPostTime = DateTime.MinValue;
if ( board.GetLastPostTime( from, ( thread == null ), ref lastPostTime ) )
{
if ( !CheckTime( lastPostTime, (thread == null ? ThreadCreateTime : ThreadReplyTime) ) )
{
if ( thread == null )
from.SendMessage( "You must wait {0} before creating a new thread.", FormatTS( ThreadCreateTime ) );
else
from.SendMessage( "You must wait {0} before replying to another thread.", FormatTS( ThreadReplyTime ) );
return;
}
}
string subject = pvSrc.ReadUTF8StringSafe( pvSrc.ReadByte() );
if ( subject.Length == 0 )
return;
string[] lines = new string[pvSrc.ReadByte()];
if ( lines.Length == 0 )
return;
for ( int i = 0; i < lines.Length; ++i )
lines[i] = pvSrc.ReadUTF8StringSafe( pvSrc.ReadByte() );
board.PostMessage( from, thread, subject, lines );
}
public static void BBRemoveMessage( Mobile from, BaseBulletinBoard board, PacketReader pvSrc )
{
BulletinMessage msg = World.FindItem( pvSrc.ReadInt32() ) as BulletinMessage;
if ( msg == null || msg.Parent != board )
return;
if ( from.AccessLevel < AccessLevel.GameMaster && msg.Poster != from )
return;
msg.Delete();
}
}
public struct BulletinEquip
{
public int itemID;
public int hue;
public BulletinEquip( int itemID, int hue )
{
this.itemID = itemID;
this.hue = hue;
}
}
public class BulletinMessage : Item
{
private Mobile m_Poster;
private string m_Subject;
private DateTime m_Time, m_LastPostTime;
private BulletinMessage m_Thread;
private string m_PostedName;
private int m_PostedBody;
private int m_PostedHue;
private BulletinEquip[] m_PostedEquip;
private string[] m_Lines;
public string GetTimeAsString()
{
return m_Time.ToString( "MMM dd, yyyy" );
}
public override bool CheckTarget( Mobile from, Server.Targeting.Target targ, object targeted )
{
return false;
}
public override bool IsAccessibleTo( Mobile check )
{
return false;
}
public BulletinMessage( Mobile poster, BulletinMessage thread, string subject, string[] lines ) : base( 0xEB0 )
{
Movable = false;
m_Poster = poster;
m_Subject = subject;
m_Time = DateTime.Now;
m_LastPostTime = m_Time;
m_Thread = thread;
m_PostedName = m_Poster.Name;
m_PostedBody = m_Poster.Body;
m_PostedHue = m_Poster.Hue;
m_Lines = lines;
List<BulletinEquip> list = new List<BulletinEquip>();
for ( int i = 0; i < poster.Items.Count; ++i )
{
Item item = poster.Items[i];
if ( item.Layer >= Layer.OneHanded && item.Layer <= Layer.Mount )
list.Add( new BulletinEquip( item.ItemID, item.Hue ) );
}
m_PostedEquip = list.ToArray();
}
public Mobile Poster{ get{ return m_Poster; } }
public BulletinMessage Thread{ get{ return m_Thread; } }
public string Subject{ get{ return m_Subject; } }
public DateTime Time{ get{ return m_Time; } }
public DateTime LastPostTime{ get{ return m_LastPostTime; } set{ m_LastPostTime = value; } }
public string PostedName{ get{ return m_PostedName; } }
public int PostedBody{ get{ return m_PostedBody; } }
public int PostedHue{ get{ return m_PostedHue; } }
public BulletinEquip[] PostedEquip{ get{ return m_PostedEquip; } }
public string[] Lines{ get{ return m_Lines; } }
public BulletinMessage( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int) 0 ); // version
writer.Write( (Mobile) m_Poster );
writer.Write( (string) m_Subject );
writer.Write( (DateTime) m_Time );
writer.Write( (DateTime) m_LastPostTime );
writer.Write( (bool) (m_Thread != null) );
writer.Write( (Item) m_Thread );
writer.Write( (string) m_PostedName );
writer.Write( (int) m_PostedBody );
writer.Write( (int) m_PostedHue );
writer.Write( (int) m_PostedEquip.Length );
for ( int i = 0; i < m_PostedEquip.Length; ++i )
{
writer.Write( (int) m_PostedEquip[i].itemID );
writer.Write( (int) m_PostedEquip[i].hue );
}
writer.Write( (int) m_Lines.Length );
for ( int i = 0; i < m_Lines.Length; ++i )
writer.Write( (string) m_Lines[i] );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
switch ( version )
{
case 0:
{
m_Poster = reader.ReadMobile();
m_Subject = reader.ReadString();
m_Time = reader.ReadDateTime();
m_LastPostTime = reader.ReadDateTime();
bool hasThread = reader.ReadBool();
m_Thread = reader.ReadItem() as BulletinMessage;
m_PostedName = reader.ReadString();
m_PostedBody = reader.ReadInt();
m_PostedHue = reader.ReadInt();
m_PostedEquip = new BulletinEquip[reader.ReadInt()];
for ( int i = 0; i < m_PostedEquip.Length; ++i )
{
m_PostedEquip[i].itemID = reader.ReadInt();
m_PostedEquip[i].hue = reader.ReadInt();
}
m_Lines = new string[reader.ReadInt()];
for ( int i = 0; i < m_Lines.Length; ++i )
m_Lines[i] = reader.ReadString();
if ( hasThread && m_Thread == null )
Delete();
break;
}
}
}
}
public class BBDisplayBoard : Packet
{
public BBDisplayBoard( BaseBulletinBoard board ) : base( 0x71 )
{
string name = board.BoardName;
if ( name == null )
name = "";
EnsureCapacity( 38 );
byte[] buffer = Utility.UTF8.GetBytes( name );
m_Stream.Write( (byte) 0x00 ); // PacketID
m_Stream.Write( (int) board.Serial ); // Bulletin board serial
// Bulletin board name
if ( buffer.Length >= 29 )
{
m_Stream.Write( buffer, 0, 29 );
m_Stream.Write( (byte) 0 );
}
else
{
m_Stream.Write( buffer, 0, buffer.Length );
m_Stream.Fill( 30 - buffer.Length );
}
}
}
public class BBMessageHeader : Packet
{
public BBMessageHeader( BaseBulletinBoard board, BulletinMessage msg ) : base( 0x71 )
{
string poster = SafeString( msg.PostedName );
string subject = SafeString( msg.Subject );
string time = SafeString( msg.GetTimeAsString() );
EnsureCapacity( 22 + poster.Length + subject.Length + time.Length );
m_Stream.Write( (byte) 0x01 ); // PacketID
m_Stream.Write( (int) board.Serial ); // Bulletin board serial
m_Stream.Write( (int) msg.Serial ); // Message serial
BulletinMessage thread = msg.Thread;
if ( thread == null )
m_Stream.Write( (int) 0 ); // Thread serial--root
else
m_Stream.Write( (int) thread.Serial ); // Thread serial--parent
WriteString( poster );
WriteString( subject );
WriteString( time );
}
public void WriteString( string v )
{
byte[] buffer = Utility.UTF8.GetBytes( v );
int len = buffer.Length + 1;
if ( len > 255 )
len = 255;
m_Stream.Write( (byte) len );
m_Stream.Write( buffer, 0, len-1 );
m_Stream.Write( (byte) 0 );
}
public string SafeString( string v )
{
if ( v == null )
return String.Empty;
return v;
}
}
public class BBMessageContent : Packet
{
public BBMessageContent( BaseBulletinBoard board, BulletinMessage msg ) : base( 0x71 )
{
string poster = SafeString( msg.PostedName );
string subject = SafeString( msg.Subject );
string time = SafeString( msg.GetTimeAsString() );
EnsureCapacity( 22 + poster.Length + subject.Length + time.Length );
m_Stream.Write( (byte) 0x02 ); // PacketID
m_Stream.Write( (int) board.Serial ); // Bulletin board serial
m_Stream.Write( (int) msg.Serial ); // Message serial
WriteString( poster );
WriteString( subject );
WriteString( time );
m_Stream.Write( (short) msg.PostedBody );
m_Stream.Write( (short) msg.PostedHue );
int len = msg.PostedEquip.Length;
if ( len > 255 )
len = 255;
m_Stream.Write( (byte) len );
for ( int i = 0; i < len; ++i )
{
BulletinEquip eq = msg.PostedEquip[i];
m_Stream.Write( (short) eq.itemID );
m_Stream.Write( (short) eq.hue );
}
len = msg.Lines.Length;
if ( len > 255 )
len = 255;
m_Stream.Write( (byte) len );
for ( int i = 0; i < len; ++i )
WriteString( msg.Lines[i] );
}
public void WriteString( string v )
{
byte[] buffer = Utility.UTF8.GetBytes( v );
int len = buffer.Length + 1;
if ( len > 255 )
len = 255;
m_Stream.Write( (byte) len );
m_Stream.Write( buffer, 0, len-1 );
m_Stream.Write( (byte) 0 );
}
public string SafeString( string v )
{
if ( v == null )
return String.Empty;
return v;
}
}
}