#W# Source and Scripts added. Added Scripts/Settings.cs to expose some basic tweak able settings.

This commit is contained in:
WarrentyExpired 2026-08-06 11:06:05 -04:00
parent b51c58f514
commit 3045c83799
3512 changed files with 627673 additions and 0 deletions

View file

@ -0,0 +1,313 @@
using System;
using Server;
using Server.Gumps;
using Server.Network;
using Server.Menus;
using Server.Menus.Questions;
using Server.Accounting;
using Server.Multis;
using Server.Mobiles;
namespace Server.Engines.Help
{
public class ContainedMenu : QuestionMenu
{
private Mobile m_From;
public ContainedMenu( Mobile from ) : base( "You already have an open help request. We will have someone assist you as soon as possible. What would you like to do?", new string[]{ "Leave my old help request like it is.", "Remove my help request from the queue." } )
{
m_From = from;
}
public override void OnCancel( NetState state )
{
m_From.SendLocalizedMessage( 1005306, "", 0x35 ); // Help request unchanged.
}
public override void OnResponse( NetState state, int index )
{
if ( index == 0 )
{
m_From.SendLocalizedMessage( 1005306, "", 0x35 ); // Help request unchanged.
}
else if ( index == 1 )
{
PageEntry entry = PageQueue.GetEntry( m_From );
if ( entry != null && entry.Handler == null )
{
m_From.SendLocalizedMessage( 1005307, "", 0x35 ); // Removed help request.
entry.AddResponse( entry.Sender, "[Canceled]" );
PageQueue.Remove( entry );
}
else
{
m_From.SendLocalizedMessage( 1005306, "", 0x35 ); // Help request unchanged.
}
}
}
}
public class HelpGump : Gump
{
public static void Initialize()
{
EventSink.HelpRequest += new HelpRequestEventHandler( EventSink_HelpRequest );
}
private static void EventSink_HelpRequest( HelpRequestEventArgs e )
{
foreach ( Gump g in e.Mobile.NetState.Gumps )
{
if ( g is HelpGump )
return;
}
if ( !PageQueue.CheckAllowedToPage( e.Mobile ) )
return;
if ( PageQueue.Contains( e.Mobile ) )
e.Mobile.SendMenu( new ContainedMenu( e.Mobile ) );
else
e.Mobile.SendGump( new HelpGump( e.Mobile ) );
}
private static bool IsYoung( Mobile m )
{
if ( m is PlayerMobile )
return ((PlayerMobile)m).Young;
return false;
}
public static bool CheckCombat( Mobile m )
{
for ( int i = 0; i < m.Aggressed.Count; ++i )
{
AggressorInfo info = m.Aggressed[i];
if ( DateTime.UtcNow - info.LastCombatTime < TimeSpan.FromSeconds( 30.0 ) )
return true;
}
return false;
}
public HelpGump( Mobile from ) : base( 0, 0 )
{
from.CloseGump( typeof( HelpGump ) );
bool isYoung = IsYoung( from );
AddBackground( 50, 25, 540, 430, 2600 );
AddPage( 0 );
AddHtmlLocalized( 150, 50, 360, 40, 1001002, false, false ); // <CENTER><U>Ultima Online Help Menu</U></CENTER>
AddButton( 425, 415, 2073, 2072, 0, GumpButtonType.Reply, 0 ); // Close
AddPage( 1 );
if ( isYoung )
{
AddButton( 80, 75, 5540, 5541, 9, GumpButtonType.Reply, 2 );
AddHtml( 110, 75, 450, 58, @"<BODY><BASEFONT COLOR=BLACK><u>Young Player Haven Transport.</u> Select this option if you want to be transported to Haven.</BODY>", true, true );
AddButton( 80, 140, 5540, 5541, 1, GumpButtonType.Reply, 2 );
AddHtml( 110, 140, 450, 58, @"<u>General question about Ultima Online.</u> Select this option if you have a general gameplay question, need help learning to use a skill, or if you would like to search the UO Knowledge Base.", true, true );
AddButton( 80, 205, 5540, 5541, 2, GumpButtonType.Reply, 0 );
AddHtml( 110, 205, 450, 58, @"<u>My character is physically stuck in the game.</u> This choice only covers cases where your character is physically stuck in a location they cannot move out of. This option will only work two times in 24 hours.", true, true );
AddButton( 80, 270, 5540, 5541, 0, GumpButtonType.Page, 3 );
AddHtml( 110, 270, 450, 58, @"<u>Another player is harassing me.</u> Another player is verbally harassing your character. When you select this option you will be sending a text log to Origin Systems. To see what constitutes harassment please visit http://support.uo.com/gm_9.html.", true, true );
AddButton( 80, 335, 5540, 5541, 0, GumpButtonType.Page, 2 );
AddHtml( 110, 335, 450, 58, @"<u>Other.</u> If you are experiencing a problem in the game that does not fall into one of the other categories or is not addressed on the Support web page (located at http://support.uo.com), please use this option.", true, true );
}
else
{
AddButton( 80, 90, 5540, 5541, 1, GumpButtonType.Reply, 2 );
AddHtml( 110, 90, 450, 74, @"<u>General question about Ultima Online.</u> Select this option if you have a general gameplay question, need help learning to use a skill, or if you would like to search the UO Knowledge Base.", true, true );
AddButton( 80, 170, 5540, 5541, 2, GumpButtonType.Reply, 0 );
AddHtml( 110, 170, 450, 74, @"<u>My character is physically stuck in the game.</u> This choice only covers cases where your character is physically stuck in a location they cannot move out of. This option will only work two times in 24 hours.", true, true );
AddButton( 80, 250, 5540, 5541, 0, GumpButtonType.Page, 3 );
AddHtml( 110, 250, 450, 74, @"<u>Another player is harassing me.</u> Another player is verbally harassing your character. When you select this option you will be sending a text log to Origin Systems. To see what constitutes harassment please visit http://support.uo.com/gm_9.html.", true, true );
AddButton( 80, 330, 5540, 5541, 0, GumpButtonType.Page, 2 );
AddHtml( 110, 330, 450, 74, @"<u>Other.</u> If you are experiencing a problem in the game that does not fall into one of the other categories or is not addressed on the Support web page (located at http://support.uo.com), please use this option.", true, true );
}
AddPage( 2 );
AddButton( 80, 90, 5540, 5541, 3, GumpButtonType.Reply, 0 );
AddHtml( 110, 90, 450, 74, @"<u>Report a bug or contact Origin.</u> Use this option to launch your web browser and mail in a bug report. Your report will be read by our Quality Assurance Staff. We apologize for not being able to reply to individual reports. ", true, true );
AddButton( 80, 170, 5540, 5541, 4, GumpButtonType.Reply, 0 );
AddHtml( 110, 170, 450, 74, @"<u>Suggestion for the Game.</u> If you'd like to make a suggestion for the game, it should be directed to the Development Team Members who participate in the discussion forums on the UO.Com web site. Choosing this option will take you to the Discussion Forums. ", true, true );
AddButton( 80, 250, 5540, 5541, 5, GumpButtonType.Reply, 0 );
AddHtml( 110, 250, 450, 74, @"<u>Account Management</u> For questions regarding your account such as forgotten passwords, payment options, account activation, and account transfer, please choose this option.", true, true );
AddButton( 80, 330, 5540, 5541, 6, GumpButtonType.Reply, 0 );
AddHtml( 110, 330, 450, 74, @"<u>Other.</u> If you are experiencing a problem in the game that does not fall into one of the other categories or is not addressed on the Support web page (located at http://support.uo.com), and requires in-game assistance, use this option. ", true, true );
AddPage( 3 );
AddButton( 80, 90, 5540, 5541, 7, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 110, 90, 450, 145, 1062572, true, true ); /* <U><CENTER>Another player is harassing me (or Exploiting).</CENTER></U><BR>
* VERBAL HARASSMENT<BR>
* Use this option when another player is verbally harassing your character.
* Verbal harassment behaviors include but are not limited to, using bad language, threats etc..
* Before you submit a complaint be sure you understand what constitutes harassment
* <A HREF="http://uo.custhelp.com/cgi-bin/uo.cfg/php/enduser/std_adp.php?p_faqid=40"> what is verbal harassment? -</A>
* and that you have followed these steps:<BR>
* 1. You have asked the player to stop and they have continued.<BR>
* 2. You have tried to remove yourself from the situation.<BR>
* 3. You have done nothing to instigate or further encourage the harassment.<BR>
* 4. You have added the player to your ignore list.
* <A HREF="http://uo.custhelp.com/cgi-bin/uo.cfg/php/enduser/std_adp.php?p_faqid=138">- How do I ignore a player?</A><BR>
* 5. You have read and understand Origins definition of harassment.<BR>
* 6. Your account information is up to date. (Including a current email address)<BR>
* *If these steps have not been taken, GMs may be unable to take action against the offending player.<BR>
* **A chat log will be review by a GM to assess the validity of this complaint.
* Abuse of this system is a violation of the Rules of Conduct.<BR>
* EXPLOITING<BR>
* Use this option to report someone who may be exploiting or cheating.
* <A HREF="http://uo.custhelp.com/cgi-bin/uo.cfg/php/enduser/std_adp.php?p_faqid=41"> What constitutes an exploit?</a>
*/
AddButton( 80, 240, 5540, 5541, 8, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 110, 240, 450, 145, 1062573, true, true ); /* <U><CENTER>Another player is harassing me using game mechanics.</CENTER></U><BR>
* <BR>
* PHYSICAL HARASSMENT<BR>
* Use this option when another player is harassing your character using game mechanics.
* Physical harassment includes but is not limited to luring, Kill Stealing, and any act that causes a players death in Trammel.
* Before you submit a complaint be sure you understand what constitutes harassment
* <A HREF="http://uo.custhelp.com/cgi-bin/uo.cfg/php/enduser/std_adp.php?p_faqid=59"> what is physical harassment?</A>
* and that you have followed these steps:<BR>
* 1. You have asked the player to stop and they have continued.<BR>
* 2. You have tried to remove yourself from the situation.<BR>
* 3. You have done nothing to instigate or further encourage the harassment.<BR>
* 4. You have added the player to your ignore list.
* <A HREF="http://uo.custhelp.com/cgi-bin/uo.cfg/php/enduser/std_adp.php?p_faqid=138"> - how do I ignore a player?</A><BR>
* 5. You have read and understand Origins definition of harassment.<BR>
* 6. Your account information is up to date. (Including a current email address)<BR>
* *If these steps have not been taken, GMs may be unable to take action against the offending player.<BR>
* **This issue will be reviewed by a GM to assess the validity of this complaint.
* Abuse of this system is a violation of the Rules of Conduct.
*/
AddButton( 150, 390, 5540, 5541, 0, GumpButtonType.Page, 1 );
AddHtmlLocalized( 180, 390, 335, 40, 1001015, false, false ); // NO - I meant to ask for help with another matter.
}
public override void OnResponse( NetState state, RelayInfo info )
{
Mobile from = state.Mobile;
PageType type = (PageType)(-1);
switch ( info.ButtonID )
{
case 0: // Close/Cancel
{
from.SendLocalizedMessage( 501235, "", 0x35 ); // Help request aborted.
break;
}
case 1: // General question
{
type = PageType.Question;
break;
}
case 2: // Stuck
{
BaseHouse house = BaseHouse.FindHouseAt( from );
if ( house != null && house.IsAosRules && !from.Region.IsPartOf( typeof( Engines.ConPVP.SafeZone ) ) ) // Dueling
{
from.Location = house.BanLocation;
}
else if ( from.Region.IsPartOf( typeof( Server.Regions.Jail ) ) )
{
from.SendLocalizedMessage( 1114345, "", 0x35 ); // You'll need a better jailbreak plan than that!
}
else if ( Factions.Sigil.ExistsOn( from ) )
{
from.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil.
}
else if ( from is PlayerMobile && ((PlayerMobile)from).CanUseStuckMenu() && from.Region.CanUseStuckMenu( from ) && !CheckCombat( from ) && !from.Frozen && !from.Criminal && (Core.AOS || from.Kills < 5) )
{
StuckMenu menu = new StuckMenu( from, from, true );
menu.BeginClose();
from.SendGump( menu );
}
else
{
type = PageType.Stuck;
}
break;
}
case 3: // Report bug or contact Origin
{
type = PageType.Bug;
break;
}
case 4: // Game suggestion
{
type = PageType.Suggestion;
break;
}
case 5: // Account management
{
type = PageType.Account;
break;
}
case 6: // Other
{
type = PageType.Other;
break;
}
case 7: // Harassment: verbal/exploit
{
type = PageType.VerbalHarassment;
break;
}
case 8: // Harassment: physical
{
type = PageType.PhysicalHarassment;
break;
}
case 9: // Young player transport
{
if ( IsYoung( from ) )
{
if ( from.Region.IsPartOf( typeof( Regions.Jail ) ) )
{
from.SendLocalizedMessage( 1114345, "", 0x35 ); // You'll need a better jailbreak plan than that!
}
else if ( from.Region.IsPartOf( "Haven Island" ) )
{
from.SendLocalizedMessage( 1041529 ); // You're already in Haven
}
else
{
from.MoveToWorld( new Point3D( 3503, 2574, 14 ), Map.Trammel );
}
}
break;
}
}
if ( type != (PageType)(-1) && PageQueue.CheckAllowedToPage( from ) )
from.SendGump( new PagePromptGump( from, type ) );
}
}
}

View file

@ -0,0 +1,30 @@
using System;
using Server.Network;
using Server.Prompts;
namespace Server.Engines.Help
{
public class PagePrompt : Prompt
{
private PageType m_Type;
public PagePrompt( PageType type )
{
m_Type = type;
}
public override void OnCancel( Mobile from )
{
from.SendLocalizedMessage( 501235, "", 0x35 ); // Help request aborted.
}
public override void OnResponse( Mobile from, string text )
{
from.SendLocalizedMessage( 501234, "", 0x35 ); /* The next available Counselor/Game Master will respond as soon as possible.
* Please check your Journal for messages every few minutes.
*/
PageQueue.Enqueue( new PageEntry( from, text, m_Type ) );
}
}
}

View file

@ -0,0 +1,61 @@
using System;
using Server;
using Server.Gumps;
using Server.Network;
namespace Server.Engines.Help
{
public class PagePromptGump : Gump
{
private Mobile m_From;
private PageType m_Type;
public PagePromptGump( Mobile from, PageType type ) : base( 0, 0 )
{
m_From = from;
m_Type = type;
from.CloseGump( typeof( PagePromptGump ) );
AddBackground( 50, 50, 540, 350, 2600 );
AddPage( 0 );
AddHtmlLocalized( 264, 80, 200, 24, 1062524, false, false ); // Enter Description
AddHtmlLocalized( 120, 108, 420, 48, 1062638, false, false ); // Please enter a brief description (up to 200 characters) of your problem:
AddBackground( 100, 148, 440, 200, 3500 );
AddTextEntry( 120, 168, 400, 200, 1153, 0, "" );
AddButton( 175, 355, 2074, 2075, 1, GumpButtonType.Reply, 0 ); // Okay
AddButton( 405, 355, 2073, 2072, 0, GumpButtonType.Reply, 0 ); // Cancel
}
public override void OnResponse( NetState sender, RelayInfo info )
{
if ( info.ButtonID == 0 )
{
m_From.SendLocalizedMessage( 501235, "", 0x35 ); // Help request aborted.
}
else
{
TextRelay entry = info.GetTextEntry( 0 );
string text = ( entry == null ? "" : entry.Text.Trim() );
if ( text.Length == 0 )
{
m_From.SendMessage( 0x35, "You must enter a description." );
m_From.SendGump( new PagePromptGump( m_From, m_Type ) );
}
else
{
m_From.SendLocalizedMessage( 501234, "", 0x35 ); /* The next available Counselor/Game Master will respond as soon as possible.
* Please check your Journal for messages every few minutes.
*/
PageQueue.Enqueue( new PageEntry( m_From, text, m_Type ) );
}
}
}
}
}

View file

@ -0,0 +1,395 @@
using System;
using System.Collections;
using System.Net.Mail;
using System.IO;
using Server;
using Server.Mobiles;
using Server.Network;
using Server.Misc;
using Server.Accounting;
using Server.Engines.Reports;
using Server.Commands;
using System.Collections.Generic;
namespace Server.Engines.Help
{
public enum PageType
{
Bug,
Stuck,
Account,
Question,
Suggestion,
Other,
VerbalHarassment,
PhysicalHarassment
}
public class PageEntry
{
// What page types should have a speech log as attachment?
public static readonly PageType[] SpeechLogAttachment = new PageType[]
{
PageType.VerbalHarassment
};
private Mobile m_Sender;
private Mobile m_Handler;
private DateTime m_Sent;
private string m_Message;
private PageType m_Type;
private Point3D m_PageLocation;
private Map m_PageMap;
private List<SpeechLogEntry> m_SpeechLog;
private PageInfo m_PageInfo;
public PageInfo PageInfo
{
get{ return m_PageInfo; }
}
public Mobile Sender
{
get
{
return m_Sender;
}
}
public Mobile Handler
{
get
{
return m_Handler;
}
set
{
PageQueue.OnHandlerChanged( m_Handler, value, this );
m_Handler = value;
}
}
public DateTime Sent
{
get
{
return m_Sent;
}
}
public string Message
{
get
{
return m_Message;
}
}
public PageType Type
{
get
{
return m_Type;
}
}
public Point3D PageLocation
{
get
{
return m_PageLocation;
}
}
public Map PageMap
{
get
{
return m_PageMap;
}
}
public List<SpeechLogEntry> SpeechLog
{
get
{
return m_SpeechLog;
}
}
private Timer m_Timer;
public void Stop()
{
if ( m_Timer != null )
m_Timer.Stop();
m_Timer = null;
}
public void AddResponse( Mobile mob, string text )
{
if ( m_PageInfo != null )
{
lock ( m_PageInfo )
m_PageInfo.Responses.Add( PageInfo.GetAccount( mob ), text );
if ( PageInfo.ResFromResp( text ) != PageResolution.None )
m_PageInfo.UpdateResolver();
}
}
public PageEntry( Mobile sender, string message, PageType type )
{
m_Sender = sender;
m_Sent = DateTime.UtcNow;
m_Message = Utility.FixHtml( message );
m_Type = type;
m_PageLocation = sender.Location;
m_PageMap = sender.Map;
PlayerMobile pm = sender as PlayerMobile;
if ( pm != null && pm.SpeechLog != null && Array.IndexOf( SpeechLogAttachment, type ) >= 0 )
m_SpeechLog = new List<SpeechLogEntry>( pm.SpeechLog );
m_Timer = new InternalTimer( this );
m_Timer.Start();
StaffHistory history = Reports.Reports.StaffHistory;
if ( history != null )
{
m_PageInfo = new PageInfo( this );
history.AddPage( m_PageInfo );
}
}
private class InternalTimer : Timer
{
private static TimeSpan StatusDelay = TimeSpan.FromMinutes( 2.0 );
private PageEntry m_Entry;
public InternalTimer( PageEntry entry ) : base( TimeSpan.FromSeconds( 1.0 ), StatusDelay )
{
m_Entry = entry;
}
protected override void OnTick()
{
int index = PageQueue.IndexOf( m_Entry );
if ( m_Entry.Sender.NetState != null && index != -1 )
{
m_Entry.Sender.SendLocalizedMessage( 1008077, true, (index + 1).ToString() ); // Thank you for paging. Queue status :
m_Entry.Sender.SendLocalizedMessage( 1008084 ); // You can reference our website at www.uo.com or contact us at support@uo.com. To cancel your page, please select the help button again and select cancel.
if ( m_Entry.Handler != null && m_Entry.Handler.NetState == null ) {
m_Entry.Handler = null;
}
}
else
{
if ( index != -1 )
m_Entry.AddResponse( m_Entry.Sender, "[Logout]" );
PageQueue.Remove( m_Entry );
}
}
}
}
public class PageQueue
{
private static ArrayList m_List = new ArrayList();
private static Hashtable m_KeyedByHandler = new Hashtable();
private static Hashtable m_KeyedBySender = new Hashtable();
public static void Initialize()
{
CommandSystem.Register( "Pages", AccessLevel.Counselor, new CommandEventHandler( Pages_OnCommand ) );
}
public static bool CheckAllowedToPage( Mobile from )
{
PlayerMobile pm = from as PlayerMobile;
if ( pm == null )
return true;
if ( pm.DesignContext != null )
{
from.SendLocalizedMessage( 500182 ); // You cannot request help while customizing a house or transferring a character.
return false;
}
else if ( pm.PagingSquelched )
{
from.SendMessage( "You cannot request help, sorry." );
return false;
}
return true;
}
public static string GetPageTypeName( PageType type )
{
if ( type == PageType.VerbalHarassment )
return "Verbal Harassment";
else if ( type == PageType.PhysicalHarassment )
return "Physical Harassment";
else
return type.ToString();
}
public static void OnHandlerChanged( Mobile old, Mobile value, PageEntry entry )
{
if ( old != null )
m_KeyedByHandler.Remove( old );
if ( value != null )
m_KeyedByHandler[value] = entry;
}
[Usage( "Pages" )]
[Description( "Opens the page queue menu." )]
private static void Pages_OnCommand( CommandEventArgs e )
{
PageEntry entry = (PageEntry)m_KeyedByHandler[e.Mobile];
if ( entry != null )
{
e.Mobile.SendGump( new PageEntryGump( e.Mobile, entry ) );
}
else if ( m_List.Count > 0 )
{
e.Mobile.SendGump( new PageQueueGump() );
}
else
{
e.Mobile.SendMessage( "The page queue is empty." );
}
}
public static bool IsHandling( Mobile check )
{
return m_KeyedByHandler.ContainsKey( check );
}
public static bool Contains( Mobile sender )
{
return m_KeyedBySender.ContainsKey( sender );
}
public static int IndexOf( PageEntry e )
{
return m_List.IndexOf( e );
}
public static void Cancel( Mobile sender )
{
Remove( (PageEntry) m_KeyedBySender[sender] );
}
public static void Remove( PageEntry e )
{
if ( e == null )
return;
e.Stop();
m_List.Remove( e );
m_KeyedBySender.Remove( e.Sender );
if ( e.Handler != null )
m_KeyedByHandler.Remove( e.Handler );
}
public static PageEntry GetEntry( Mobile sender )
{
return (PageEntry)m_KeyedBySender[sender];
}
public static void Remove( Mobile sender )
{
Remove( GetEntry( sender ) );
}
public static ArrayList List
{
get
{
return m_List;
}
}
public static void Enqueue( PageEntry entry )
{
m_List.Add( entry );
m_KeyedBySender[entry.Sender] = entry;
bool isStaffOnline = false;
foreach ( NetState ns in NetState.Instances )
{
Mobile m = ns.Mobile;
if ( m != null && m.AccessLevel >= AccessLevel.Counselor && m.AutoPageNotify && !IsHandling( m ) )
m.SendMessage( "A new page has been placed in the queue." );
if (m != null && m.AccessLevel >= AccessLevel.Counselor && m.AutoPageNotify && Core.TickCount - m.LastMoveTime < 600000)
isStaffOnline = true;
}
if ( !isStaffOnline )
entry.Sender.SendMessage( "We are sorry, but no staff members are currently available to assist you. Your page will remain in the queue until one becomes available, or until you cancel it manually." );
if ( Email.FromAddress != null && Email.SpeechLogPageAddresses != null && entry.SpeechLog != null )
SendEmail( entry );
}
private static void SendEmail( PageEntry entry )
{
Mobile sender = entry.Sender;
DateTime time = DateTime.UtcNow;
MailMessage mail = new MailMessage( Email.FromAddress, Email.SpeechLogPageAddresses );
mail.Subject = "RunUO Speech Log Page Forwarding";
using ( StringWriter writer = new StringWriter() )
{
writer.WriteLine( "RunUO Speech Log Page - {0}", PageQueue.GetPageTypeName( entry.Type ) );
writer.WriteLine();
writer.WriteLine( "From: '{0}', Account: '{1}'", sender.RawName, sender.Account is Account ? sender.Account.Username : "???" );
writer.WriteLine( "Location: {0} [{1}]", sender.Location, sender.Map );
writer.WriteLine( "Sent on: {0}/{1:00}/{2:00} {3}:{4:00}:{5:00}", time.Year, time.Month, time.Day, time.Hour, time.Minute, time.Second );
writer.WriteLine();
writer.WriteLine( "Message:" );
writer.WriteLine( "'{0}'", entry.Message );
writer.WriteLine();
writer.WriteLine( "Speech Log" );
writer.WriteLine( "==========" );
foreach ( SpeechLogEntry logEntry in entry.SpeechLog )
{
Mobile from = logEntry.From;
string fromName = from.RawName;
string fromAccount = from.Account is Account ? from.Account.Username : "???";
DateTime created = logEntry.Created;
string speech = logEntry.Speech;
writer.WriteLine( "{0}:{1:00}:{2:00} - {3} ({4}): '{5}'", created.Hour, created.Minute, created.Second, fromName, fromAccount, speech );
}
mail.Body = writer.ToString();
}
Email.AsyncSend( mail );
}
}
}

View file

@ -0,0 +1,834 @@
using System;
using System.IO;
using System.Collections;
using Server;
using Server.Network;
using Server.Gumps;
namespace Server.Engines.Help
{
public class MessageSentGump : Gump
{
private string m_Name, m_Text;
private Mobile m_Mobile;
public MessageSentGump( Mobile mobile, string name, string text ) : base( 30, 30 )
{
m_Name = name;
m_Text = text;
m_Mobile = mobile;
Closable = false;
AddPage( 0 );
AddBackground( 0, 0, 92, 75, 0xA3C );
AddImageTiled( 5, 7, 82, 61, 0xA40 );
AddAlphaRegion( 5, 7, 82, 61 );
AddImageTiled( 9, 11, 21, 53, 0xBBC );
AddButton( 10, 12, 0x7D2, 0x7D2, 0, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 34, 28, 65, 24, 3001002, 0xFFFFFF, false, false ); // Message
}
public override void OnResponse( NetState state, RelayInfo info )
{
m_Mobile.SendGump( new PageResponseGump( m_Mobile, m_Name, m_Text ) );
//m_Mobile.SendMessage( 0x482, "{0} tells you:", m_Name );
//m_Mobile.SendMessage( 0x482, m_Text );
}
}
public class PageQueueGump : Gump
{
private PageEntry[] m_List;
public PageQueueGump() : base( 30, 30 )
{
Add( new GumpPage( 0 ) );
//Add( new GumpBackground( 0, 0, 410, 448, 9200 ) );
Add( new GumpImageTiled( 0, 0, 410, 448, 0xA40 ) );
Add( new GumpAlphaRegion( 1, 1, 408, 446 ) );
Add( new GumpLabel( 180, 12, 2100, "Page Queue" ) );
ArrayList list = PageQueue.List;
for ( int i = 0; i < list.Count; )
{
PageEntry e = (PageEntry)list[i];
if ( e.Sender.Deleted || e.Sender.NetState == null )
{
e.AddResponse( e.Sender, "[Logout]" );
PageQueue.Remove( e );
}
else
{
++i;
}
}
m_List = (PageEntry[])list.ToArray( typeof( PageEntry ) );
if ( m_List.Length > 0 )
{
Add( new GumpPage( 1 ) );
for ( int i = 0; i < m_List.Length; ++i )
{
PageEntry e = m_List[i];
if ( i >= 5 && (i % 5) == 0 )
{
Add( new GumpButton( 368, 12, 0xFA5, 0xFA7, 0, GumpButtonType.Page, (i / 5) + 1 ) );
Add( new GumpLabel( 298, 12, 2100, "Next Page" ) );
Add( new GumpPage( (i / 5) + 1 ) );
Add( new GumpButton( 12, 12, 0xFAE, 0xFB0, 0, GumpButtonType.Page, (i / 5) ) );
Add( new GumpLabel( 48, 12, 2100, "Previous Page" ) );
}
string typeString = PageQueue.GetPageTypeName( e.Type );
string html = String.Format( "[{0}] {1} <basefont color=#{2:X6}>[<u>{3}</u>]</basefont>", typeString, e.Message, e.Handler == null ? 0xFF0000 : 0xFF, e.Handler == null ? "Unhandled" : "Handling" );
Add( new GumpHtml( 12, 44 + ((i % 5) * 80), 350, 70, html, true, true ) );
Add( new GumpButton( 370, 44 + ((i % 5) * 80) + 24, 0xFA5, 0xFA7, i + 1, GumpButtonType.Reply, 0 ) );
}
}
else
{
Add( new GumpLabel( 12, 44, 2100, "The page queue is empty." ) );
}
}
public override void OnResponse( NetState state, RelayInfo info )
{
if ( info.ButtonID >= 1 && info.ButtonID <= m_List.Length )
{
if ( PageQueue.List.IndexOf( m_List[info.ButtonID - 1] ) >= 0 )
{
PageEntryGump g = new PageEntryGump( state.Mobile, m_List[info.ButtonID - 1] );
g.SendTo( state );
}
else
{
state.Mobile.SendGump( new PageQueueGump() );
state.Mobile.SendMessage( "That page has been removed." );
}
}
}
}
public class PredefinedResponse
{
private string m_Title;
private string m_Message;
public string Title{ get{ return m_Title; } set{ m_Title = value; } }
public string Message{ get{ return m_Message; } set{ m_Message = value; } }
public PredefinedResponse( string title, string message )
{
m_Title = title;
m_Message = message;
}
private static ArrayList m_List;
public static ArrayList List
{
get
{
if ( m_List == null )
m_List = Load();
return m_List;
}
}
public static PredefinedResponse Add( string title, string message )
{
if ( m_List == null )
m_List = Load();
PredefinedResponse resp = new PredefinedResponse( title, message );
m_List.Add( resp );
Save();
return resp;
}
public static void Save()
{
if ( m_List == null )
m_List = Load();
try
{
string path = Path.Combine( Core.BaseDirectory, "Data/pageresponse.cfg" );
using ( StreamWriter op = new StreamWriter( path ) )
{
for ( int i = 0; i < m_List.Count; ++i )
{
PredefinedResponse resp = (PredefinedResponse)m_List[i];
op.WriteLine( "{0}\t{1}", resp.Title, resp.Message );
}
}
}
catch ( Exception e )
{
Console.WriteLine( e );
}
}
public static ArrayList Load()
{
ArrayList list = new ArrayList();
string path = Path.Combine( Core.BaseDirectory, "Data/pageresponse.cfg" );
if ( File.Exists( path ) )
{
try
{
using ( StreamReader ip = new StreamReader( path ) )
{
string line;
while ( (line = ip.ReadLine()) != null )
{
try
{
line = line.Trim();
if ( line.Length == 0 || line.StartsWith( "#" ) )
continue;
string[] split = line.Split( '\t' );
if ( split.Length == 2 )
list.Add( new PredefinedResponse( split[0], split[1] ) );
}
catch
{
}
}
}
}
catch ( Exception e )
{
Console.WriteLine( e );
}
}
return list;
}
}
public class PredefGump : Gump
{
private const int LabelColor32 = 0xFFFFFF;
public string Center( string text )
{
return String.Format( "<CENTER>{0}</CENTER>", text );
}
public string Color( string text, int color )
{
return String.Format( "<BASEFONT COLOR=#{0:X6}>{1}</BASEFONT>", color, text );
}
public void AddTextInput( int x, int y, int w, int h, int id, string def )
{
AddImageTiled( x, y, w, h, 0xA40 );
AddImageTiled( x + 1, y + 1, w - 2, h - 2, 0xBBC );
AddTextEntry( x + 3, y + 1, w - 4, h - 2, 0x480, id, def );
}
private Mobile m_From;
private PredefinedResponse m_Response;
public PredefGump( Mobile from, PredefinedResponse response ) : base( 30, 30 )
{
m_From = from;
m_Response = response;
from.CloseGump( typeof( PredefGump ) );
bool canEdit = ( from.AccessLevel >= AccessLevel.GameMaster );
AddPage( 0 );
if ( response == null )
{
AddImageTiled( 0, 0, 410, 448, 0xA40 );
AddAlphaRegion( 1, 1, 408, 446 );
AddHtml( 10, 10, 390, 20, Color( Center( "Predefined Responses" ), LabelColor32 ), false, false );
ArrayList list = PredefinedResponse.List;
AddPage( 1 );
int i;
for ( i = 0; i < list.Count; ++i )
{
if ( i >= 5 && (i % 5) == 0 )
{
AddButton( 368, 10, 0xFA5, 0xFA7, 0, GumpButtonType.Page, (i / 5) + 1 );
AddLabel( 298, 10, 2100, "Next Page" );
AddPage( (i / 5) + 1 );
AddButton( 12, 10, 0xFAE, 0xFB0, 0, GumpButtonType.Page, i / 5 );
AddLabel( 48, 10, 2100, "Previous Page" );
}
PredefinedResponse resp = (PredefinedResponse)list[i];
string html = String.Format( "<u>{0}</u><br>{1}", resp.Title, resp.Message );
AddHtml( 12, 44 + ((i % 5) * 80), 350, 70, html, true, true );
if ( canEdit )
{
AddButton( 370, 44 + ((i % 5) * 80) + 24, 0xFA5, 0xFA7, 2 + (i * 3), GumpButtonType.Reply, 0 );
if ( i > 0 )
AddButton( 377, 44 + ((i % 5) * 80) + 2, 0x15E0, 0x15E4, 3 + (i * 3), GumpButtonType.Reply, 0 );
else
AddImage( 377, 44 + ((i % 5) * 80) + 2, 0x25E4 );
if ( i < (list.Count - 1) )
AddButton( 377, 44 + ((i % 5) * 80) + 70 - 2 - 16, 0x15E2, 0x15E6, 4 + (i * 3), GumpButtonType.Reply, 0 );
else
AddImage( 377, 44 + ((i % 5) * 80) + 70 - 2 - 16, 0x25E8 );
}
}
if ( canEdit )
{
if ( i >= 5 && (i % 5) == 0 )
{
AddButton( 368, 10, 0xFA5, 0xFA7, 0, GumpButtonType.Page, (i / 5) + 1 );
AddLabel( 298, 10, 2100, "Next Page" );
AddPage( (i / 5) + 1 );
AddButton( 12, 10, 0xFAE, 0xFB0, 0, GumpButtonType.Page, i / 5 );
AddLabel( 48, 10, 2100, "Previous Page" );
}
AddButton( 12, 44 + ((i % 5) * 80), 0xFAB, 0xFAD, 1, GumpButtonType.Reply, 0 );
AddHtml( 45, 44 + ((i % 5) * 80), 200, 20, Color( "New Response", LabelColor32 ), false, false );
}
}
else if ( canEdit )
{
AddImageTiled( 0, 0, 410, 250, 0xA40 );
AddAlphaRegion( 1, 1, 408, 248 );
AddHtml( 10, 10, 390, 20, Color( Center( "Predefined Response Editor" ), LabelColor32 ), false, false );
AddButton( 10, 40, 0xFB1, 0xFB3, 1, GumpButtonType.Reply, 0 );
AddHtml( 45, 40, 200, 20, Color( "Remove", LabelColor32 ), false, false );
AddButton( 10, 70, 0xFA5, 0xFA7, 2, GumpButtonType.Reply, 0 );
AddHtml( 45, 70, 200, 20, Color( "Title:", LabelColor32 ), false, false );
AddTextInput( 10, 90, 300, 20, 0, response.Title );
AddButton( 10, 120, 0xFA5, 0xFA7, 3, GumpButtonType.Reply, 0 );
AddHtml( 45, 120, 200, 20, Color( "Message:", LabelColor32 ), false, false );
AddTextInput( 10, 140, 390, 100, 1, response.Message );
}
}
public override void OnResponse( NetState sender, RelayInfo info )
{
if ( m_From.AccessLevel < AccessLevel.Administrator )
return;
if ( m_Response == null )
{
int index = info.ButtonID - 1;
if ( index == 0 )
{
PredefinedResponse resp = new PredefinedResponse( "", "" );
ArrayList list = PredefinedResponse.List;
list.Add( resp );
m_From.SendGump( new PredefGump( m_From, resp ) );
}
else
{
--index;
int type = index % 3;
index /= 3;
ArrayList list = PredefinedResponse.List;
if ( index >= 0 && index < list.Count )
{
PredefinedResponse resp = (PredefinedResponse)list[index];
switch ( type )
{
case 0: // edit
{
m_From.SendGump( new PredefGump( m_From, resp ) );
break;
}
case 1: // move up
{
if ( index > 0 )
{
list.RemoveAt( index );
list.Insert( index - 1, resp );
PredefinedResponse.Save();
m_From.SendGump( new PredefGump( m_From, null ) );
}
break;
}
case 2: // move down
{
if ( index < (list.Count - 1) )
{
list.RemoveAt( index );
list.Insert( index + 1, resp );
PredefinedResponse.Save();
m_From.SendGump( new PredefGump( m_From, null ) );
}
break;
}
}
}
}
}
else
{
ArrayList list = PredefinedResponse.List;
switch ( info.ButtonID )
{
case 1:
{
list.Remove( m_Response );
PredefinedResponse.Save();
m_From.SendGump( new PredefGump( m_From, null ) );
break;
}
case 2:
{
TextRelay te = info.GetTextEntry( 0 );
if ( te != null )
m_Response.Title = te.Text;
PredefinedResponse.Save();
m_From.SendGump( new PredefGump( m_From, m_Response ) );
break;
}
case 3:
{
TextRelay te = info.GetTextEntry( 1 );
if ( te != null )
m_Response.Message = te.Text;
PredefinedResponse.Save();
m_From.SendGump( new PredefGump( m_From, m_Response ) );
break;
}
}
}
}
}
public class PageEntryGump : Gump
{
private PageEntry m_Entry;
private Mobile m_Mobile;
private static int[] m_AccessLevelHues = new int[]
{
2100,
2122,
2117,
2129,
2415,
2415,
2415
};
public PageEntryGump( Mobile m, PageEntry entry ) : base( 30, 30 )
{
try
{
m_Mobile = m;
m_Entry = entry;
int buttons = 0;
int bottom = 356;
AddPage( 0 );
AddImageTiled( 0, 0, 410, 456, 0xA40 );
AddAlphaRegion( 1, 1, 408, 454 );
AddPage( 1 );
AddLabel( 18, 18, 2100, "Sent:" );
AddLabelCropped( 128, 18, 264, 20, 2100, entry.Sent.ToString() );
AddLabel( 18, 38, 2100, "Sender:" );
AddLabelCropped( 128, 38, 264, 20, 2100, String.Format( "{0} {1} [{2}]", entry.Sender.RawName, entry.Sender.Location, entry.Sender.Map ) );
AddButton( 18, bottom - (buttons * 22), 0xFAB, 0xFAD, 8, GumpButtonType.Reply, 0 );
AddImageTiled( 52, bottom - (buttons * 22) + 1, 340, 80, 0xA40/*0xBBC*//*0x2458*/ );
AddImageTiled( 53, bottom - (buttons * 22) + 2, 338, 78, 0xBBC/*0x2426*/ );
AddTextEntry( 55, bottom - (buttons++ * 22) + 2, 336, 78, 0x480, 0, "" );
AddButton( 18, bottom - (buttons * 22), 0xFA5, 0xFA7, 0, GumpButtonType.Page, 2 );
AddLabel( 52, bottom - (buttons++ * 22), 2100, "Predefined Response" );
if ( entry.Sender != m )
{
AddButton( 18, bottom - (buttons * 22), 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 );
AddLabel( 52, bottom - (buttons++ * 22), 2100, "Go to Sender" );
}
AddLabel( 18, 58, 2100, "Handler:" );
if ( entry.Handler == null )
{
AddLabelCropped( 128, 58, 264, 20, 2100, "Unhandled" );
AddButton( 18, bottom - (buttons * 22), 0xFB1, 0xFB3, 5, GumpButtonType.Reply, 0 );
AddLabel( 52, bottom - (buttons++ * 22), 2100, "Delete Page" );
AddButton( 18, bottom - (buttons * 22), 0xFB7, 0xFB9, 4, GumpButtonType.Reply, 0 );
AddLabel( 52, bottom - (buttons++ * 22), 2100, "Handle Page" );
}
else
{
AddLabelCropped( 128, 58, 264, 20, m_AccessLevelHues[(int)entry.Handler.AccessLevel], entry.Handler.Name );
if ( entry.Handler != m )
{
AddButton( 18, bottom - (buttons * 22), 0xFA5, 0xFA7, 2, GumpButtonType.Reply, 0 );
AddLabel( 52, bottom - (buttons++ * 22), 2100, "Go to Handler" );
}
else
{
AddButton( 18, bottom - (buttons * 22), 0xFA2, 0xFA4, 6, GumpButtonType.Reply, 0 );
AddLabel( 52, bottom - (buttons++ * 22), 2100, "Abandon Page" );
AddButton( 18, bottom - (buttons * 22), 0xFB7, 0xFB9, 7, GumpButtonType.Reply, 0 );
AddLabel( 52, bottom - (buttons++ * 22), 2100, "Page Handled" );
}
}
AddLabel( 18, 78, 2100, "Page Location:" );
AddLabelCropped( 128, 78, 264, 20, 2100, String.Format( "{0} [{1}]", entry.PageLocation, entry.PageMap ) );
AddButton( 18, bottom - (buttons * 22), 0xFA5, 0xFA7, 3, GumpButtonType.Reply, 0 );
AddLabel( 52, bottom - (buttons++ * 22), 2100, "Go to Page Location" );
if ( entry.SpeechLog != null )
{
AddButton( 18, bottom - (buttons * 22), 0xFA5, 0xFA7, 10, GumpButtonType.Reply, 0 );
AddLabel( 52, bottom - (buttons++ * 22), 2100, "View Speech Log" );
}
AddLabel( 18, 98, 2100, "Page Type:" );
AddLabelCropped( 128, 98, 264, 20, 2100, PageQueue.GetPageTypeName( entry.Type ) );
AddLabel( 18, 118, 2100, "Message:" );
AddHtml( 128, 118, 250, 100, entry.Message, true, true );
AddPage( 2 );
ArrayList preresp = PredefinedResponse.List;
AddButton( 18, 18, 0xFAE, 0xFB0, 0, GumpButtonType.Page, 1 );
AddButton( 410 - 18 - 32, 18, 0xFAB, 0xFAC, 9, GumpButtonType.Reply, 0 );
if ( preresp.Count == 0 )
{
AddLabel( 52, 18, 2100, "There are no predefined responses." );
}
else
{
AddLabel( 52, 18, 2100, "Back" );
for ( int i = 0; i < preresp.Count; ++i )
{
AddButton( 18, 40 + (i * 22), 0xFA5, 0xFA7, 100 + i, GumpButtonType.Reply, 0 );
AddLabel( 52, 40 + (i * 22), 2100, ((PredefinedResponse)preresp[i]).Title );
}
}
}
catch ( Exception e )
{
Console.WriteLine(e);
}
}
public void Resend( NetState state )
{
PageEntryGump g = new PageEntryGump( m_Mobile, m_Entry );
g.SendTo( state );
}
public override void OnResponse( NetState state, RelayInfo info )
{
if ( info.ButtonID != 0 && PageQueue.List.IndexOf( m_Entry ) < 0 )
{
state.Mobile.SendGump( new PageQueueGump() );
state.Mobile.SendMessage( "That page has been removed." );
return;
}
switch ( info.ButtonID )
{
case 0: // close
{
if ( m_Entry.Handler != state.Mobile )
{
PageQueueGump g = new PageQueueGump();
g.SendTo( state );
}
break;
}
case 1: // go to sender
{
Mobile m = state.Mobile;
if ( m_Entry.Sender.Deleted )
{
m.SendMessage( "That character no longer exists." );
}
else if ( m_Entry.Sender.Map == null || m_Entry.Sender.Map == Map.Internal )
{
m.SendMessage( "That character is not in the world." );
}
else
{
m_Entry.AddResponse( state.Mobile, "[Go Sender]" );
m.MoveToWorld( m_Entry.Sender.Location, m_Entry.Sender.Map );
m.SendMessage( "You have been teleported to that page's sender." );
Resend( state );
}
break;
}
case 2: // go to handler
{
Mobile m = state.Mobile;
Mobile h = m_Entry.Handler;
if ( h != null )
{
if ( h.Deleted )
{
m.SendMessage( "That character no longer exists." );
}
else if ( h.Map == null || h.Map == Map.Internal )
{
m.SendMessage( "That character is not in the world." );
}
else
{
m_Entry.AddResponse( state.Mobile, "[Go Handler]" );
m.MoveToWorld( h.Location, h.Map );
m.SendMessage( "You have been teleported to that page's handler." );
Resend( state );
}
}
else
{
m.SendMessage( "Nobody is handling that page." );
Resend( state );
}
break;
}
case 3: // go to page location
{
Mobile m = state.Mobile;
if ( m_Entry.PageMap == null || m_Entry.PageMap == Map.Internal )
{
m.SendMessage( "That location is not in the world." );
}
else
{
m_Entry.AddResponse( state.Mobile, "[Go PageLoc]" );
m.MoveToWorld( m_Entry.PageLocation, m_Entry.PageMap );
state.Mobile.SendMessage( "You have been teleported to the original page location." );
Resend( state );
}
break;
}
case 4: // handle page
{
if ( m_Entry.Handler == null )
{
m_Entry.AddResponse( state.Mobile, "[Handling]" );
m_Entry.Handler = state.Mobile;
state.Mobile.SendMessage( "You are now handling the page." );
}
else
{
state.Mobile.SendMessage( "Someone is already handling that page." );
}
Resend( state );
break;
}
case 5: // delete page
{
if ( m_Entry.Handler == null )
{
m_Entry.AddResponse( state.Mobile, "[Deleting]" );
PageQueue.Remove( m_Entry );
state.Mobile.SendMessage( "You delete the page." );
PageQueueGump g = new PageQueueGump();
g.SendTo( state );
}
else
{
state.Mobile.SendMessage( "Someone is handling that page, it can not be deleted." );
Resend( state );
}
break;
}
case 6: // abandon page
{
if ( m_Entry.Handler == state.Mobile )
{
m_Entry.AddResponse( state.Mobile, "[Abandoning]" );
state.Mobile.SendMessage( "You abandon the page." );
m_Entry.Handler = null;
}
else
{
state.Mobile.SendMessage( "You are not handling that page." );
}
Resend( state );
break;
}
case 7: // page handled
{
if ( m_Entry.Handler == state.Mobile )
{
m_Entry.AddResponse( state.Mobile, "[Handled]" );
PageQueue.Remove( m_Entry );
m_Entry.Handler = null;
state.Mobile.SendMessage( "You mark the page as handled, and remove it from the queue." );
PageQueueGump g = new PageQueueGump();
g.SendTo( state );
}
else
{
state.Mobile.SendMessage( "You are not handling that page." );
Resend( state );
}
break;
}
case 8: // Send message
{
TextRelay text = info.GetTextEntry( 0 );
if ( text != null )
{
m_Entry.AddResponse( state.Mobile, "[Response] " + text.Text );
m_Entry.Sender.SendGump( new MessageSentGump( m_Entry.Sender, state.Mobile.Name, text.Text ) );
//m_Entry.Sender.SendMessage( 0x482, "{0} tells you:", state.Mobile.Name );
//m_Entry.Sender.SendMessage( 0x482, text.Text );
}
Resend( state );
break;
}
case 9: // predef overview
{
Resend( state );
state.Mobile.SendGump( new PredefGump( state.Mobile, null ) );
break;
}
case 10: // View Speech Log
{
Resend( state );
if ( m_Entry.SpeechLog != null )
{
Gump gump = new SpeechLogGump( m_Entry.Sender, m_Entry.SpeechLog );
state.Mobile.SendGump( gump );
}
break;
}
default:
{
int index = info.ButtonID - 100;
ArrayList preresp = PredefinedResponse.List;
if ( index >= 0 && index < preresp.Count )
{
m_Entry.AddResponse( state.Mobile, "[PreDef] " + ((PredefinedResponse)preresp[index]).Title );
m_Entry.Sender.SendGump( new MessageSentGump( m_Entry.Sender, state.Mobile.Name, ((PredefinedResponse)preresp[index]).Message ) );
}
Resend( state );
break;
}
}
}
}
}

View file

@ -0,0 +1,39 @@
using System;
using Server;
using Server.Gumps;
using Server.Network;
namespace Server.Engines.Help
{
public class PageResponseGump : Gump
{
private Mobile m_From;
private string m_Name, m_Text;
public PageResponseGump( Mobile from, string name, string text ) : base( 0, 0 )
{
m_From = from;
m_Name = name;
m_Text = text;
AddBackground( 50, 25, 540, 430, 2600 );
AddPage( 0 );
AddHtmlLocalized( 150, 40, 360, 40, 1062610, false, false ); // <CENTER><U>Ultima Online Help Response</U></CENTER>
AddHtml( 80, 90, 480, 290, String.Format( "{0} tells {1}: {2}", name, from.Name, text ), true, true );
AddHtmlLocalized( 80, 390, 480, 40, 1062611, false, false ); // Clicking the OKAY button will remove the reponse you have received.
AddButton( 400, 417, 2074, 2075, 1, GumpButtonType.Reply, 0 ); // OKAY
AddButton( 475, 417, 2073, 2072, 0, GumpButtonType.Reply, 0 ); // CANCEL
}
public override void OnResponse( NetState sender, RelayInfo info )
{
if ( info.ButtonID != 1 )
m_From.SendGump( new MessageSentGump( m_From, m_Name, m_Text ) );
}
}
}

View file

@ -0,0 +1,148 @@
using System;
using System.Collections;
using Server;
using Server.Mobiles;
using Server.Targeting;
using Server.Gumps;
using Server.Commands;
using System.Collections.Generic;
namespace Server.Engines.Help
{
public class SpeechLog : IEnumerable<SpeechLogEntry>
{
// Are speech logs enabled?
public static readonly bool Enabled = true;
// How long should we maintain each speech entry?
public static readonly TimeSpan EntryDuration = TimeSpan.FromMinutes( 20.0 );
// What is the maximum number of entries a log can contain? (0 -> no limit)
public static readonly int MaxLength = 0;
public static void Initialize()
{
CommandSystem.Register( "SpeechLog", AccessLevel.Counselor, new CommandEventHandler( SpeechLog_OnCommand ) );
}
[Usage( "SpeechLog" )]
[Description( "Opens the speech log of a given target." )]
private static void SpeechLog_OnCommand( CommandEventArgs e )
{
Mobile from = e.Mobile;
from.SendMessage( "Target a player to view his speech log." );
e.Mobile.Target = new SpeechLogTarget();
}
private class SpeechLogTarget : Target
{
public SpeechLogTarget() : base( -1, false, TargetFlags.None )
{
}
protected override void OnTarget( Mobile from, object targeted )
{
PlayerMobile pm = targeted as PlayerMobile;
if ( pm == null )
{
from.SendMessage( "Speech logs aren't supported on that target." );
}
else if ( from != targeted && from.AccessLevel <= pm.AccessLevel && from.AccessLevel != AccessLevel.Owner )
{
from.SendMessage( "You don't have the required access level to view {0} speech log.", pm.Female ? "her" : "his" );
}
else if ( pm.SpeechLog == null )
{
from.SendMessage( "{0} has no speech log.", pm.Female ? "She" : "He" );
}
else
{
CommandLogging.WriteLine( from, "{0} {1} viewing speech log of {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( targeted ) );
Gump gump = new SpeechLogGump( pm, pm.SpeechLog );
from.SendGump( gump );
}
}
}
private Queue<SpeechLogEntry> m_Queue;
public int Count{ get{ return m_Queue.Count; } }
public SpeechLog()
{
m_Queue = new Queue<SpeechLogEntry>();
}
public void Add( Mobile from, string speech )
{
Add( new SpeechLogEntry( from, speech ) );
}
public void Add( SpeechLogEntry entry )
{
if ( MaxLength > 0 && m_Queue.Count >= MaxLength )
m_Queue.Dequeue();
Clean();
m_Queue.Enqueue( entry );
}
public void Clean()
{
while ( m_Queue.Count > 0 )
{
SpeechLogEntry entry = (SpeechLogEntry) m_Queue.Peek();
if ( DateTime.UtcNow - entry.Created > EntryDuration )
m_Queue.Dequeue();
else
break;
}
}
public void CopyTo( SpeechLogEntry[] array, int index )
{
m_Queue.CopyTo( array, index );
}
#region IEnumerable<SpeechLogEntry> Members
IEnumerator<SpeechLogEntry> IEnumerable<SpeechLogEntry>.GetEnumerator()
{
return m_Queue.GetEnumerator();
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return m_Queue.GetEnumerator();
}
#endregion
}
public class SpeechLogEntry
{
private Mobile m_From;
private string m_Speech;
private DateTime m_Created;
public Mobile From{ get{ return m_From; } }
public string Speech{ get{ return m_Speech; } }
public DateTime Created{ get{ return m_Created; } }
public SpeechLogEntry( Mobile from, string speech )
{
m_From = from;
m_Speech = speech;
m_Created = DateTime.UtcNow;
}
}
}

View file

@ -0,0 +1,112 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Server;
using Server.Gumps;
using Server.Accounting;
using Server.Network;
namespace Server.Engines.Help
{
public class SpeechLogGump : Gump
{
public static readonly int MaxEntriesPerPage = 30;
private Mobile m_Player;
private List<SpeechLogEntry> m_Log;
private int m_Page;
public SpeechLogGump( Mobile player, SpeechLog log )
: this( player, new List<SpeechLogEntry>( log ) )
{
}
public SpeechLogGump( Mobile player, List<SpeechLogEntry> log ) : this( player, log, ( log.Count - 1 ) / MaxEntriesPerPage )
{
}
public SpeechLogGump( Mobile player, List<SpeechLogEntry> log, int page )
: base( 500, 30 )
{
m_Player = player;
m_Log = log;
m_Page = page;
AddImageTiled( 0, 0, 300, 425, 0xA40 );
AddAlphaRegion( 1, 1, 298, 423 );
string playerName = player.Name;
string playerAccount = player.Account is Account ? player.Account.Username : "???";
AddHtml( 10, 10, 280, 20, String.Format( "<basefont color=#A0A0FF><center>SPEECH LOG - {0} (<i>{1}</i>)</center></basefont>", playerName, Utility.FixHtml( playerAccount ) ), false, false );
int lastPage = ( log.Count - 1 ) / MaxEntriesPerPage;
string sLog;
if ( page < 0 || page > lastPage )
{
sLog = "";
}
else
{
int max = log.Count - ( lastPage - page ) * MaxEntriesPerPage;
int min = Math.Max( max - MaxEntriesPerPage, 0 );
StringBuilder builder = new StringBuilder();
for ( int i = min; i < max; i++ )
{
SpeechLogEntry entry = log[i];
Mobile m = entry.From;
string name = m.Name;
string account = m.Account is Account ? m.Account.Username : "???";
string speech = entry.Speech;
if ( i != min )
builder.Append( "<br>" );
builder.AppendFormat( "<u>{0}</u> (<i>{1}</i>): {2}", name, Utility.FixHtml( account ), Utility.FixHtml( speech ) );
}
sLog = builder.ToString();
}
AddHtml( 10, 40, 280, 350, sLog, false, true );
if ( page > 0 )
AddButton( 10, 395, 0xFAE, 0xFB0, 1, GumpButtonType.Reply, 0 ); // Previous page
AddLabel( 45, 395, 0x481, String.Format( "Current page: {0}/{1}", page + 1, lastPage + 1 ) );
if ( page < lastPage )
AddButton( 261, 395, 0xFA5, 0xFA7, 2, GumpButtonType.Reply, 0 ); // Next page
}
public override void OnResponse( NetState sender, RelayInfo info )
{
Mobile from = sender.Mobile;
switch ( info.ButtonID )
{
case 1: // Previous page
{
if ( m_Page - 1 >= 0 )
from.SendGump( new SpeechLogGump( m_Player, m_Log, m_Page - 1 ) );
break;
}
case 2: // Next page
{
if ( ( m_Page + 1 ) * MaxEntriesPerPage < m_Log.Count )
from.SendGump( new SpeechLogGump( m_Player, m_Log, m_Page + 1 ) );
break;
}
}
}
}
}

View file

@ -0,0 +1,292 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Gumps;
namespace Server.Menus.Questions
{
public class StuckMenuEntry
{
private int m_Name;
private Point3D[] m_Locations;
public int Name{ get{ return m_Name; } }
public Point3D[] Locations{ get{ return m_Locations; } }
public StuckMenuEntry( int name, Point3D[] locations )
{
m_Name = name;
m_Locations = locations;
}
}
public class StuckMenu : Gump
{
private static StuckMenuEntry[] m_Entries = new StuckMenuEntry[]
{
// Britain
new StuckMenuEntry( 1011028, new Point3D[]
{
new Point3D( 1522, 1757, 28 ),
new Point3D( 1519, 1619, 10 ),
new Point3D( 1457, 1538, 30 ),
new Point3D( 1607, 1568, 20 ),
new Point3D( 1643, 1680, 18 )
} ),
// Trinsic
new StuckMenuEntry( 1011029, new Point3D[]
{
new Point3D( 2005, 2754, 30 ),
new Point3D( 1993, 2827, 0 ),
new Point3D( 2044, 2883, 0 ),
new Point3D( 1876, 2859, 20 ),
new Point3D( 1865, 2687, 0 )
} ),
// Vesper
new StuckMenuEntry( 1011030, new Point3D[]
{
new Point3D( 2973, 891, 0 ),
new Point3D( 3003, 776, 0 ),
new Point3D( 2910, 727, 0 ),
new Point3D( 2865, 804, 0 ),
new Point3D( 2832, 927, 0 )
} ),
// Minoc
new StuckMenuEntry( 1011031, new Point3D[]
{
new Point3D( 2498, 392, 0 ),
new Point3D( 2433, 541, 0 ),
new Point3D( 2445, 501, 15 ),
new Point3D( 2501, 469, 15 ),
new Point3D( 2444, 420, 15 )
} ),
// Yew
new StuckMenuEntry( 1011032, new Point3D[]
{
new Point3D( 490, 1166, 0 ),
new Point3D( 652, 1098, 0 ),
new Point3D( 650, 1013, 0 ),
new Point3D( 536, 979, 0 ),
new Point3D( 464, 970, 0 )
} ),
// Cove
new StuckMenuEntry( 1011033, new Point3D[]
{
new Point3D( 2230, 1159, 0 ),
new Point3D( 2218, 1203, 0 ),
new Point3D( 2247, 1194, 0 ),
new Point3D( 2236, 1224, 0 ),
new Point3D( 2273, 1231, 0 )
} )
};
private static StuckMenuEntry[] m_T2AEntries = new StuckMenuEntry[]
{
// Papua
new StuckMenuEntry( 1011057, new Point3D[]
{
new Point3D( 5720, 3109, -1 ),
new Point3D( 5677, 3176, -3 ),
new Point3D( 5678, 3227, 0 ),
new Point3D( 5769, 3206, -2 ),
new Point3D( 5777, 3270, -1 )
} ),
// Delucia
new StuckMenuEntry( 1011058, new Point3D[]
{
new Point3D( 5216, 4033, 37 ),
new Point3D( 5262, 4049, 37 ),
new Point3D( 5284, 4006, 37 ),
new Point3D( 5189, 3971, 39 ),
new Point3D( 5243, 3960, 37 )
} )
};
private static bool IsInSecondAgeArea( Mobile m )
{
if ( m.Map != Map.Trammel && m.Map != Map.Felucca )
return false;
if ( m.X >= 5120 && m.Y >= 2304 )
return true;
if ( m.Region.IsPartOf( "Terathan Keep" ) )
return true;
return false;
}
private Mobile m_Mobile, m_Sender;
private bool m_MarkUse;
private Timer m_Timer;
public StuckMenu( Mobile beholder, Mobile beheld, bool markUse ) : base( 150, 50 )
{
m_Sender = beholder;
m_Mobile = beheld;
m_MarkUse = markUse;
Closable = false;
Dragable = false;
Disposable = false;
AddBackground( 0, 0, 270, 320, 2600 );
AddHtmlLocalized( 50, 20, 250, 35, 1011027, false, false ); // Chose a town:
StuckMenuEntry[] entries = IsInSecondAgeArea( beheld ) ? m_T2AEntries : m_Entries;
for ( int i = 0; i < entries.Length; i++ )
{
StuckMenuEntry entry = entries[i];
AddButton( 50, 55 + 35 * i, 208, 209, i + 1, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 75, 55 + 35 * i, 335, 40, entry.Name, false, false );
}
AddButton( 55, 263, 4005, 4007, 0, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 90, 265, 200, 35, 1011012, false, false ); // CANCEL
}
public void BeginClose()
{
StopClose();
m_Timer = new CloseTimer( m_Mobile );
m_Timer.Start();
m_Mobile.Frozen = true;
}
public void StopClose()
{
if ( m_Timer != null )
m_Timer.Stop();
m_Mobile.Frozen = false;
}
public override void OnResponse( NetState state, RelayInfo info )
{
StopClose();
if ( Factions.Sigil.ExistsOn( m_Mobile ) )
{
m_Mobile.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil.
}
else if ( info.ButtonID == 0 )
{
if ( m_Mobile == m_Sender )
m_Mobile.SendLocalizedMessage( 1010588 ); // You choose not to go to any city.
}
else
{
int index = info.ButtonID - 1;
StuckMenuEntry[] entries = IsInSecondAgeArea( m_Mobile ) ? m_T2AEntries : m_Entries;
if ( index >= 0 && index < entries.Length )
Teleport( entries[index] );
}
}
private void Teleport( StuckMenuEntry entry )
{
if ( m_MarkUse )
{
m_Mobile.SendLocalizedMessage( 1010589 ); // You will be teleported within the next two minutes.
new TeleportTimer( m_Mobile, entry, TimeSpan.FromSeconds( 10.0 + (Utility.RandomDouble() * 110.0) ) ).Start();
if (m_Mobile is PlayerMobile)
((PlayerMobile)m_Mobile).UsedStuckMenu();
}
else
{
new TeleportTimer( m_Mobile, entry, TimeSpan.Zero ).Start();
}
}
private class CloseTimer : Timer
{
private Mobile m_Mobile;
private DateTime m_End;
public CloseTimer( Mobile m ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( 1.0 ) )
{
m_Mobile = m;
m_End = DateTime.UtcNow + TimeSpan.FromMinutes( 3.0 );
}
protected override void OnTick()
{
if ( m_Mobile.NetState == null || DateTime.UtcNow > m_End )
{
m_Mobile.Frozen = false;
m_Mobile.CloseGump( typeof( StuckMenu ) );
Stop();
}
else
{
m_Mobile.Frozen = true;
}
}
}
private class TeleportTimer : Timer
{
private Mobile m_Mobile;
private StuckMenuEntry m_Destination;
private DateTime m_End;
public TeleportTimer( Mobile mobile, StuckMenuEntry destination, TimeSpan delay ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( 1.0 ) )
{
Priority = TimerPriority.TwoFiftyMS;
m_Mobile = mobile;
m_Destination = destination;
m_End = DateTime.UtcNow + delay;
}
protected override void OnTick()
{
if ( DateTime.UtcNow < m_End )
{
m_Mobile.Frozen = true;
}
else
{
m_Mobile.Frozen = false;
Stop();
if ( Factions.Sigil.ExistsOn( m_Mobile ) )
{
m_Mobile.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil.
return;
}
int idx = Utility.Random( m_Destination.Locations.Length );
Point3D dest = m_Destination.Locations[idx];
Map destMap;
if ( m_Mobile.Map == Map.Trammel )
destMap = Map.Trammel;
else if ( m_Mobile.Map == Map.Felucca )
destMap = Map.Felucca;
else
destMap = m_Mobile.Kills >= 5 ? Map.Felucca : Map.Trammel;
Mobiles.BaseCreature.TeleportPets( m_Mobile, dest, destMap );
m_Mobile.MoveToWorld( dest, destMap );
}
}
}
}
}