Files
Unstable Kitsune b918192e4e Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
2023-11-28 23:20:26 -05:00

2229 lines
75 KiB
C#

using System;
using System.Data;
using System.IO;
using System.Collections;
using Server;
using Server.Items;
using Server.Network;
using Server.Gumps;
using Server.Targeting;
using System.Reflection;
using Server.Commands;
using CPA = Server.CommandPropertyAttribute;
using System.Xml;
using Server.Spells;
using System.Text;
using Server.Accounting;
using System.Diagnostics;
using System.Text.RegularExpressions;
using Server.Mobiles;
namespace Server.Engines.XmlSpawner2
{
public class XmlDialog : XmlAttachment
{
// speech entry
public class SpeechEntry
{
public int EntryNumber;
private int m_ID;
public string Text; // text displayed when the entry is activated
public string Keywords; // comma separated list of keywords that can be matched to activate the entry. If no keywords are present then it is automatically activated
public string Action; // action string
public string Condition; // condition test string
public string DependsOn; // the previous entrynumber required to activate this entry
public int Pause = 1; // pause in seconds before advancing to the next entry
public int PrePause = -1; // pause in seconds before saying the speech for this entry. -1 indicates the use of auto pause calculation based on triggering speech length.
public bool LockConversation = true; // flag to determine if the conversation locks to one player
public bool AllowNPCTrigger = false; // flag to determine if npc speech can trigger it
public MessageType SpeechStyle = MessageType.Regular;
public string Gump; // GUMP specification string
public int m_SpeechHue = -1; // speech hue
public bool IgnoreCarried = false; // ignore the TriggerOnCarried/NoTriggerOnCarried settings for the dialog when activating this entry
public int SpeechHue
{
get { return m_SpeechHue; }
set
{
// dont allow invalid hues
m_SpeechHue = value;
if (m_SpeechHue > 37852) m_SpeechHue = 37852;
}
}
public int ID
{
get { return m_ID; }
set
{
// dont allow ID modification of entry 0
if (EntryNumber == 0) return;
m_ID = value;
}
}
}
public static int defProximityRange = 3;
public static int defResetRange = 16;
public static TimeSpan defResetTime = TimeSpan.FromSeconds(60);
public static int defSpeechPace = 10;
private const string NPCDataSetName = "XmlQuestNPC";
private const string NPCPointName = "NPC";
private const string SpeechPointName = "SpeechEntry";
public static string DefsDir = "XmlQuestNPC";
private ArrayList m_SpeechEntries = new ArrayList(); // contains the list of speech entries
private int m_CurrentEntryNumber = -1; // used to determine which entry will be subject to modification by various entry editing calls
private SpeechEntry m_CurrentEntry;
private bool m_Running = true;
private int m_ProximityRange = defProximityRange;
private bool m_AllowGhostTriggering = false;
private AccessLevel m_TriggerAccessLevel = AccessLevel.Player;
private DateTime m_LastInteraction;
private TimeSpan m_ResetTime = defResetTime;
private int m_ResetRange = defResetRange;
private bool m_IsActive = false;
private InternalTimer m_Timer;
private string m_ConfigFile;
private Mobile m_ActivePlayer; // keep track of the player that is currently engaged in conversation so that other players speech can be ignored.
private int m_SpeechPace = defSpeechPace; // used for automatic prepause delay calculation. delayinsecs = speechlength/speechpace + 1
bool m_HoldProcessing;
private string m_ItemTriggerName;
private string m_NoItemTriggerName;
public ArrayList m_TextEntryBook;
private string m_ResponseString;
public string ResponseString
{
get { return m_ResponseString; }
set { m_ResponseString = value; }
}
public ArrayList SpeechEntries
{
get
{
return m_SpeechEntries;
}
set
{
m_SpeechEntries = value;
}
}
public Mobile ActivePlayer
{
get { return m_ActivePlayer; }
set { m_ActivePlayer = value; }
}
// a serial constructor is REQUIRED
public XmlDialog(ASerial serial)
: base(serial)
{
}
[Attachable]
public XmlDialog(string ConfigFile)
{
DoLoadNPC(null, ConfigFile);
}
[Attachable]
public XmlDialog()
{
EntryNumber = 0;
}
public void DeleteTextEntryBook()
{
if (m_TextEntryBook != null)
{
foreach (Item s in m_TextEntryBook)
s.Delete();
m_TextEntryBook = null;
}
}
private SpeechEntry GetEntry(int entryid)
{
if (entryid < 0) return null;
if (m_SpeechEntries == null)
{
m_SpeechEntries = new ArrayList();
}
// find the speech entry that matches the current entry number
foreach (SpeechEntry s in m_SpeechEntries)
{
if (s.EntryNumber == entryid)
return s;
}
// didnt find it so make a new entry
SpeechEntry newentry = new SpeechEntry();
newentry.EntryNumber = entryid;
newentry.ID = entryid;
m_SpeechEntries.Add(newentry);
return newentry;
}
private bool ValidMovementTrig(Mobile m)
{
if (m == null || m.Deleted) return false;
return (
((m is PlayerMobile && (m.AccessLevel <= TriggerAccessLevel))) &&
((!m.Body.IsGhost && !m_AllowGhostTriggering) || (m.Body.IsGhost && m_AllowGhostTriggering)));
}
private bool ValidSpeechTrig(Mobile m)
{
if (m == null || m.Deleted) return false;
bool allownpctrigger = false;
if (CurrentEntry != null)
{
allownpctrigger = CurrentEntry.AllowNPCTrigger;
}
return (
((m is PlayerMobile && (m.AccessLevel <= TriggerAccessLevel)) || (allownpctrigger && !(m is PlayerMobile))) &&
((!m.Body.IsGhost && !m_AllowGhostTriggering) || (m.Body.IsGhost && m_AllowGhostTriggering)));
}
[CommandProperty(AccessLevel.GameMaster)]
public AccessLevel TriggerAccessLevel
{
get
{
return m_TriggerAccessLevel;
}
set
{
m_TriggerAccessLevel = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public DateTime LastInteraction
{
get
{
return m_LastInteraction;
}
set
{
m_LastInteraction = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public bool DoReset
{
get { return false; }
set
{
if (value) Reset();
}
}
[CommandProperty(AccessLevel.GameMaster)]
public bool IsActive
{
get
{
return m_IsActive;
}
set
{
m_IsActive = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan GameTOD
{
get
{
int hours;
int minutes;
Map map = null;
int x = 0;
int y = 0;
if (AttachedTo is Item)
{
map = ((Item)AttachedTo).Map;
x = ((Item)AttachedTo).Location.X;
y = ((Item)AttachedTo).Location.Y;
}
else
if (AttachedTo is Mobile)
{
map = ((Mobile)AttachedTo).Map;
x = ((Mobile)AttachedTo).Location.X;
y = ((Mobile)AttachedTo).Location.Y;
}
Server.Items.Clock.GetTime(map, x, y, out hours, out minutes);
return (new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, hours, minutes, 0).TimeOfDay);
}
}
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan RealTOD
{
get
{
return DateTime.UtcNow.TimeOfDay;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int RealDay
{
get
{
return DateTime.UtcNow.Day;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int RealMonth
{
get
{
return DateTime.UtcNow.Month;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public DayOfWeek RealDayOfWeek
{
get
{
return DateTime.UtcNow.DayOfWeek;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public MoonPhase MoonPhase
{
get
{
Map map = null;
int x = 0;
int y = 0;
if (AttachedTo is Item)
{
map = ((Item)AttachedTo).Map;
x = ((Item)AttachedTo).Location.X;
y = ((Item)AttachedTo).Location.Y;
}
else
if (AttachedTo is Mobile)
{
map = ((Mobile)AttachedTo).Map;
x = ((Mobile)AttachedTo).Location.X;
y = ((Mobile)AttachedTo).Location.Y;
}
return Clock.GetMoonPhase(map, x, y);
}
}
[CommandProperty(AccessLevel.GameMaster)]
public bool AllowGhostTrig
{
get { return m_AllowGhostTriggering; }
set
{
m_AllowGhostTriggering = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public bool Running
{
get { return m_Running; }
set { m_Running = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan ResetTime
{
get { return m_ResetTime; }
set { m_ResetTime = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public int SpeechPace
{
get { return m_SpeechPace; }
set { m_SpeechPace = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public string Keywords
{
get
{
// return the keyword string for the current entry
if (m_CurrentEntry == null)
{
return null;
}
return m_CurrentEntry.Keywords;
}
set
{
// set the keyword string for the current entry
if (m_CurrentEntry == null)
{
return;
}
m_CurrentEntry.Keywords = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public string Action
{
get
{
if (m_CurrentEntry == null)
{
return null;
}
return m_CurrentEntry.Action;
}
set
{
if (m_CurrentEntry == null)
{
return;
}
m_CurrentEntry.Action = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public string Gump
{
get
{
if (m_CurrentEntry == null)
{
return null;
}
return m_CurrentEntry.Gump;
}
set
{
if (m_CurrentEntry == null)
{
return;
}
m_CurrentEntry.Gump = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int SpeechHue
{
get
{
if (m_CurrentEntry == null)
{
return 0;
}
return m_CurrentEntry.SpeechHue;
}
set
{
if (m_CurrentEntry == null)
{
return;
}
m_CurrentEntry.SpeechHue = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public string Condition
{
get
{
if (m_CurrentEntry == null)
{
return null;
}
return m_CurrentEntry.Condition;
}
set
{
if (m_CurrentEntry == null)
{
return;
}
m_CurrentEntry.Condition = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public string Text
{
get
{
if (m_CurrentEntry == null)
{
return null;
}
return m_CurrentEntry.Text;
}
set
{
if (m_CurrentEntry == null)
{
return;
}
m_CurrentEntry.Text = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public string DependsOn
{
get
{
// return the keyword string for the current entry
if (m_CurrentEntry == null)
{
return "-1";
}
return m_CurrentEntry.DependsOn;
}
set
{
// set the keyword string for the current entry
if (m_CurrentEntry == null)
{
return;
}
m_CurrentEntry.DependsOn = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public bool LockConversation
{
get
{
if (m_CurrentEntry == null)
{
return true;
}
return m_CurrentEntry.LockConversation;
}
set
{
if (m_CurrentEntry == null)
{
return;
}
m_CurrentEntry.LockConversation = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public bool IgnoreCarried
{
get
{
if (m_CurrentEntry == null)
{
return true;
}
return m_CurrentEntry.IgnoreCarried;
}
set
{
if (m_CurrentEntry == null)
{
return;
}
m_CurrentEntry.IgnoreCarried = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public MessageType SpeechStyle
{
get
{
if (m_CurrentEntry == null)
{
return MessageType.Regular;
}
return m_CurrentEntry.SpeechStyle;
}
set
{
if (m_CurrentEntry == null)
{
return;
}
m_CurrentEntry.SpeechStyle = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public bool AllowNPCTrigger
{
get
{
if (m_CurrentEntry == null)
{
return false;
}
return m_CurrentEntry.AllowNPCTrigger;
}
set
{
if (m_CurrentEntry == null)
{
return;
}
m_CurrentEntry.AllowNPCTrigger = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int Pause
{
get
{
if (m_CurrentEntry == null)
{
return -1;
}
return m_CurrentEntry.Pause;
}
set
{
if (m_CurrentEntry == null)
{
return;
}
m_CurrentEntry.Pause = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int PrePause
{
get
{
if (m_CurrentEntry == null)
{
return -1;
}
return m_CurrentEntry.PrePause;
}
set
{
if (m_CurrentEntry == null)
{
return;
}
m_CurrentEntry.PrePause = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int ID
{
get
{
if (m_CurrentEntry == null)
{
return -1;
}
return m_CurrentEntry.ID;
}
set
{
if (m_CurrentEntry == null)
{
return;
}
m_CurrentEntry.ID = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int EntryNumber
{
get { return m_CurrentEntryNumber; }
set
{
m_CurrentEntryNumber = value;
// get the entry corresponding to the number
m_CurrentEntry = GetEntry(m_CurrentEntryNumber);
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int ProximityRange
{
get { return m_ProximityRange; }
set
{
m_ProximityRange = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int ResetRange
{
get { return m_ResetRange; }
set
{
m_ResetRange = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public string ConfigFile
{
get { return m_ConfigFile; }
set
{
m_ConfigFile = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public bool LoadConfig
{
get { return false; }
set { if (value == true) DoLoadNPC(null, ConfigFile); }
}
[CommandProperty(AccessLevel.GameMaster)]
public string TriggerOnCarried
{
get { return m_ItemTriggerName; }
set
{
m_ItemTriggerName = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public string NoTriggerOnCarried
{
get { return m_NoItemTriggerName; }
set
{
m_NoItemTriggerName = value;
}
}
public SpeechEntry CurrentEntry
{
get { return m_CurrentEntry; }
set
{
// get the entry corresponding to the number
m_CurrentEntry = value;
if (m_CurrentEntry != null)
m_CurrentEntryNumber = m_CurrentEntry.EntryNumber;
else
m_CurrentEntryNumber = -1;
}
}
// see if the DependsOn property contains the specified id
public bool CheckDependsOn(SpeechEntry s, int id)
{
if (s == null || s.DependsOn == null) return false;
// parse the DependsOn string
string[] args = s.DependsOn.Split(',');
for (int i = 0; i < args.Length; i++)
{
try
{
if (int.Parse(args[i].Trim()) == id) return true;
}
catch { }
}
return false;
}
private SpeechEntry FindMatchingKeyword(Mobile from, string keyword, int currententryid)
{
if (m_SpeechEntries == null) return null;
ArrayList matchlist = new ArrayList();
// go through all of the speech entries and find those that depend on the current entry
foreach (SpeechEntry s in m_SpeechEntries)
{
// ignore self-referencing entries
if (CheckDependsOn(s, s.ID)) continue;
// start processing if set for spontaneous activation (banter), already active, or waiting in the default state
if (((CheckDependsOn(s, -1) || CheckDependsOn(s, -2)) && !IsActive) || (CheckDependsOn(s, currententryid) && (IsActive || currententryid == 0)))
{
// now check for any conditions as well
// check for any condition that must be met for this entry to be processed
if (s.Condition != null)
{
string status_str;
if (!BaseXmlSpawner.CheckPropertyString(null, this, s.Condition, from, out status_str))
{
continue;
}
}
// testing for keyword = null will handle calls from the OnTick
if ((keyword == null && s.Keywords == null))
{
// add it to the list of match candidates
matchlist.Add(s);
}
else
// parse the keyword string
if (keyword != null && s.Keywords != null)
{
string[] arglist = s.Keywords.Split(",".ToCharArray());
for (int i = 0; i < arglist.Length; i++)
{
if (arglist[i] == "*")
{
// special match anything expression (regex doesnt parse this well)
matchlist.Add(s);
break;
}
else
{
bool error = false;
Regex r = null;
string status_str = null;
try
{
r = new Regex(arglist[i], RegexOptions.IgnoreCase);
}
catch (Exception e) { error = true; status_str = e.Message; }
if (!error && r != null)
{
Match m = r.Match(keyword);
if (m.Success)
{
// add it to the list of match candidates
matchlist.Add(s);
break;
}
}
else
{
ReportError(from, String.Format("Bad regular expression: {0} ", status_str));
}
}
}
}
}
}
if (matchlist.Count > 0)
{
// found at least one match
// if there is more than one, then randomly pick one
int select = Utility.Random(matchlist.Count);
return (SpeechEntry)matchlist[select];
}
else
{
// didnt find a match
return null;
}
}
public static void DialogGumpCallback(Mobile from, object invoker, string response)
{
// insert the response into the triggering speech of the invoking attachment
if (invoker is XmlDialog)
{
XmlDialog xd = (XmlDialog)invoker;
xd.m_HoldProcessing = false;
xd.ProcessSpeech(from, response);
}
}
private void ExecuteGump(Mobile mob, string gumpstring)
{
if (gumpstring == null || gumpstring.Length <= 0) return;
string status_str = null;
Server.Mobiles.XmlSpawner.SpawnObject TheSpawn = new Server.Mobiles.XmlSpawner.SpawnObject(null, 0);
TheSpawn.TypeName = gumpstring;
string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(null, this, mob, gumpstring);
string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName);
Point3D loc = new Point3D(0, 0, 0);
Map map = null;
if (AttachedTo is Mobile)
{
Mobile m = AttachedTo as Mobile;
loc = m.Location;
map = m.Map;
}
else
if (AttachedTo is Item && ((Item)AttachedTo).Parent == null)
{
Item i = AttachedTo as Item;
loc = i.Location;
map = i.Map;
}
if (typeName == "GUMP")
{
BaseXmlSpawner.SpawnTypeKeyword(this, TheSpawn, typeName, substitutedtypeName, true, mob, loc, map, new XmlGumpCallback(DialogGumpCallback), out status_str, 0);
// hold processing until the gump response is completed
m_HoldProcessing = true;
}
else
{
status_str = "not a GUMP specification";
}
ReportError(mob, status_str);
}
private void ExecuteAction(Mobile mob, string action)
{
if (action == null || action.Length <= 0) return;
string status_str = null;
Server.Mobiles.XmlSpawner.SpawnObject TheSpawn = new Server.Mobiles.XmlSpawner.SpawnObject(null, 0);
TheSpawn.TypeName = action;
string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(null, this, mob, action);
string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName);
Point3D loc = new Point3D(0, 0, 0);
Map map = null;
if (AttachedTo is Mobile)
{
Mobile m = AttachedTo as Mobile;
loc = m.Location;
map = m.Map;
}
else
if (AttachedTo is Item && ((Item)AttachedTo).Parent == null)
{
Item i = AttachedTo as Item;
loc = i.Location;
map = i.Map;
}
if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName))
{
BaseXmlSpawner.SpawnTypeKeyword(AttachedTo, TheSpawn, typeName, substitutedtypeName, true, mob, loc, map, out status_str);
}
else
{
// its a regular type descriptor so find out what it is
Type type = SpawnerType.GetType(typeName);
try
{
string[] arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/");
object o = Server.Mobiles.XmlSpawner.CreateObject(type, arglist[0]);
if (o == null)
{
status_str = "invalid type specification: " + arglist[0];
}
else
if (o is Mobile)
{
Mobile m = (Mobile)o;
if (m is BaseCreature)
{
BaseCreature c = (BaseCreature)m;
c.Home = loc; // Spawners location is the home point
}
m.Location = loc;
m.Map = map;
BaseXmlSpawner.ApplyObjectStringProperties(null, substitutedtypeName, m, mob, AttachedTo, out status_str);
}
else
if (o is Item)
{
Item item = (Item)o;
BaseXmlSpawner.AddSpawnItem(null, AttachedTo, TheSpawn, item, loc, map, mob, false, substitutedtypeName, out status_str);
}
}
catch { }
}
ReportError(mob, status_str);
}
private void ReportError(Mobile mob, string status_str)
{
if (status_str != null && mob != null && !mob.Deleted && mob is PlayerMobile && mob.AccessLevel > AccessLevel.Player)
{
mob.SendMessage(33, String.Format("{0}:{1}", AttachedTo.GetType().Name, status_str));
}
}
public override bool HandlesOnSpeech
{
get { return (m_Running); }
}
public override void OnSpeech(SpeechEventArgs e)
{
if (e.Mobile == null) return;
// dont handle your own speech
if (e.Mobile == AttachedTo as Mobile || e.Mobile.AccessLevel > TriggerAccessLevel)
{
e.Handled = false;
return;
}
if (m_HoldProcessing) return;
bool lockconversation = true;
bool ishandled = false;
Point3D loc = new Point3D(0, 0, 0);
Map map;
if (AttachedTo is Mobile)
{
Mobile m = AttachedTo as Mobile;
loc = m.Location;
map = m.Map;
}
else
if (AttachedTo is Item && ((Item)AttachedTo).Parent == null)
{
Item i = AttachedTo as Item;
loc = i.Location;
map = i.Map;
}
if (CurrentEntry != null)
{
lockconversation = CurrentEntry.LockConversation;
}
if (!e.Handled && m_Running && m_ProximityRange >= 0 && ValidSpeechTrig(e.Mobile) && ((e.Mobile == m_ActivePlayer) || !lockconversation || m_ActivePlayer == null))
{
if (!Utility.InRange(e.Mobile.Location, loc, m_ProximityRange))
return;
CheckForReset();
// process the current speech entry
ishandled = ProcessSpeech(e.Mobile, e.Speech);
// check to make sure the timer is running
DoTimer(TimeSpan.FromSeconds(1), m_ActivePlayer);
}
if (!ishandled)
{
base.OnSpeech(e);
}
}
public override bool HandlesOnMovement { get { return (m_Running); } }
public override void OnMovement(MovementEventArgs e)
{
Mobile m = e.Mobile;
if (m == null || m.AccessLevel > TriggerAccessLevel) return;
Point3D loc = new Point3D(0, 0, 0);
Map map;
if (AttachedTo is Mobile)
{
Mobile mob = AttachedTo as Mobile;
loc = mob.Location;
map = mob.Map;
}
else
if (AttachedTo is Item && ((Item)AttachedTo).Parent == null)
{
Item i = AttachedTo as Item;
loc = i.Location;
map = i.Map;
}
// if proximity sensing is off, a speech entry has been activated, or player is an admin then ignore
if (m_Running && m_ProximityRange >= 0 && ValidMovementTrig(m) && !IsActive && !m_HoldProcessing)
{
// check to see if player is within range of the npc
if (Utility.InRange(m.Location, loc, m_ProximityRange))
{
TimeSpan pause = TimeSpan.FromSeconds(0);
if (CurrentEntry != null && CurrentEntry.Pause > 0)
{
pause = TimeSpan.FromSeconds(CurrentEntry.Pause);
}
// check to see if the current pause interval has elapsed
if (DateTime.UtcNow - pause > m_LastInteraction)
{
// process speech that is not keyword dependent
CheckForReset();
ProcessSpeech(m, null);
}
// turn on the timer that will run until the speech list is reset
// it will control paused speech and will allow the speech entry to be reset after ResetTime timeout
DoTimer(TimeSpan.FromSeconds(1), m);
}
}
else
{
CheckForReset();
}
base.OnMovement(e);
}
private bool IsInRange(IEntity e1, IEntity e2, int range)
{
if (e1 == null || e2 == null) return false;
if (e1.Map != e2.Map) return false;
return Utility.InRange(e1.Location, e2.Location, range);
}
private void CheckForReset()
{
// check to see if the interaction time has elapsed or player has gone out of range. If so then reset to entry zero
if (!m_HoldProcessing &&
((DateTime.UtcNow - ResetTime > m_LastInteraction) ||
(AttachedTo is IEntity && m_ActivePlayer != null && !IsInRange(m_ActivePlayer, (IEntity)AttachedTo, ResetRange))))
{
Reset();
}
}
private void Reset()
{
EntryNumber = 0;
IsActive = false;
m_ActivePlayer = null;
// turn off the timer
if (m_Timer != null)
m_Timer.Stop();
}
private void DelayedSpeech(object state)
{
object[] states = (object[])state;
SpeechEntry matchentry = (SpeechEntry)states[0];
Mobile m = (Mobile)states[1];
if (matchentry != null)
{
CurrentEntry = matchentry;
string text = BaseXmlSpawner.ApplySubstitution(null, this, m, CurrentEntry.Text);
if (text != null)
{
// dont know why emote doesnt work, but we'll just do it manually
if (CurrentEntry.SpeechStyle == MessageType.Emote)
{
text = String.Format("*{0}*", text);
}
// items cannot produce actual speech
// display a message over the item it was attached to
if (AttachedTo is Item)
{
int speechhue = 0x3B2;
if (CurrentEntry.SpeechHue >= 0)
{
speechhue = CurrentEntry.SpeechHue;
}
((Item)AttachedTo).PublicOverheadMessage(MessageType.Regular, speechhue, true, text);
}
else
if (AttachedTo is Mobile)
{
// mobiles can produce actual speech
// so let them. This allows mobiles to talk with one another
int speechhue = ((Mobile)AttachedTo).SpeechHue;
if (CurrentEntry.SpeechHue >= 0)
{
speechhue = CurrentEntry.SpeechHue;
}
((Mobile)AttachedTo).DoSpeech(text, new int[] { }, CurrentEntry.SpeechStyle, speechhue);
//((Mobile)AttachedTo).PublicOverheadMessage( MessageType.Regular, 0x3B2, true, text );
}
}
IsActive = true;
m_LastInteraction = DateTime.UtcNow;
// execute any action associated with it
// allow for multiple action strings on a single line separated by a semicolon
if (CurrentEntry.Action != null && CurrentEntry.Action.Length > 0)
{
string[] args = CurrentEntry.Action.Split(';');
for (int j = 0; j < args.Length; j++)
{
ExecuteAction(m, args[j]);
}
}
// execute any GUMP associated with it
ExecuteGump(m, CurrentEntry.Gump);
}
m_HoldProcessing = false;
}
public bool ProcessSpeech(Mobile m, string speech)
{
if (m_HoldProcessing) return true;
// check the speech against the entries that depend on the present entry
SpeechEntry matchentry = FindMatchingKeyword(m, speech, ID);
if (matchentry == null) return false;
// when attempting to process speech-triggered speech, check for oncarried dependencies
// This will not apply to movement-triggered speech (banter with -1 dependson) which will continue to be activated
// regardless of oncarried status
// dependson of -2 will allow non-speech triggering but will still apply oncarried dependencies
// if player-carried item triggering is set then test for the presence of an item on the player an in their pack
if ((speech != null || CheckDependsOn(matchentry, -2)) && TriggerOnCarried != null && TriggerOnCarried.Length > 0)
{
bool found = BaseXmlSpawner.CheckForCarried(m, TriggerOnCarried) || matchentry.IgnoreCarried;
// is the player carrying the right item, if not then dont process
if (!found) return false;
}
// if player-carried noitem triggering is set then test for the presence of an item in the players pack that should block triggering
if ((speech != null || CheckDependsOn(matchentry, -2)) && NoTriggerOnCarried != null && NoTriggerOnCarried.Length > 0)
{
bool notfound = BaseXmlSpawner.CheckForNotCarried(m, NoTriggerOnCarried) || matchentry.IgnoreCarried;
// is the player carrying the right item, if so then dont process
if (!notfound) return false;
}
ResponseString = speech;
// the player that successfully activates a conversation by speech becomes the exclusive conversationalist until the npc resets
if ((speech != null || LockConversation) && m != null)
m_ActivePlayer = m;
// calculate the delay before activating the entry
int prepause = 1; // 1 sec by default
if (matchentry.PrePause < 0)
{
if (SpeechPace > 0 && speech != null)
{
// do the auto delay calculation based on the length of the triggering speech
prepause = (speech.Length / SpeechPace) + 1; // make 1 sec the min pause
}
}
else
{
prepause = matchentry.PrePause;
}
// and switch to the one that matches
m_HoldProcessing = true;
Timer.DelayCall(TimeSpan.FromSeconds(prepause), new TimerStateCallback(DelayedSpeech), new object[] { matchentry, m });
return true;
}
public void DoTimer(TimeSpan delay, Mobile trigmob)
{
if (!m_Running)
return;
if (m_Timer != null)
m_Timer.Stop();
m_Timer = new InternalTimer(this, delay, trigmob);
m_Timer.Start();
}
private class InternalTimer : Timer
{
private XmlDialog m_npc;
public Mobile m_trigmob;
public TimeSpan m_delay;
public InternalTimer(XmlDialog npc, TimeSpan delay, Mobile trigmob)
: base(delay, delay)
{
Priority = TimerPriority.OneSecond;
m_npc = npc;
m_trigmob = trigmob;
m_delay = delay;
}
protected override void OnTick()
{
if (m_npc != null && !m_npc.Deleted)
{
// check to see if any speech needs to be processed
TimeSpan pause = TimeSpan.FromSeconds(0);
if (m_npc.CurrentEntry != null && m_npc.CurrentEntry.Pause > 0)
{
pause = TimeSpan.FromSeconds(m_npc.CurrentEntry.Pause);
}
// check to see if the current pause interval has elapsed
if (DateTime.UtcNow - pause > m_npc.LastInteraction)
{
// process speech that is not keyword dependent
m_npc.ProcessSpeech(m_trigmob, null);
m_npc.CheckForReset();
}
}
else
{
Stop();
}
}
}
public void DoLoadNPC(Mobile from, string filename)
{
if (filename == null || filename.Length <= 0) return;
string dirname;
if (System.IO.Directory.Exists(DefsDir) == true)
{
// look for it in the defaults directory
dirname = String.Format("{0}/{1}.npc", DefsDir, filename);
// Check if the file exists
if (System.IO.File.Exists(dirname) == false)
{
// didnt find it so just look in the main install dir
dirname = String.Format("{0}.npc", filename);
}
}
else
{
// look in the main installation dir
dirname = String.Format("{0}.npc", filename);
}
// Check if the file exists
if (System.IO.File.Exists(dirname) == true)
{
FileStream fs = null;
try
{
fs = File.Open(dirname, FileMode.Open, FileAccess.Read);
}
catch { }
if (fs == null)
{
from.SendMessage("Unable to open {0} for loading", dirname);
return;
}
// Create the data set
DataSet ds = new DataSet(NPCDataSetName);
// Read in the file
bool fileerror = false;
try
{
ds.ReadXml(fs);
}
catch { fileerror = true; }
// close the file
fs.Close();
if (fileerror)
{
if (from != null && !from.Deleted)
from.SendMessage(33, "Error reading npc file {0}", dirname);
return;
}
// Check that at least a single table was loaded
if (ds.Tables != null && ds.Tables.Count > 0)
{
// get the npc info
if (ds.Tables[NPCPointName] != null && ds.Tables[NPCPointName].Rows.Count > 0)
{
DataRow dr = ds.Tables[NPCPointName].Rows[0];
try
{
if (AttachedTo is Item)
{
((Item)AttachedTo).Name = (string)dr["Name"];
}
else
if (AttachedTo is Mobile)
{
((Mobile)AttachedTo).Name = (string)dr["Name"];
}
}
catch { }
try { this.ProximityRange = int.Parse((string)dr["ProximityRange"]); }
catch { }
try { this.ResetRange = int.Parse((string)dr["ResetRange"]); }
catch { }
try { this.TriggerOnCarried = (string)dr["TriggerOnCarried"]; }
catch { }
try { this.NoTriggerOnCarried = (string)dr["NoTriggerOnCarried"]; }
catch { }
try { this.m_AllowGhostTriggering = bool.Parse((string)dr["AllowGhost"]); }
catch { }
try { this.m_SpeechPace = int.Parse((string)dr["SpeechPace"]); }
catch { }
try { this.Running = bool.Parse((string)dr["Running"]); }
catch { }
try { this.ResetTime = TimeSpan.FromMinutes(double.Parse((string)dr["ResetTime"])); }
catch { }
try { this.ConfigFile = (string)dr["ConfigFile"]; }
catch { }
int entrycount = 0;
try { entrycount = int.Parse((string)dr["SpeechEntries"]); }
catch { }
}
// get the speech entry info
if (ds.Tables[NPCPointName] != null && ds.Tables[NPCPointName].Rows.Count > 0)
{
m_SpeechEntries = new ArrayList();
foreach (DataRow dr in ds.Tables[SpeechPointName].Rows)
{
SpeechEntry s = new SpeechEntry();
// Populate the speech entry data
try { s.EntryNumber = int.Parse((string)dr["EntryNumber"]); }
catch { }
try { s.ID = int.Parse((string)dr["ID"]); }
catch { }
try { s.Text = (string)dr["Text"]; }
catch { }
try { s.Keywords = (string)dr["Keywords"]; }
catch { }
try { s.Action = (string)dr["Action"]; }
catch { }
try { s.Condition = (string)dr["Condition"]; }
catch { }
try { s.DependsOn = (string)dr["DependsOn"]; }
catch { }
try { s.Pause = int.Parse((string)dr["Pause"]); }
catch { }
try { s.PrePause = int.Parse((string)dr["PrePause"]); }
catch { }
try { s.LockConversation = bool.Parse((string)dr["LockConversation"]); }
catch { }
try { s.IgnoreCarried = bool.Parse((string)dr["IgnoreCarried"]); }
catch { }
try { s.AllowNPCTrigger = bool.Parse((string)dr["AllowNPCTrigger"]); }
catch { }
try { s.SpeechStyle = (MessageType)Enum.Parse(typeof(MessageType), (string)dr["SpeechStyle"]); }
catch { }
try { s.SpeechHue = int.Parse((string)dr["SpeechHue"]); }
catch { }
try { s.Gump = (string)dr["Gump"]; }
catch { }
m_SpeechEntries.Add(s);
}
}
Reset();
if (from != null && !from.Deleted)
from.SendMessage("Loaded npc from file {0}", dirname);
}
else
{
if (from != null && !from.Deleted)
from.SendMessage(33, "No npc data found in: {0}", dirname);
}
}
else
{
if (from != null && !from.Deleted)
from.SendMessage(33, "File not found: {0}", dirname);
}
}
public void DoSaveNPC(Mobile from, string filename, bool updateconfig)
{
if (filename == null || filename.Length <= 0) return;
// Create the data set
DataSet ds = new DataSet(NPCDataSetName);
// Load the data set up
ds.Tables.Add(NPCPointName);
ds.Tables.Add(SpeechPointName);
// Create a schema for the npc
ds.Tables[NPCPointName].Columns.Add("Name");
ds.Tables[NPCPointName].Columns.Add("Running");
ds.Tables[NPCPointName].Columns.Add("ProximityRange");
ds.Tables[NPCPointName].Columns.Add("ResetRange");
ds.Tables[NPCPointName].Columns.Add("TriggerOnCarried");
ds.Tables[NPCPointName].Columns.Add("NoTriggerOnCarried");
ds.Tables[NPCPointName].Columns.Add("AllowGhost");
ds.Tables[NPCPointName].Columns.Add("SpeechPace");
ds.Tables[NPCPointName].Columns.Add("ResetTime");
ds.Tables[NPCPointName].Columns.Add("ConfigFile");
ds.Tables[NPCPointName].Columns.Add("SpeechEntries");
// Create a schema for the speech entries
ds.Tables[SpeechPointName].Columns.Add("EntryNumber");
ds.Tables[SpeechPointName].Columns.Add("ID");
ds.Tables[SpeechPointName].Columns.Add("Text");
ds.Tables[SpeechPointName].Columns.Add("Keywords");
ds.Tables[SpeechPointName].Columns.Add("Action");
ds.Tables[SpeechPointName].Columns.Add("Condition");
ds.Tables[SpeechPointName].Columns.Add("DependsOn");
ds.Tables[SpeechPointName].Columns.Add("Pause");
ds.Tables[SpeechPointName].Columns.Add("PrePause");
ds.Tables[SpeechPointName].Columns.Add("LockConversation");
ds.Tables[SpeechPointName].Columns.Add("IgnoreCarried");
ds.Tables[SpeechPointName].Columns.Add("AllowNPCTrigger");
ds.Tables[SpeechPointName].Columns.Add("SpeechStyle");
ds.Tables[SpeechPointName].Columns.Add("SpeechHue");
ds.Tables[SpeechPointName].Columns.Add("Gump");
// Create a new data row
DataRow dr = ds.Tables[NPCPointName].NewRow();
// Populate the npc data
if (AttachedTo is Item)
{
dr["Name"] = (string)((Item)AttachedTo).Name;
}
else
if (AttachedTo is Mobile)
{
dr["Name"] = (string)((Mobile)AttachedTo).Name;
}
dr["Running"] = (bool)this.Running;
dr["ProximityRange"] = (int)this.m_ProximityRange;
dr["ResetRange"] = (int)this.m_ResetRange;
dr["TriggerOnCarried"] = (string)this.TriggerOnCarried;
dr["NoTriggerOnCarried"] = (string)this.NoTriggerOnCarried;
dr["AllowGhost"] = (bool)this.m_AllowGhostTriggering;
dr["SpeechPace"] = (int)this.SpeechPace;
dr["ResetTime"] = (double)this.ResetTime.TotalMinutes;
dr["ConfigFile"] = (string)this.ConfigFile;
int entrycount = 0;
if (SpeechEntries != null)
{
entrycount = SpeechEntries.Count;
}
dr["SpeechEntries"] = (int)entrycount;
// Add the row the the table
ds.Tables[NPCPointName].Rows.Add(dr);
for (int i = 0; i < entrycount; i++)
{
SpeechEntry s = (SpeechEntry)SpeechEntries[i];
// Create a new data row
dr = ds.Tables[SpeechPointName].NewRow();
// Populate the speech entry data
dr["EntryNumber"] = (int)s.EntryNumber;
dr["ID"] = (int)s.ID;
dr["Text"] = (string)s.Text;
dr["Keywords"] = (string)s.Keywords;
dr["Action"] = (string)s.Action;
dr["Condition"] = (string)s.Condition;
dr["DependsOn"] = (string)s.DependsOn;
dr["Pause"] = (int)s.Pause;
dr["PrePause"] = (int)s.PrePause;
dr["LockConversation"] = (bool)s.LockConversation;
dr["IgnoreCarried"] = (bool)s.IgnoreCarried;
dr["AllowNPCTrigger"] = (bool)s.AllowNPCTrigger;
dr["SpeechStyle"] = (MessageType)s.SpeechStyle;
dr["SpeechHue"] = (int)s.SpeechHue;
dr["Gump"] = (string)s.Gump;
// Add the row the the table
ds.Tables[SpeechPointName].Rows.Add(dr);
}
// Write out the file
string dirname;
if (System.IO.Directory.Exists(DefsDir) == true)
{
// put it in the defaults directory if it exists
dirname = String.Format("{0}/{1}.npc", DefsDir, filename);
}
else
{
// otherwise just put it in the main installation dir
dirname = String.Format("{0}.npc", filename);
}
// check to see if the file already exists
if (System.IO.File.Exists(dirname) == true)
{
// prompt the user to save over it
if (from != null)
{
from.SendGump(new ConfirmSaveGump(this, ds, dirname, filename, updateconfig));
}
}
else
{
SaveFile(from, ds, dirname, filename, updateconfig);
}
}
public bool SaveFile(Mobile from, DataSet ds, string dirname, string configname, bool updateconfig)
{
if (ds == null)
{
if (from != null && !from.Deleted)
from.SendMessage("Empty dataset. File {0} not saved.", dirname);
return false;
}
bool file_error = false;
try
{
ds.WriteXml(dirname);
}
catch { file_error = true; }
if (file_error)
{
if (from != null && !from.Deleted)
from.SendMessage("Error trying to save to file {0}", dirname);
return false;
}
else
{
if (from != null && !from.Deleted)
from.SendMessage("Saved npc to file {0}", dirname);
if (updateconfig)
ConfigFile = configname;
}
return true;
}
public class ConfirmSaveGump : Gump
{
private XmlDialog m_dialog;
private DataSet m_ds;
private string m_filename;
private string m_configname;
private bool m_updateconfig;
public ConfirmSaveGump(XmlDialog dialog, DataSet ds, string filename, string configname, bool updateconfig)
: base(0, 0)
{
m_dialog = dialog;
m_ds = ds;
m_filename = filename;
m_configname = configname;
m_updateconfig = updateconfig;
Closable = false;
Dragable = true;
AddPage(0);
AddBackground(10, 200, 200, 130, 5054);
AddLabel(20, 210, 33, String.Format("{0} exists.", filename));
AddLabel(20, 230, 33, String.Format("Overwrite?", filename));
AddRadio(35, 255, 9721, 9724, false, 1); // accept/yes radio
AddRadio(135, 255, 9721, 9724, true, 2); // decline/no radio
AddHtmlLocalized(72, 255, 200, 30, 1049016, 0x7fff, false, false); // Yes
AddHtmlLocalized(172, 255, 200, 30, 1049017, 0x7fff, false, false); // No
AddButton(80, 289, 2130, 2129, 3, GumpButtonType.Reply, 0); // Okay button
}
public override void OnResponse(NetState state, RelayInfo info)
{
if (info == null || state == null || state.Mobile == null) return;
int radiostate = -1;
if (info.Switches.Length > 0)
{
radiostate = info.Switches[0];
}
switch (info.ButtonID)
{
default:
{
if (radiostate == 1)
{ // accept
if (m_dialog != null)
m_dialog.SaveFile(state.Mobile, m_ds, m_filename, m_configname, m_updateconfig);
}
else
{
state.Mobile.SendMessage("File {0} not saved.", m_filename);
}
break;
}
}
}
}
[Usage("XmlSaveNPC filename")]
[Description("Saves the targeted Talking NPC to an xml file.")]
public static void SaveNPC_OnCommand(CommandEventArgs e)
{
e.Mobile.Target = new SaveNPCTarget(e);
}
private class SaveNPCTarget : Target
{
private CommandEventArgs m_e;
public SaveNPCTarget(CommandEventArgs e)
: base(30, false, TargetFlags.None)
{
m_e = e;
}
protected override void OnTarget(Mobile from, object targeted)
{
string filename = m_e.GetString(0);
if (filename == null || filename.Length <= 0)
{
from.SendMessage("must specify a save filename");
return;
}
// save the XmlDialog attachment info to xml
XmlDialog xa = XmlAttach.FindAttachment(targeted, typeof(XmlDialog)) as XmlDialog;
if (xa != null)
{
xa.DoSaveNPC(from, filename, false);
}
else
{
from.SendMessage("Must target a Talking NPC");
}
}
}
[Usage("XmlLoadNPC filename")]
[Description("Loads the targeted Talking NPC to an xml file.")]
public static void LoadNPC_OnCommand(CommandEventArgs e)
{
e.Mobile.Target = new LoadNPCTarget(e);
}
private class LoadNPCTarget : Target
{
private CommandEventArgs m_e;
public LoadNPCTarget(CommandEventArgs e)
: base(30, false, TargetFlags.None)
{
m_e = e;
}
protected override void OnTarget(Mobile from, object targeted)
{
string filename = m_e.GetString(0);
if (filename == null || filename.Length <= 0)
{
from.SendMessage("must specify a load filename");
return;
}
// load the XmlDialog attachment
XmlDialog xa = XmlAttach.FindAttachment(targeted, typeof(XmlDialog)) as XmlDialog;
if (xa != null)
{
xa.DoLoadNPC(from, filename);
}
else
{
// doesnt have a dialog attachment, so add and load
xa = new XmlDialog(filename);
XmlAttach.AttachTo(targeted, xa);
}
}
}
public static bool AssignSettings(string argname, string value)
{
switch (argname)
{
case "XmlQuestNPCDir":
DefsDir = value;
break;
case "defResetTime":
defResetTime = TimeSpan.FromSeconds(XmlSpawner.ConvertToInt(value));
break;
case "defProximityRange":
defProximityRange = XmlSpawner.ConvertToInt(value);
break;
case "defResetRange":
defResetRange = XmlSpawner.ConvertToInt(value);
break;
case "defSpeechPace":
defSpeechPace = XmlSpawner.ConvertToInt(value);
break;
default:
return false;
}
return true;
}
public new static void Initialize()
{
XmlSpawner.LoadSettings(new XmlSpawner.AssignSettingsHandler(AssignSettings), "XmlDialog");
CommandSystem.Register("SaveNPC", AccessLevel.Administrator, new CommandEventHandler(SaveNPC_OnCommand));
CommandSystem.Register("LoadNPC", AccessLevel.Administrator, new CommandEventHandler(LoadNPC_OnCommand));
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)9); // version
// Version 9 added the ResetRange property
writer.Write(m_ResetRange);
// Version 8 added the IgnoreCarried property
if (m_SpeechEntries != null)
{
writer.Write((int)m_SpeechEntries.Count);
foreach (SpeechEntry s in m_SpeechEntries)
{
writer.Write(s.IgnoreCarried);
}
}
else
{
writer.Write((int)0);
}
// Version 7
// changed DependsOn to a string
// Version 6
// write out the additional speech entry fields
if (m_SpeechEntries != null)
{
writer.Write((int)m_SpeechEntries.Count);
foreach (SpeechEntry s in m_SpeechEntries)
{
writer.Write(s.SpeechHue);
}
}
else
{
writer.Write((int)0);
}
// Version 5
// write out the additional speech entry fields
if (m_SpeechEntries != null)
{
writer.Write((int)m_SpeechEntries.Count);
foreach (SpeechEntry s in m_SpeechEntries)
{
writer.Write(s.Gump);
}
}
else
{
writer.Write((int)0);
}
// Version 4
// write out the additional speech entry fields
if (m_SpeechEntries != null)
{
writer.Write((int)m_SpeechEntries.Count);
foreach (SpeechEntry s in m_SpeechEntries)
{
writer.Write(s.Condition);
}
}
else
{
writer.Write((int)0);
}
// Version 3
writer.Write(TriggerOnCarried);
writer.Write(NoTriggerOnCarried);
// Version 2
writer.Write(m_SpeechPace);
// write out the additional speech entry fields
if (m_SpeechEntries != null)
{
writer.Write((int)m_SpeechEntries.Count);
foreach (SpeechEntry s in m_SpeechEntries)
{
writer.Write(s.PrePause);
writer.Write(s.LockConversation);
writer.Write(s.AllowNPCTrigger);
writer.Write((int)s.SpeechStyle);
}
}
else
{
writer.Write((int)0);
}
// Version 1
writer.Write(m_ActivePlayer);
// Version 0
writer.Write(m_IsActive);
writer.Write(m_ResetTime);
writer.Write(m_LastInteraction);
writer.Write(m_AllowGhostTriggering);
writer.Write(m_ProximityRange);
writer.Write(m_Running);
writer.Write(m_ConfigFile);
// write out the speech entries
if (m_SpeechEntries != null)
{
writer.Write((int)m_SpeechEntries.Count);
foreach (SpeechEntry s in m_SpeechEntries)
{
writer.Write(s.EntryNumber);
writer.Write(s.ID);
writer.Write(s.Text);
writer.Write(s.Keywords);
writer.Write(s.Action);
writer.Write(s.DependsOn);
writer.Write(s.Pause);
}
}
else
{
writer.Write((int)0);
}
writer.Write(m_CurrentEntryNumber);
// check to see if the timer is running
if (m_Timer != null && m_Timer.Running)
{
writer.Write(true);
writer.Write(m_Timer.m_trigmob);
writer.Write(m_Timer.m_delay);
}
else
{
writer.Write(false);
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 9:
{
m_ResetRange = reader.ReadInt();
goto case 8;
}
case 8:
{
int count = reader.ReadInt();
m_SpeechEntries = new ArrayList();
for (int i = 0; i < count; i++)
{
SpeechEntry newentry = new SpeechEntry();
newentry.IgnoreCarried = reader.ReadBool();
m_SpeechEntries.Add(newentry);
}
goto case 7;
}
case 7:
{
goto case 6;
}
case 6:
{
int count = reader.ReadInt();
if (version < 8)
{
m_SpeechEntries = new ArrayList();
}
for (int i = 0; i < count; i++)
{
if (version < 8)
{
SpeechEntry newentry = new SpeechEntry();
newentry.SpeechHue = reader.ReadInt();
m_SpeechEntries.Add(newentry);
}
else
{
SpeechEntry newentry = (SpeechEntry)m_SpeechEntries[i];
newentry.SpeechHue = reader.ReadInt();
}
}
goto case 5;
}
case 5:
{
int count = reader.ReadInt();
if (version < 6)
{
m_SpeechEntries = new ArrayList();
}
for (int i = 0; i < count; i++)
{
if (version < 6)
{
SpeechEntry newentry = new SpeechEntry();
newentry.Gump = reader.ReadString();
m_SpeechEntries.Add(newentry);
}
else
{
SpeechEntry newentry = (SpeechEntry)m_SpeechEntries[i];
newentry.Gump = reader.ReadString();
}
}
goto case 4;
}
case 4:
{
int count = reader.ReadInt();
if (version < 5)
{
m_SpeechEntries = new ArrayList();
}
for (int i = 0; i < count; i++)
{
if (version < 5)
{
SpeechEntry newentry = new SpeechEntry();
newentry.Condition = reader.ReadString();
m_SpeechEntries.Add(newentry);
}
else
{
SpeechEntry newentry = (SpeechEntry)m_SpeechEntries[i];
newentry.Condition = reader.ReadString();
}
}
goto case 3;
}
case 3:
{
TriggerOnCarried = reader.ReadString();
NoTriggerOnCarried = reader.ReadString();
goto case 2;
}
case 2:
{
m_SpeechPace = reader.ReadInt();
int count = reader.ReadInt();
if (version < 4)
{
m_SpeechEntries = new ArrayList();
}
for (int i = 0; i < count; i++)
{
if (version < 4)
{
SpeechEntry newentry = new SpeechEntry();
newentry.PrePause = reader.ReadInt();
newentry.LockConversation = reader.ReadBool();
newentry.AllowNPCTrigger = reader.ReadBool();
newentry.SpeechStyle = (MessageType)reader.ReadInt();
m_SpeechEntries.Add(newentry);
}
else
{
SpeechEntry newentry = (SpeechEntry)m_SpeechEntries[i];
newentry.PrePause = reader.ReadInt();
newentry.LockConversation = reader.ReadBool();
newentry.AllowNPCTrigger = reader.ReadBool();
newentry.SpeechStyle = (MessageType)reader.ReadInt();
}
}
goto case 1;
}
case 1:
{
m_ActivePlayer = reader.ReadMobile();
goto case 0;
}
case 0:
{
m_IsActive = reader.ReadBool();
m_ResetTime = reader.ReadTimeSpan();
m_LastInteraction = reader.ReadDateTime();
m_AllowGhostTriggering = reader.ReadBool();
m_ProximityRange = reader.ReadInt();
m_Running = reader.ReadBool();
m_ConfigFile = reader.ReadString();
int count = reader.ReadInt();
if (version < 2)
{
m_SpeechEntries = new ArrayList();
}
for (int i = 0; i < count; i++)
{
if (version < 2)
{
SpeechEntry newentry = new SpeechEntry();
newentry.EntryNumber = reader.ReadInt();
newentry.ID = reader.ReadInt();
newentry.Text = reader.ReadString();
newentry.Keywords = reader.ReadString();
newentry.Action = reader.ReadString();
newentry.DependsOn = reader.ReadInt().ToString();
newentry.Pause = reader.ReadInt();
m_SpeechEntries.Add(newentry);
}
else
{
SpeechEntry newentry = (SpeechEntry)m_SpeechEntries[i];
newentry.EntryNumber = reader.ReadInt();
newentry.ID = reader.ReadInt();
newentry.Text = reader.ReadString();
newentry.Keywords = reader.ReadString();
newentry.Action = reader.ReadString();
if (version < 7)
{
newentry.DependsOn = reader.ReadInt().ToString();
}
else
{
newentry.DependsOn = reader.ReadString();
}
newentry.Pause = reader.ReadInt();
}
}
// read in the current entry number. Note this will also set the current entry
EntryNumber = reader.ReadInt();
// restart the timer if it was active
bool isrunning = reader.ReadBool();
if (isrunning)
{
Mobile trigmob = reader.ReadMobile();
TimeSpan delay = reader.ReadTimeSpan();
DoTimer(delay, trigmob);
}
break;
}
}
}
}
}