Files
abysmal-isle/Scripts/Services/XmlSpawner/XmlSpawner Core/XmlSpawner2.cs
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

12806 lines
368 KiB
C#

//#define TRACE
//#define RESTRICTCONSTRUCTABLE
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Reflection;
using Server;
using Server.Accounting;
using Server.Commands;
using Server.Commands.Generic;
using Server.ContextMenus;
using System.Diagnostics;
using Server.Engines.XmlSpawner2;
using Server.Gumps;
using Server.Items;
using Server.Misc;
using Server.Network;
using Server.Spells;
using Server.Targeting;
using System.Text;
using System.Xml;
using CPA = Server.CommandPropertyAttribute;
/*
** XmlSpawner2
** version 4.00
** updated 10/7/13
** Blaze
**
** Originally modified by:
** ArteGordon
** Modification of the original XmlSpawner written by bobsmart
*/
namespace Server.Mobiles
{
public class XmlSpawner : Item, ISpawner
{
private static bool m_XmlPoints;
private static bool m_XmlFactions;
private static bool m_XmlSockets;
public static bool PointsEnabled { get { return m_XmlPoints; } }
public static bool FactionsEnabled { get { return m_XmlFactions; } }
public static bool SocketsEnabled { get { return m_XmlSockets; } }
public static void Configure()
{
m_XmlPoints = Config.Get("XmlSpawner2.Points", false);
m_XmlFactions = Config.Get("XmlSpawner2.Factions", false);
m_XmlSockets = Config.Get("XmlSpawner2.Sockets", false);
}
#region Type declarations
public enum TODModeType { Realtime, Gametime }
public enum SpawnPositionType { Random, RowFill, ColFill, Perimeter, Player, Waypoint, RelXY, DeltaLocation, Location, Wet, Tiles, NoTiles, ItemID, NoItemID }
public class SpawnPositionInfo
{
public SpawnPositionType positionType;
public Mobile trigMob;
public string[] positionArgs;
public SpawnPositionInfo(SpawnPositionType positiontype, Mobile trigmob, string[] positionargs)
{
positionType = positiontype;
trigMob = trigmob;
positionArgs = positionargs;
}
}
public class MovementInfo
{
public Mobile trigMob;
public Point3D trigLocation = Point3D.Zero;
public MovementInfo(Mobile m)
{
trigMob = m;
if (m != null)
trigLocation = m.Location;
}
}
#endregion
#region Constant declarations
public const byte MaxLoops = 10; //maximum number of recursive calls from spawner to itself. this is to prevent stack overflow from xmlspawner scripting
public const string Version = "4.00";
//private const double SpawnIdleTime = 72.0; // time in hours after which idle spawns will be relocated. A value < 0 disables this feature. This does not work properly under RunUO 2.0
private const int ShowBoundsItemId = 14089; // 14089 Fire Column // 3555 Campfire // 8708 Skull Pole
private const string SpawnDataSetName = "Spawns";
private const string SpawnTablePointName = "Points";
private const int SpawnFitSize = 16; // Normal wall/door height for a mobile is 20 to walk through
private static int BaseItemId = 0x1F1C; // Purple Magic Crystal
private static int ShowItemId = 0x3E57; // ships mast
private static int defaultTriggerSound = 0x1F4; // click and sparkle sound by default (0x1F4) , click sound (0x3A4)
public static string XmlSpawnDir = "XmlSpawner"; // default directory for saving/loading .xml files with [xmlload [xmlsave
public static string XmlMultiDir = "XmlMultis";
private static string XmlConfigsDir = "XmlSpawnerConfigs"; // default directory for loading .xml config files with LoadConfig
private const int MaxSmartSectorListSize = 1024; // maximum sector list size for use in smart spawning. This gives a 512x512 tile range.
private static string defwaypointname = null; // default waypoint name will get assigned in Initialize
private const string XmlTableName = "Properties";
private const string XmlDataSetName = "XmlSpawner";
public static AccessLevel DiskAccessLevel = AccessLevel.Administrator; // minimum access level required by commands that can access the disk such as XmlLoad, XmlSave, and the Save function of XmlEdit
#if(RESTRICTCONSTRUCTABLE)
public static AccessLevel ConstructableAccessLevel = AccessLevel.GameMaster; // only allow spawning of objects that have Constructable access restrictions at this level or lower. Must define RESTRICTCONSTRUCTABLE to enable this.
#endif
private static int MaxMoveCheck = 10; // limit number of players that can be checked for triggering in a single OnMovement tick
#endregion
#region Static variable declarations
// specifies the level at which smartspawning will be triggered. Players with AccessLevel above this will not trigger smartspawning unless unhidden.
public static AccessLevel SmartSpawnAccessLevel = AccessLevel.Player;
// define the default values used in making spawners
private static TimeSpan defMinDelay = TimeSpan.FromMinutes(5);
private static TimeSpan defMaxDelay = TimeSpan.FromMinutes(10);
private static TimeSpan defMinRefractory = TimeSpan.FromMinutes(0);
private static TimeSpan defMaxRefractory = TimeSpan.FromMinutes(0);
private static TimeSpan defTODStart = TimeSpan.FromMinutes(0);
private static TimeSpan defTODEnd = TimeSpan.FromMinutes(0);
private static TimeSpan defDuration = TimeSpan.FromMinutes(0);
private static TimeSpan defDespawnTime = TimeSpan.FromHours(0);
private static bool defIsGroup = false;
private static int defTeam = 0;
private static int defProximityTriggerSound = defaultTriggerSound;
private static int defAmount = 1;
private static bool defRelativeHome = true;
private static int defSpawnRange = 5;
private static int defHomeRange = 5;
private static double defTriggerProbability = 1;
private static int defProximityRange = -1;
private static int defKillReset = 1;
private static TODModeType defTODMode = TODModeType.Realtime;
private static Timer m_GlobalSectorTimer;
private static bool SmartSpawningSystemEnabled = false;
private static WarnTimer2 m_WarnTimer;
// hash table for optimizing HoldSmartSpawning method invocation
private static Dictionary<Type, PropertyInfo> holdSmartSpawningHash;
public static int seccount;
// sector hashtable for each map
private static Dictionary<Sector, List<XmlSpawner>>[] GlobalSectorTable = new Dictionary<Sector, List<XmlSpawner>>[Map.Maps.Length];
#endregion
#region Variable declarations
private string m_Name = string.Empty;
private string m_UniqueId = string.Empty;
private bool m_PlayerCreated = false;
private bool m_HomeRangeIsRelative = false;
private int m_Team;
private int m_HomeRange;
// added a amount parameter for stacked item spawns
private int m_StackAmount;
// this is actually redundant with the width height spec for spawning area
// just an easier way of specifying it
private int m_SpawnRange;
private int m_Count;
private TimeSpan m_MinDelay;
private TimeSpan m_MaxDelay;
// added a duration parameter for time-limited spawns
private TimeSpan m_Duration;
public List<XmlSpawner.SpawnObject> m_SpawnObjects = new List<XmlSpawner.SpawnObject>(); // List of objects to spawn
private DateTime m_End;
private DateTime m_RefractEnd;
private DateTime m_DurEnd;
private SpawnerTimer m_Timer;
private InternalTimer m_DurTimer;
private InternalTimer3 m_RefractoryTimer;
private bool m_Running;
private bool m_Group;
private int m_X;
private int m_Y;
private int m_Width;
private int m_Height;
private WayPoint m_WayPoint;
private Static m_ShowContainerStatic;
private bool m_proximityActivated;
private bool m_refractActivated;
private bool m_durActivated;
private TimeSpan m_TODStart;
private TimeSpan m_TODEnd;
// time after proximity activation when the spawn cannot be reactivated
private TimeSpan m_MinRefractory;
private TimeSpan m_MaxRefractory;
private string m_ItemTriggerName;
private string m_NoItemTriggerName;
private Item m_ObjectPropertyItem;
private string m_ObjectPropertyName;
public string status_str;
public int m_killcount;
// added proximity range sensor
private int m_ProximityRange;
// sound played when a proximity triggered spawner is tripped by a player
// set this to zero if you dont want to hear anything
private int m_ProximityTriggerSound;
private string m_ProximityTriggerMessage;
private string m_SpeechTrigger;
private bool m_speechTriggerActivated;
private string m_MobPropertyName;
private string m_MobTriggerName;
private string m_PlayerPropertyName;
private double m_TriggerProbability = defTriggerProbability;
private Mobile m_mob_who_triggered;
private Item m_SetPropertyItem;
private bool m_skipped = false;
private int m_KillReset = defKillReset; // number of spawn ticks that pass without kills before killcount gets reset to zero
private int m_spawncheck = 0;
private TODModeType m_TODMode = TODModeType.Realtime;
private string m_GumpState;
private bool m_ExternalTriggering;
private bool m_ExternalTrigger;
private int m_SequentialSpawning = -1; // off by default
private DateTime m_SeqEnd;
private Region m_Region; // 2004.02.08 :: Omega Red
private string m_RegionName = string.Empty; // 2004.02.08 :: Omega Red
private AccessLevel m_TriggerAccessLevel = AccessLevel.Player;
public List<XmlTextEntryBook> m_TextEntryBook;
private XmlSpawnerGump m_SpawnerGump;
private bool m_AllowGhostTriggering = false;
private bool m_AllowNPCTriggering = false;
private string m_ConfigFile;
private bool m_OnHold = false;
private bool m_HoldSequence = false;
private bool m_SpawnOnTrigger = false;
private DateTime m_FirstModified;
private DateTime m_LastModified;
private List<MovementInfo> m_MovementList;
private MovementTimer m_MovementTimer;
internal List<BaseXmlSpawner.KeywordTag> m_KeywordTagList = new List<BaseXmlSpawner.KeywordTag>();
private string m_FirstModifiedBy = null;
private string m_LastModifiedBy = null;
public List<XmlSpawner> RecentSpawnerSearchList = null;
public List<Item> RecentItemSearchList = null;
public List<Mobile> RecentMobileSearchList = null;
private TimeSpan m_DespawnTime;
private string m_SkillTrigger;
private bool m_skillTriggerActivated;
private SkillName m_skill_that_triggered;
private bool m_FreeRun = false; // override for all other triggering modes
private SkillName m_SkillTriggerName;
private double m_SkillTriggerMin;
private double m_SkillTriggerMax;
private int m_SkillTriggerSuccess;
private Map currentmap;
public bool m_IsInactivated = false;
private bool m_SmartSpawning = false;
private SectorTimer m_SectorTimer;
private List<Static> m_ShowBoundsItems = new List<Static>();
public List<BaseXmlSpawner.TypeInfo> PropertyInfoList = null; // used to optimize property info lookup used by set and get property methods.
private Dictionary<string, List<Item>> spawnPositionWayTable = null; // used to optimize #waypoint lookup
private bool inrespawn = false;
private List<Sector> sectorList = null;
private bool m_DisableGlobalAutoReset;
private Point3D mostRecentSpawnPosition = Point3D.Zero;
private int m_MovingPlayerCount = 0;
private int m_FastestPlayerSpeed = 0;
private bool m_DebugThis = false;
private TimerPriority m_BasePriority = TimerPriority.OneSecond;
#endregion
#region Property Overrides
// does not decay
public override bool Decays { get { return false; } }
// is not counted in the normal item count
public override bool IsVirtualItem { get { return true; } }
#endregion
#region Properties
public TimerPriority BasePriority { get { return m_BasePriority; } set { m_BasePriority = value; } }
public bool DebugThis { get { return m_DebugThis; } set { m_DebugThis = value; } }
public int MovingPlayerCount { get { return m_MovingPlayerCount; } set { m_MovingPlayerCount = value; } }
public int FastestPlayerSpeed { get { return m_FastestPlayerSpeed; } set { m_FastestPlayerSpeed = value; } }
public int NearbyPlayerCount
{
get
{
int count = 0;
if (ProximityRange >= 0)
{
IPooledEnumerable eable = GetMobilesInRange(ProximityRange);
foreach (Mobile m in eable)
{
if (m != null && m.Player) count++;
}
eable.Free();
}
return count;
}
}
public Point3D MostRecentSpawnPosition
{
get { return mostRecentSpawnPosition; }
set { mostRecentSpawnPosition = value; }
}
public TimeSpan GameTOD
{
get
{
int hours;
int minutes;
Server.Items.Clock.GetTime(this.Map, this.Location.X, this.Location.Y, out hours, out minutes);
return (new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, hours, minutes, 0).TimeOfDay);
}
}
public TimeSpan RealTOD { get { return DateTime.UtcNow.TimeOfDay; } }
public int RealDay { get { return DateTime.UtcNow.Day; } }
public int RealMonth { get { return DateTime.UtcNow.Month; } }
public DayOfWeek RealDayOfWeek { get { return DateTime.UtcNow.DayOfWeek; } }
public MoonPhase MoonPhase
{
get
{
return Clock.GetMoonPhase(this.Map, this.Location.X, this.Location.Y);
}
}
public XmlSpawnerGump SpawnerGump
{
get { return m_SpawnerGump; }
set
{
m_SpawnerGump = value;
}
}
public bool DisableGlobalAutoReset { get { return m_DisableGlobalAutoReset; } set { m_DisableGlobalAutoReset = value; } }
public bool DoDefrag
{
get { return false; }
set
{
if (value == true)
{
Defrag(true);
}
}
}
private bool sectorIsActive = false;
private bool UseSectorActivate = false;
public bool SingleSector { get { return UseSectorActivate; } }
/*
public override void OnSectorDeactivate()
{
sectorIsActive = false;
base.OnSectorDeactivate();
}
public override void OnSectorActivate()
{
sectorIsActive = true;
base.OnSectorActivate();
// perform the smart respawning
if(SmartSpawning && IsInactivated && UseSectorActivate)
{
SmartRespawn();
}
}
*/
public bool InActivationRange(Sector s1, Sector s2)
{
// check to see if the sectors are within +- 2 of one another
if (s1 == null || s2 == null) return false;
return (Math.Abs(s1.X - s2.X) < 3 && Math.Abs(s1.Y - s2.Y) < 3);
}
public bool HasDamagedOrDistantSpawns
{
get
{
Sector ssec = Map.GetSector(Location);
// go through the spawn lists
foreach (SpawnObject so in m_SpawnObjects)
{
for (int x = 0; x < so.SpawnedObjects.Count; x++)
{
object o = so.SpawnedObjects[x];
if (o is BaseCreature)
{
BaseCreature b = (BaseCreature)o;
// if the mob is damaged or outside of smartspawning detection range then return true
if ((b.Hits < b.HitsMax) || (b.Mana < b.ManaMax) || (b.Stam < b.StamMax) || (b.Map != this.Map))
{
return true;
}
// if the spawn moves into a sector that is not activatable from a sector on the sector list then dont smartspawn
if (b.Map != null && b.Map != Map.Internal)
{
Sector bsec = b.Map.GetSector(b.Location);
if (UseSectorActivate)
{
// is it in activatable range of the sector the spawner is in
if (!InActivationRange(bsec, ssec))
{
return true;
}
}
else
{
bool outofsec = true;
if (sectorList != null)
{
foreach (Sector s in sectorList)
{
// is the creatures sector within activation range of any of the sectors in the list
if (InActivationRange(bsec, s))
{
outofsec = false;
break;
}
}
}
if (outofsec)
{
return true;
}
}
}
}
}
}
return false;
}
}
private static int totalSectorsMonitored = 0;
public bool HasActiveSectors
{
get
{
if (!SmartSpawning || Map == null || Map == Map.Internal) return false;
// is this a region spawner?
if (m_Region != null)
{
List<Mobile> players = m_Region.GetPlayers();
if (players == null || players.Count == 0) return false;
// confirm that players with the proper access level are present
foreach (Mobile m in players)
{
if (m != null && (m.AccessLevel <= SmartSpawnAccessLevel || !m.Hidden))
{
return true;
}
}
return false;
}
// is this a single sector spawner?
if (UseSectorActivate)
{
return sectorIsActive;
}
// if there is no sector list made for this spawner then create one.
if (sectorList == null)
{
Point3D loc = this.Location;
sectorList = new List<Sector>();
// is this container held?
if (Parent != null)
{
if (RootParent is Mobile)
loc = ((Mobile)(RootParent)).Location;
else
if (RootParent is Item)
loc = ((Item)(RootParent)).Location;
}
// find the max detection range by examining both spawnrange
// note, sectors will activate when within +-2 sectors
int bufferzone = 2 * Server.Map.SectorSize;
int x1 = m_X - bufferzone;
int width = m_Width + 2 * bufferzone;
int y1 = m_Y - bufferzone;
int height = m_Height + 2 * bufferzone;
// go through all of the sectors within the SpawnRange of the spawner to see if any are active
for (int x = x1; x <= x1 + width; x += Server.Map.SectorSize)
{
for (int y = y1; y <= y1 + height; y += Server.Map.SectorSize)
{
Sector s = Map.GetSector(new Point3D(x, y, loc.Z));
if (s == null) continue;
// dont add any redundant sectors
bool duplicate = false;
foreach (Sector olds in sectorList)
{
if (olds == s)
{
duplicate = true;
break;
}
}
if (!duplicate)
{
sectorList.Add(s);
if (GlobalSectorTable[Map.MapID] == null)
{
GlobalSectorTable[Map.MapID] = new Dictionary<Sector, List<XmlSpawner>>();
}
// add this sector and the spawner associated with it to the global sector table
List<XmlSpawner> spawnerlist;
if (GlobalSectorTable[Map.MapID].TryGetValue(s, out spawnerlist))//.Contains(s))
{
//List<XmlSpawner> spawnerlist = GlobalSectorTable[Map.MapID][s];
if (spawnerlist == null)
{
//GlobalSectorTable[Map.MapID].Remove(s);
spawnerlist = new List<XmlSpawner>();
//GlobalSectorTable[Map.MapID].Add(s, spawnerlist);
GlobalSectorTable[Map.MapID][s] = spawnerlist;
}
if (!spawnerlist.Contains(this))
{
spawnerlist.Add(this);
}
}
else
{
spawnerlist = new List<XmlSpawner>();
spawnerlist.Add(this);
// add a new entry to the table
GlobalSectorTable[Map.MapID][s] = spawnerlist;
}
totalSectorsMonitored++;
// add some sanity checking here
if (sectorList.Count > MaxSmartSectorListSize)
{
SmartSpawning = false;
// log it
try
{
Console.WriteLine("SmartSpawning disabled at {0} {1} : Range too large.", loc, Map);
using (StreamWriter op = new StreamWriter("badspawn.log", true))
{
op.WriteLine("{0} SmartSpawning disabled at {1} {2} : Range too large.", DateTime.UtcNow, loc, Map);
op.WriteLine();
}
}
catch
{ }
return true;
}
}
}
}
// if the spawner is in a single sector, then we can use the OnSectorActivation method to test for activity
// note, sectors will activate when within +-2 sectors
/*
if((sectorList.Count == 1) && (Location.X >= m_X) && (Location.X <= m_X + m_Width) &&
(Location.Y >= m_Y) && (Location.Y <= m_Y + m_Height))
{
UseSectorActivate = true;
}
else
{
UseSectorActivate = false;
}
*/
UseSectorActivate = false;
}
_TraceStart(2);
// go through the sectorlist and see if any of the sectors are active
foreach (Sector s in sectorList)
{
if (s != null && s.Active && s.Players != null && s.Players.Count > 0)
{
// confirm that players with the proper access level are present
foreach (Mobile m in s.Players)
{
if (m != null && (m.AccessLevel <= SmartSpawnAccessLevel || !m.Hidden))
{
return true;
}
}
_TraceEnd(2);
}
seccount++;
}
_TraceEnd(2);
return false;
}
}
public int SecCount { get { return seccount; } }
public bool IsInactivated
{
get { return m_IsInactivated; }
set
{
m_IsInactivated = value;
}
}
public int ActiveSectorCount
{
get
{
if (sectorList != null) return sectorList.Count;
return 0;
}
}
public DateTime FirstModified
{
get { return m_FirstModified; }
}
public DateTime LastModified
{
get { return m_LastModified; }
}
public bool PlayerCreated
{
get { return m_PlayerCreated; }
set { m_PlayerCreated = value; }
}
public bool OnHold
{
get
{
if (m_OnHold) return true;
// determine whether there are any keywordtags with the hold flag
if (m_KeywordTagList == null || m_KeywordTagList.Count == 0) return false;
foreach (BaseXmlSpawner.KeywordTag sot in m_KeywordTagList)
{
// check for any keyword tag with the holdspawn flag
if (sot != null && !sot.Deleted && ((sot.Flags & BaseXmlSpawner.KeywordFlags.HoldSpawn) != 0))
{
return true;
}
}
// no hold flags were set
return false;
}
set { m_OnHold = value; }
}
public string AddSpawn
{
get { return null; }
set
{
if(!string.IsNullOrEmpty(value))
{
string str = value.Trim();
string typestr = BaseXmlSpawner.ParseObjectType(str);
Type type = SpawnerType.GetType(typestr);
if (type != null)
m_SpawnObjects.Add(new XmlSpawner.SpawnObject(str, 1));
else
{
// check for special keywords
if (typestr != null && (BaseXmlSpawner.IsTypeOrItemKeyword(typestr) || typestr.IndexOf("{") != -1 || typestr.StartsWith("*") || typestr.StartsWith("#")))
{
m_SpawnObjects.Add(new XmlSpawner.SpawnObject(str, 1));
}
else
this.status_str = String.Format("{0} is not a valid type name.", str);
}
InvalidateProperties();
}
}
}
public Skill TriggerSkill
{
get
{
if (TriggerMob != null && (int)m_skill_that_triggered >= 0)
{
return TriggerMob.Skills[m_skill_that_triggered];
}
else
{
return null;
}
}
set
{
if (value != null)
{
m_skill_that_triggered = value.SkillName;
}
else
{
m_skill_that_triggered = XmlSpawnerSkillCheck.RegisteredSkill.Invalid;
}
}
}
public string UniqueId
{
get { return m_UniqueId; }
}
// does not perform a defrag, so less accurate but can be used while looping through world object enums
public int SafeCurrentCount
{
get { return SafeTotalSpawnedObjects; }
}
public bool FreeRun
{
get { return m_FreeRun; }
set { m_FreeRun = value; }
}
public bool CanFreeSpawn
{
get
{
// allow free spawning if proximity sensing is off and if all of the potential free-spawning triggers are disabled
if (Running && m_ProximityRange == -1 &&
(m_ObjectPropertyName == null || m_ObjectPropertyName.Length == 0) &&
(m_MobPropertyName == null || m_MobPropertyName.Length == 0 ||
m_MobTriggerName == null || m_MobTriggerName.Length == 0) &&
!m_ExternalTriggering)
return true;
else
return false;
}
}
public SpawnObject[] SpawnObjects
{
get { return m_SpawnObjects.ToArray(); }
set
{
if ((value != null) && (value.Length > 0))
{
foreach (SpawnObject so in value)
{
if (so == null) continue;
bool AlreadyInList = false;
// Check if the new array has an existing spawn object
foreach (SpawnObject TheSpawn in m_SpawnObjects)
{
if(TheSpawn.TypeName.ToUpper() == so.TypeName.ToUpper())
{
AlreadyInList = true;
break;
}
}
// Does this item need to be added
if (!AlreadyInList)
{
// This is a new spawn object so add it to the array (deep copy)
m_SpawnObjects.Add(new SpawnObject(so.TypeName, so.ActualMaxCount, so.SubGroup, so.SequentialResetTime, so.SequentialResetTo, so.KillsNeeded,
so.RestrictKillsToSubgroup, so.ClearOnAdvance, so.MinDelay, so.MaxDelay, so.SpawnsPerTick, so.PackRange));
}
}
if (SpawnObjects.Length < 1)
Stop();
InvalidateProperties();
}
}
}
public bool HoldSequence
{
get
{
// check to see if any keyword tags have the holdsequence flag set, or whether the spawner holdsequence flag is set
if (m_HoldSequence) return true;
// determine whether there are any keywordtags with the hold flag
if (m_KeywordTagList == null || m_KeywordTagList.Count == 0) return false;
foreach (BaseXmlSpawner.KeywordTag sot in m_KeywordTagList)
{
// check for any keyword tag with the holdsequence flag
if (sot != null && !sot.Deleted && ((sot.Flags & BaseXmlSpawner.KeywordFlags.HoldSequence) != 0))
{
return true;
}
}
// no hold flags were set
return false;
}
set { m_HoldSequence = value; }
}
public bool CanSpawn
{
get
{
if (OnHold) return false;
if (m_Group == true)
{
if (TotalSpawnedObjects <= 0)
return true;
else
return false;
}
else
{
if (IsFull)
return false;
else
return true;
}
}
}
// test for a full spawner
public bool IsFull
{
get
{
int nobj = TotalSpawnedObjects;
return ((nobj >= m_Count) || (nobj >= TotalSpawnObjectCount));
}
}
// this can be used in loops over world objects since it will not defrag and potentially modify the world object lists
public int SafeTotalSpawnedObjects
{
get
{
if (m_SpawnObjects == null) return 0;
int count = 0;
foreach (SpawnObject so in m_SpawnObjects)
count += so.SpawnedObjects.Count;
return count;
}
}
public int TotalSpawnedObjects
{
get
{
if (m_SpawnObjects == null) return 0;
// defrag so that accurately reflects currently active spawns
Defrag(true);
int count = 0;
foreach (SpawnObject so in m_SpawnObjects)
count += so.SpawnedObjects.Count;
return count;
}
}
public bool isEmpty()
{
if (m_SpawnObjects == null) return true;
foreach(SpawnObject so in m_SpawnObjects)
{
if(so.SpawnedObjects != null && so.SpawnedObjects.Count>0)
{
if(so.SpawnedObjects[0] is Mobile)
return false;
}
}
return true;
}
public int TotalSpawnObjectCount
{
get
{
int count = 0;
foreach (SpawnObject so in m_SpawnObjects)
count += so.MaxCount;
return count;
}
}
#endregion
#region Command Properties
[CommandProperty(AccessLevel.GameMaster)]
public bool GumpReset
{
set
{
if (value == true)
{
m_SpawnerGump = null;
}
}
}
[CommandProperty(AccessLevel.GameMaster)]
public Region SpawnRegion
{
get { return m_Region; }
set
{
// force a re-update of the smart spawning sector list the next time it is accessed
ResetSectorList();
m_Region = value;
if (m_Region != null)
{
m_RegionName = m_Region.Name;
}
else
{
m_RegionName = null;
}
}
}
// 2004.02.08 :: Omega Red
[CommandProperty(AccessLevel.GameMaster)]
public string RegionName
{
get
{
return m_RegionName;
}
set
{
// force a re-update of the smart spawning sector list the next time it is accessed
ResetSectorList();
m_RegionName = value;
if (string.IsNullOrEmpty(value))
{
m_Region = null;
return;
}
if (Region.Regions.Count == 0) // after world load, before region load
return;
foreach (Region region in Region.Regions)
{
if (string.Compare(region.Name, m_RegionName, true) == 0)
{
m_Region = region;
m_RegionName = region.Name;
//InvalidateProperties();
return;
}
}
status_str = "invalid region: " + value;
m_Region = null;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public Point3D X1_Y1
{
get { return new Point3D(m_X, m_Y, Z); }
set
{
// X1 and Y1 will initiate region specification
m_Width = 0;
m_Height = 0;
m_X = value.X;
m_Y = value.Y;
// reset the sector list
ResetSectorList();
m_SpawnRange = 0;
// Check if the spawner is showing its bounds
if (ShowBounds == true)
{
ShowBounds = false;
ShowBounds = true;
}
}
}
[CommandProperty(AccessLevel.GameMaster)]
public Point3D X2_Y2
{
get { return new Point3D((m_X + m_Width), (m_Y + m_Height), Z); }
set
{
int X2;
int Y2;
int OriginalX2 = m_X + m_Width;
int OriginalY2 = m_Y + m_Height;
// reset the sector list
ResetSectorList();
// now determine based upon the entered coordinate values what the lower left corner is
// lower left will be the min x and min y
// upper right will be max x max y
if (value.X < OriginalX2)
{
// ok, this is the proper x value for the lower left
m_X = value.X;
X2 = OriginalX2;
}
else
{
m_X = OriginalX2;
X2 = value.X;
}
if (value.Y < OriginalY2)
{
// ok, this is the proper y value for the lower left
m_Y = value.Y;
Y2 = OriginalY2;
}
else
{
m_Y = OriginalY2;
Y2 = value.Y;
}
m_Width = X2 - m_X;
m_Height = Y2 - m_Y;
if (m_Width == m_Height)
m_SpawnRange = m_Width / 2;
else
m_SpawnRange = -1;
if (m_HomeRangeIsRelative == false)
{
int NewHomeRange = (m_Width > m_Height ? m_Height : m_Width);
m_HomeRange = (NewHomeRange > 0 ? NewHomeRange : 0);
}
//original test was for less than 1, changed it to less than zero (zero is a valid width, its the default in fact)
// Stop the spawner if the width or height is less than 1
if ((m_Width < 0) || (m_Height < 0))
Running = false;
InvalidateProperties();
// Check if the spawner is showing its bounds
if (ShowBounds == true)
{
ShowBounds = false;
ShowBounds = true;
}
}
}
// added the spawnrange property. It sets both the XY and width/height parameters automatically.
// also doesnt mess with homerange like XY does
[CommandProperty(AccessLevel.GameMaster)]
public int SpawnRange
{
get { return (m_SpawnRange); }
set
{
if (value < 0) return;
// reset the sector list
ResetSectorList();
m_SpawnRange = value;
m_Width = m_SpawnRange * 2;
m_Height = m_SpawnRange * 2;
// dont set the bounding box locations if the initial location is 0,0 since this occurs when the item is just being made
// because m_X and m_Y are restored on loading, it creates problems with OnLocationChange which has to avoid applying translational
// adjustments to newly placed spawners (because the actual m_X and m_Y is associated with the original location, not the 0,0 location)
// basically, before placement, dont set m_X or m_Y to anything that needs to be adjusted later on
if (Location.X == 0 && Location.Y == 0) return;
m_X = Location.X - m_SpawnRange;
m_Y = Location.Y - m_SpawnRange;
//InvalidateProperties();
// Check if the spawner is showing its bounds
if (ShowBounds == true)
{
ShowBounds = false;
ShowBounds = true;
}
}
}
[CommandProperty(AccessLevel.GameMaster)]
public bool ShowBounds
{
get { return (m_ShowBoundsItems != null && m_ShowBoundsItems.Count > 0); }
set
{
if ((value == true) && (ShowBounds == false))
{
if (m_ShowBoundsItems == null) m_ShowBoundsItems = new List<Static>();
// Boundary lines
int ValidX1 = m_X;
int ValidX2 = m_X + m_Width;
int ValidY1 = m_Y;
int ValidY2 = m_Y + m_Height;
for (int x = 0; x <= m_Width; x++)
{
int NewX = m_X + x;
for (int y = 0; y <= m_Height; y++)
{
int NewY = m_Y + y;
if (NewX == ValidX1 || NewX == ValidX2 || NewX == ValidY1 || NewX == ValidY2 || NewY == ValidX1 || NewY == ValidX2 || NewY == ValidY1 || NewY == ValidY2)
{
// Add an object to show the spawn area
Static s = new Static(ShowBoundsItemId);
s.Visible = false;
s.MoveToWorld(new Point3D(NewX, NewY, Z), this.Map);
m_ShowBoundsItems.Add(s);
}
}
}
}
if (value == false && m_ShowBoundsItems != null)
{
// Remove all of the items from the array
foreach (Static s in m_ShowBoundsItems)
s.Delete();
m_ShowBoundsItems.Clear();
}
}
}
/*
[CommandProperty(AccessLevel.GameMaster)]
public override string Name
{
get { return m_Name; }
set
{
m_Name = value;
InvalidateProperties();
}
}
*/
[CommandProperty(AccessLevel.GameMaster)]
public int MaxCount
{
get { return m_Count; }
set
{
m_Count = value;
InvalidateProperties();
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int CurrentCount
{
get { return TotalSpawnedObjects; }
}
[CommandProperty(AccessLevel.GameMaster)]
public WayPoint WayPoint
{
get { return m_WayPoint; }
set { m_WayPoint = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public bool ExternalTriggering
{
get { return m_ExternalTriggering; }
set { m_ExternalTriggering = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public bool ExtTrigState
{
get { return m_ExternalTrigger; }
set { m_ExternalTrigger = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public bool Running
{
get { return m_Running; }
set
{
// Don't start the spawner unless the height and width are valid
if ((value == true) && (m_Width >= 0) && (m_Height >= 0))
{
Start();
}
else
Stop();
InvalidateProperties();
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int HomeRange
{
get { return m_HomeRange; }
set { m_HomeRange = value; InvalidateProperties(); }
}
[CommandProperty(AccessLevel.GameMaster)]
public bool HomeRangeIsRelative
{
get { return m_HomeRangeIsRelative; }
set { m_HomeRangeIsRelative = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public int Team
{
get { return m_Team; }
set { m_Team = value; InvalidateProperties(); }
}
[CommandProperty(AccessLevel.GameMaster)]
public int StackAmount
{
get { return m_StackAmount; }
set { m_StackAmount = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan MinDelay
{
get { return m_MinDelay; }
set
{
m_MinDelay = value;
// reset the spawn timer
DoTimer();
InvalidateProperties();
}
}
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan MaxDelay
{
get { return m_MaxDelay; }
set
{
m_MaxDelay = value;
// reset the spawn timer
DoTimer();
InvalidateProperties();
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int KillCount
{
get { return m_killcount; }
set { m_killcount = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public int KillReset
{
get { return m_KillReset; }
set { m_KillReset = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public double TriggerProbability
{
get { return m_TriggerProbability; }
set { m_TriggerProbability = value; }
}
//added refractory period support
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan RefractMin
{
get { return m_MinRefractory; }
set { m_MinRefractory = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan RefractMax
{
get { return m_MaxRefractory; }
set { m_MaxRefractory = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan RefractoryOver
{
get
{
if (m_refractActivated)
return m_RefractEnd - DateTime.UtcNow;
else
return TimeSpan.FromSeconds(0);
}
set
{
DoTimer3(value);
}
}
[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; }
}
[CommandProperty(AccessLevel.GameMaster)]
public string TriggerObjectProp
{
get { return m_ObjectPropertyName; }
set { m_ObjectPropertyName = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public string TriggerObjectName
{
get
{
if (m_ObjectPropertyItem == null || m_ObjectPropertyItem.Deleted) return null;
return m_ObjectPropertyItem.Name;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public Item TriggerObject
{
get { return m_ObjectPropertyItem; }
set { m_ObjectPropertyItem = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public string SetItemName
{
get
{
if (m_SetPropertyItem == null || m_SetPropertyItem.Deleted) return null;
return m_SetPropertyItem.Name;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public Item SetItem
{
get
{
return m_SetPropertyItem;
}
set { m_SetPropertyItem = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public string MobTriggerProp
{
get { return m_MobPropertyName; }
set { m_MobPropertyName = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public string MobTriggerName
{
get { return m_MobTriggerName; }
set { m_MobTriggerName = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public Mobile MobTriggerId
{
get
{
if (m_MobTriggerName == null) return null;
// try to parse out the type information if it has also been saved
string[] typeargs = m_MobTriggerName.Split(",".ToCharArray(), 2);
string typestr = null;
string namestr = m_MobTriggerName;
if (typeargs.Length > 1)
{
namestr = typeargs[0];
typestr = typeargs[1];
}
return BaseXmlSpawner.FindMobileByName(this, namestr, typestr);
}
}
[CommandProperty(AccessLevel.GameMaster)]
public string PlayerTriggerProp
{
get { return m_PlayerPropertyName; }
set { m_PlayerPropertyName = value; }
}
// time of day activation
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan TODStart
{
get { return m_TODStart; }
set { m_TODStart = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan TODEnd
{
get { return m_TODEnd; }
set { m_TODEnd = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan TOD
{
get
{
if (m_TODMode == TODModeType.Gametime)
{
int hours;
int minutes;
Server.Items.Clock.GetTime(this.Map, Location.X, this.Location.Y, out hours, out minutes);
return (new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, hours, minutes, 0).TimeOfDay);
}
else
return DateTime.UtcNow.TimeOfDay;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public TODModeType TODMode
{
get { return m_TODMode; }
set { m_TODMode = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public bool TODInRange
{
get
{
if (m_TODStart == m_TODEnd) return true;
DateTime now;
DateTime TOD_start;
DateTime TOD_end;
DateTime day_start;
if (m_TODMode == TODModeType.Gametime)
{
int hours;
int minutes;
Server.Items.Clock.GetTime(this.Map, Location.X, this.Location.Y, out hours, out minutes);
now = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, hours, minutes, 0);
}
else
{
// calculate the time window
now = DateTime.UtcNow;
}
day_start = new DateTime(now.Year, now.Month, now.Day);
// calculate the starting TOD window by adding the TODStart to day_start
TOD_start = day_start + m_TODStart;
TOD_end = day_start + m_TODEnd;
// handle the case when TODstart is before midnight and end is after
if (TOD_start > TOD_end)
{
if (now > TOD_start || now < TOD_end)
return true;
else
return false;
}
else
{
if (now > TOD_start && now < TOD_end)
return true;
else
return false;
}
}
}
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan DespawnTime
{
get { return m_DespawnTime; }
set { m_DespawnTime = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan Duration
{
get { return m_Duration; }
set
{
m_Duration = value;
InvalidateProperties();
}
}
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan DurationOver
{
get
{
if (m_durActivated)
return m_DurEnd - DateTime.UtcNow;
else
return TimeSpan.FromSeconds(0);
}
set
{
DoTimer2(value);
}
}
// proximity range parameter
[CommandProperty(AccessLevel.GameMaster)]
public int ProximityRange
{
get { return m_ProximityRange; }
set
{
m_ProximityRange = value;
InvalidateProperties();
}
}
// proximity range activated?
[CommandProperty(AccessLevel.GameMaster)]
public bool ProximityActivated
{
get { return m_proximityActivated; }
set
{
if (AllowTriggering)
{
ActivateTrigger();
}
m_proximityActivated = value;
}
}
// proximity trigger sound parameter
[CommandProperty(AccessLevel.GameMaster)]
public int ProximitySound
{
get { return m_ProximityTriggerSound; }
set { m_ProximityTriggerSound = value; }
}
// proximity trigger message parameter
[CommandProperty(AccessLevel.GameMaster)]
public string ProximityMsg
{
get { return m_ProximityTriggerMessage; }
set { m_ProximityTriggerMessage = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public string SpeechTrigger
{
get { return m_SpeechTrigger; }
set { m_SpeechTrigger = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public string SkillTrigger
{
get { return m_SkillTrigger; }
set
{
SkillName news = XmlSpawnerSkillCheck.RegisteredSkill.Invalid;
double minval = -1;
double maxval = -1;
int successval = 3; // either success or failure will trigger
if (value != null)
{
// try parsing the skill trigger string for min and maxval
// the string can take the form "skill,[+/-][,minval,maxval]"
string[] arglist = BaseXmlSpawner.ParseString(value, 4, ",");
if (arglist.Length == 2 || arglist.Length == 4)
{
if (arglist[1] == "+")
{
successval = 1; // trigger on success only
}
else
if (arglist[1] == "-")
{
successval = 2; // trigger on failure only
}
}
if (arglist.Length == 3)
{
successval = 3;
try
{
minval = double.Parse(arglist[1]);
maxval = double.Parse(arglist[2]);
}
catch { }
}
else
if (arglist.Length == 4)
{
try
{
minval = double.Parse(arglist[2]);
maxval = double.Parse(arglist[3]);
}
catch { }
}
try
{
news = (SkillName)Enum.Parse(typeof(SkillName), arglist[0], true);
}
catch { }
}
// unregister the previous skill if it was assigned
if (m_SkillTrigger != null)
{
XmlSpawnerSkillCheck.UnRegisterSkillTrigger(this, m_SkillTriggerName, this.Map, false);
}
// if the skill trigger was valid then register it
if (news != XmlSpawnerSkillCheck.RegisteredSkill.Invalid)
{
XmlSpawnerSkillCheck.RegisterSkillTrigger(this, news, this.Map);
m_SkillTrigger = value;
m_SkillTriggerName = news;
m_SkillTriggerMin = minval;
m_SkillTriggerMax = maxval;
m_SkillTriggerSuccess = successval;
}
else
{
m_SkillTrigger = null;
m_SkillTriggerName = XmlSpawnerSkillCheck.RegisteredSkill.Invalid;
m_SkillTriggerMin = -1;
m_SkillTriggerMax = -1;
}
}
}
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan NextSpawn
{
get
{
if (m_Running)
return m_End - DateTime.UtcNow;
else
return TimeSpan.FromSeconds(0);
}
set
{
Start();
DoTimer(value);
//InvalidateProperties();
}
}
[CommandProperty(AccessLevel.GameMaster)]
public bool SpawnOnTrigger
{
get { return m_SpawnOnTrigger; }
set { m_SpawnOnTrigger = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public bool Group
{
get { return m_Group; }
set { m_Group = value; InvalidateProperties(); }
}
[CommandProperty(AccessLevel.GameMaster)]
public string GumpState
{
get { return m_GumpState; }
set { m_GumpState = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public int SequentialSpawn
{
get { return m_SequentialSpawning; }
set { m_SequentialSpawning = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public TimeSpan NextSeqReset
{
get
{
if (m_Running && ((m_SeqEnd - DateTime.UtcNow) > TimeSpan.Zero))
return m_SeqEnd - DateTime.UtcNow;
else
return TimeSpan.FromSeconds(0);
}
set
{
m_SeqEnd = DateTime.UtcNow + value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public AccessLevel TriggerAccessLevel
{
get { return m_TriggerAccessLevel; }
set { m_TriggerAccessLevel = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public bool DoRespawn
{
get { return false; }
set
{
// need to determine whether this is being set by the spawner during processing of a respawn entry
// if so then dont do it, otherwise you will infinitely recurse and crash with a stack overflow
if (value == true && !inrespawn)
{
Respawn();
}
}
}
[CommandProperty(AccessLevel.GameMaster)]
public bool DoReset
{
get { return false; }
set { if (value == true) Reset(); }
}
[CommandProperty(AccessLevel.GameMaster)]
public bool AllowGhostTrig
{
get { return m_AllowGhostTriggering; }
set { m_AllowGhostTriggering = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public bool AllowNPCTrig
{
get { return m_AllowNPCTriggering; }
set { m_AllowNPCTriggering = 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) LoadXmlConfig(ConfigFile); }
}
[CommandProperty(AccessLevel.GameMaster)]
public Mobile TriggerMob
{
get { return m_mob_who_triggered; }
set { m_mob_who_triggered = value; }
}
[CommandProperty(AccessLevel.GameMaster)]
public string FirstModifiedBy
{
get { return m_FirstModifiedBy; }
set
{
m_FirstModifiedBy = value;
m_FirstModified = DateTime.UtcNow;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public string LastModifiedBy
{
get { return m_LastModifiedBy; }
set
{
m_LastModifiedBy = value;
m_LastModified = DateTime.UtcNow;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public bool SmartSpawning
{
get { return m_SmartSpawning; }
set
{
m_SmartSpawning = value;
if (m_SmartSpawning)
{
// if any spawner is smartspawning, then the smartspawning system is enabled
SmartSpawningSystemEnabled = true;
// check to see if the global sector timer is running
if (m_GlobalSectorTimer == null || !m_GlobalSectorTimer.Running)
{
// start the global smartspawning timer
DoGlobalSectorTimer(TimeSpan.FromSeconds(1));
}
}
//IsInactivated = false;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public bool IsEmpty
{
get
{
return isEmpty();
}
}
#endregion
#region ISpawner interface support
public bool UnlinkOnTaming { get { return true; } }
public Point3D HomeLocation { get { return this.Location; } }
public int Range { get { return HomeRange; } }
public virtual void GetSpawnProperties(ISpawnable spawn, ObjectPropertyList list)
{ }
public virtual void GetSpawnContextEntries(ISpawnable spawn, Mobile user, List<ContextMenuEntry> list)
{ }
public void Remove(ISpawnable spawn)
{
if (m_SpawnObjects == null) return;
foreach (SpawnObject so in m_SpawnObjects)
{
for (int i = 0; i < so.SpawnedObjects.Count; ++i)
{
if (so.SpawnedObjects[i] == spawn)
{
so.SpawnedObjects.Remove(spawn);
if(SequentialSpawn >= 0 && so.RestrictKillsToSubgroup)
{
if (so.SubGroup == SequentialSpawn)
m_killcount++;
}
else
m_killcount++;
return;
}
}
}
}
public void RestoreISpawner()
{
// restore the Spawner assignments to all spawned objects
if (m_SpawnObjects == null) return;
foreach (SpawnObject so in m_SpawnObjects)
{
for (int i = 0; i < so.SpawnedObjects.Count; ++i)
{
object o = so.SpawnedObjects[i];
if (o is Item)
{
((Item)o).Spawner = this;
}
else if (o is Mobile)
{
((Mobile)o).Spawner = this;
}
}
}
}
#endregion
#region Method Overrides
public override void OnAfterDuped(Item newItem)
{
// automatically turn off duped spawners
((XmlSpawner)newItem).Running = false;
base.OnAfterDuped(newItem);
}
public override void OnMapChange()
{
base.OnMapChange();
// unregister the skill trigger on the previous map
XmlSpawnerSkillCheck.UnRegisterSkillTrigger(this, m_SkillTriggerName, currentmap, false);
// register the skill trigger on the new current map
XmlSpawnerSkillCheck.RegisterSkillTrigger(this, m_SkillTriggerName, this.Map);
currentmap = this.Map;
// reset the sector list for smart spawning
ResetSectorList();
}
public override void OnDoubleClick(Mobile from)
{
if (from == null || from.Deleted || from.AccessLevel < AccessLevel.GameMaster || (m_SpawnerGump != null && SomeOneHasGumpOpen)) return;
// flag the first person to open the spawner as the placer
if (FirstModifiedBy == null) FirstModifiedBy = from.Name;
LastModifiedBy = from.Name;
// clear any text entry books that might still be around
DeleteTextEntryBook();
int x = 0;
int y = 0;
// read the text entries for default values
Account acct = from.Account as Account;
if (acct != null)
{
XmlSpawnerDefaults.DefaultEntry defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), from.Name);
if (defs != null)
{
x = defs.SpawnerGumpX;
y = defs.SpawnerGumpY;
}
}
XmlSpawnerGump g = new XmlSpawnerGump(this, x, y, 0, 0, 0);
from.SendGump(g);
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
if (m_Running)
{
list.Add(1060742); // active
}
else
{
list.Add(1060743); // inactive
}
// add whitespace to the beginning to avoid any problem with names that begin with # and are interpreted as cliloc ids
list.Add(1042971, " " + Name); // ~1_val~
list.Add(1060656, m_Count.ToString()); // amount to make: ~1_val~
list.Add(1061169, m_HomeRange.ToString()); // range ~1_val~
int nlist_items = 6;
if (m_Group)
{
list.Add(1060658 + 6 - nlist_items, "group\t{0}", m_Group); // ~1_val~: ~2_val~
nlist_items--;
}
if (m_Team != 0)
{
list.Add(1060658 + 6 - nlist_items, "team\t{0}", m_Team); // ~1_val~: ~2_val~
nlist_items--;
}
list.Add(1060658 + 6 - nlist_items, "speed\t{0} to {1}", m_MinDelay, m_MaxDelay); // ~1_val~: ~2_val~
nlist_items--;
// display the duration parameter in the prop gump if it is non-zero
if (m_Duration > TimeSpan.FromMinutes(0))
{
list.Add(1060658 + 6 - nlist_items, "Duration\t{0}", m_Duration);
nlist_items--;
}
// display the proximity range parameter in the prop gump if it is active
if (m_ProximityRange != -1)
{
list.Add(1060658 + 6 - nlist_items, "ProximityRange\t{0}", m_ProximityRange);
nlist_items--;
}
if (m_SpawnObjects != null)
for (int i = 0; i < nlist_items && i < m_SpawnObjects.Count; ++i)
{
string typename = m_SpawnObjects[i].TypeName;
if (typename != null && typename.Length > 20)
{
typename = typename.Substring(0, 20);
}
list.Add(1060658 + (6 - nlist_items) + i, " {0}\t{1}", typename, m_SpawnObjects[i].SpawnedObjects.Count);
}
// ARTEGORDONMOD
// mod to display attachment properties
XmlAttach.AddAttachmentProperties(this, list);
}
public override void OnSingleClick(Mobile from)
{
LabelTo(from, "XmlSpawner");
LabelTo(from, Name + (m_Running == true ? " [On]" : " [Off]"));
}
public override void OnDelete()
{
base.OnDelete();
if (ShowBounds == true)
ShowBounds = false;
RemoveSpawnObjects();
// remove any text entry books that might still be attached to the spawner
DeleteTextEntryBook();
if (m_Timer != null)
m_Timer.Stop();
if (m_DurTimer != null)
m_DurTimer.Stop();
if (m_RefractoryTimer != null)
m_RefractoryTimer.Stop();
// if statics were added for marking container held spawners, delete them
if (m_ShowContainerStatic != null && !m_ShowContainerStatic.Deleted)
m_ShowContainerStatic.Delete();
// unregister all triggerskills that might have been added
XmlSpawnerSkillCheck.UnRegisterSkillTrigger(this, SkillName.Alchemy, this.Map, true);
}
static bool IgnoreLocationChange = false;
public override void OnLocationChange(Point3D oldLocation)
{
if (IgnoreLocationChange)
{
IgnoreLocationChange = false;
return;
}
// calculate the positional shift
if (oldLocation.X > 0 && oldLocation.Y > 0)
{
int diffx = this.X - oldLocation.X;
int diffy = this.Y - oldLocation.Y;
m_X += diffx;
m_Y += diffy;
}
else
{
// Keep the original dimensions the same (Width, Height),
// just recalculate the new top left corner
m_X = this.X - (m_Width / 2);
m_Y = this.Y - (m_Height / 2);
}
// reset the sector list for smart spawning
ResetSectorList();
// Check if the spawner is showing its bounds
if (ShowBounds == true)
{
ShowBounds = false;
ShowBounds = true;
}
}
#endregion
#region Gump support
public bool SomeOneHasGumpOpen
{
get
{
// go through all online mobiles and see if any have xmlspawner gumps open
List<NetState> states = NetState.Instances;
for (int i = 0; i < states.Count; ++i)
{
Mobile m = ((NetState)states[i]).Mobile;
if (m != null && m.HasGump(typeof(XmlSpawnerGump)))
{
return true;
}
}
return false;
}
}
public static void SpawnerGumpCallback(Mobile from, object invoker, string response)
{
// assign the response to the gumpstate
if (invoker is XmlSpawner)
{
XmlSpawner xs = (XmlSpawner)invoker;
xs.GumpState = response;
}
}
public void DeleteTextEntryBook()
{
if (m_TextEntryBook != null)
{
foreach (XmlTextEntryBook s in m_TextEntryBook)
s.Delete();
m_TextEntryBook = null;
}
}
#endregion
#region Utility Methods
private static bool IsConstructable(ConstructorInfo ctor)
{
return ctor.IsDefined(typeof(ConstructableAttribute), false);
}
public static int ConvertToInt(string value)
{
if (value.StartsWith("0x"))
{
return Convert.ToInt32(value.Substring(2), 16);
}
else
{
return Convert.ToInt32(value);
}
}
public static void ExecuteAction(object attachedto, Mobile trigmob, string action)
{
Point3D loc = Point3D.Zero;
Map map = null;
if (attachedto is IEntity)
{
loc = ((IEntity)attachedto).Location;
map = ((IEntity)attachedto).Map;
}
if (action == null || action.Length <= 0 || attachedto == null || map == null) 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, attachedto, trigmob, action);
string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName);
if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName))
{
BaseXmlSpawner.SpawnTypeKeyword(attachedto, TheSpawn, typeName, substitutedtypeName, true, trigmob, 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, trigmob, attachedto, out status_str);
}
else
if (o is Item)
{
Item item = (Item)o;
BaseXmlSpawner.AddSpawnItem(null, attachedto, TheSpawn, item, loc, map, trigmob, false, substitutedtypeName, out status_str);
}
}
catch { }
}
}
private static void RemoveFromSectorTable(Sector s, XmlSpawner spawner)
{
if (s == null || s.Owner == null || s.Owner == Map.Internal || GlobalSectorTable[s.Owner.MapID] == null) return;
// find the sector
List<XmlSpawner> spawnerlist;
if (GlobalSectorTable[s.Owner.MapID].TryGetValue(s, out spawnerlist) && spawnerlist!=null)
{
//List<XmlSpawner> spawnerlist = GlobalSectorTable[s.Owner.MapID][s];
if (spawnerlist.Contains(spawner))
{
spawnerlist.Remove(spawner);
}
}
}
private void ResetSectorList()
{
// remove the global sector entries
if (sectorList != null)
{
foreach (Sector s in sectorList)
{
RemoveFromSectorTable(s, this);
}
}
sectorList = null;
UseSectorActivate = false;
//IsInactivated = false;
// force an update of the sector list
bool sectorrefresh = HasActiveSectors;
}
public void LoadXmlConfig(string filename)
{
if (filename == null || filename.Length <= 0) return;
// Check if the file exists
if (System.IO.File.Exists(filename) == true)
{
FileStream fs = null;
try
{
fs = File.Open(filename, FileMode.Open, FileAccess.Read);
}
catch { }
if (fs == null)
{
status_str = String.Format("Unable to open {0} for loading", filename);
return;
}
// Create the data set
DataSet ds = new DataSet(XmlDataSetName);
// Read in the file
bool fileerror = false;
try
{
ds.ReadXml(fs);
}
catch { fileerror = true; }
// close the file
fs.Close();
if (fileerror)
{
Console.WriteLine("XmlSpawner: Error in XML config file '{0}'", filename);
return;
}
// Check that at least a single table was loaded
if (ds.Tables != null && ds.Tables.Count > 0)
{
if (ds.Tables[XmlTableName] != null && ds.Tables[XmlTableName].Rows.Count > 0)
{
foreach (DataRow dr in ds.Tables[XmlTableName].Rows)
{
bool valid_entry;
string strEntry = null;
bool boolEntry = true;
double doubleEntry = 0;
int intEntry = 0;
valid_entry = true;
try { strEntry = (string)dr["Name"]; }
catch { valid_entry = false; }
if (valid_entry) { Name = strEntry; }
valid_entry = true;
try { intEntry = int.Parse((string)dr["X"]); }
catch { valid_entry = false; }
if (valid_entry) { m_X = intEntry; }
valid_entry = true;
try { intEntry = int.Parse((string)dr["Y"]); }
catch { valid_entry = false; }
if (valid_entry) { m_Y = intEntry; }
valid_entry = true;
try { intEntry = int.Parse((string)dr["Width"]); }
catch { valid_entry = false; }
if (valid_entry) { m_Width = intEntry; }
valid_entry = true;
try { intEntry = int.Parse((string)dr["Height"]); }
catch { valid_entry = false; }
if (valid_entry) { m_Height = intEntry; }
valid_entry = true;
try { intEntry = int.Parse((string)dr["CentreX"]); }
catch { valid_entry = false; }
if (valid_entry) { X = intEntry; }
valid_entry = true;
try { intEntry = int.Parse((string)dr["CentreY"]); }
catch { valid_entry = false; }
if (valid_entry) { Y = intEntry; }
valid_entry = true;
try { intEntry = int.Parse((string)dr["CentreZ"]); }
catch { valid_entry = false; }
if (valid_entry) { Z = intEntry; }
valid_entry = true;
try { intEntry = int.Parse((string)dr["SequentialSpawning"]); }
catch { valid_entry = false; }
if (valid_entry) { m_SequentialSpawning = intEntry; }
valid_entry = true;
try { intEntry = int.Parse((string)dr["ProximityRange"]); }
catch { valid_entry = false; }
if (valid_entry) { m_ProximityRange = intEntry; }
valid_entry = true;
try { strEntry = (string)dr["ProximityTriggerMessage"]; }
catch { valid_entry = false; }
if (valid_entry) { m_ProximityTriggerMessage = strEntry; }
valid_entry = true;
try { strEntry = (string)dr["SpeechTrigger"]; }
catch { valid_entry = false; }
if (valid_entry) { m_SpeechTrigger = strEntry; }
valid_entry = true;
try { strEntry = (string)dr["SkillTrigger"]; }
catch { valid_entry = false; }
if (valid_entry) { m_SkillTrigger = strEntry; }
valid_entry = true;
try { intEntry = int.Parse((string)dr["ProximityTriggerSound"]); }
catch { valid_entry = false; }
if (valid_entry) { m_ProximityTriggerSound = intEntry; }
valid_entry = true;
try { strEntry = (string)dr["ItemTriggerName"]; }
catch { valid_entry = false; }
if (valid_entry) { m_ItemTriggerName = strEntry; }
valid_entry = true;
try { strEntry = (string)dr["NoItemTriggerName"]; }
catch { valid_entry = false; }
if (valid_entry) { m_NoItemTriggerName = strEntry; }
// check for the delayinsec entry
bool delayinsec = false;
try { delayinsec = bool.Parse((string)dr["DelayInSec"]); }
catch { }
valid_entry = true;
try { doubleEntry = double.Parse((string)dr["MinDelay"]); }
catch { valid_entry = false; }
if (valid_entry) { if (delayinsec) m_MinDelay = TimeSpan.FromSeconds(doubleEntry); else m_MinDelay = TimeSpan.FromMinutes(doubleEntry); }
valid_entry = true;
try { doubleEntry = double.Parse((string)dr["MaxDelay"]); }
catch { valid_entry = false; }
if (valid_entry) { if (delayinsec) m_MaxDelay = TimeSpan.FromSeconds(doubleEntry); else m_MaxDelay = TimeSpan.FromMinutes(doubleEntry); }
valid_entry = true;
try { doubleEntry = double.Parse((string)dr["Duration"]); }
catch { valid_entry = false; }
if (valid_entry) { m_Duration = TimeSpan.FromMinutes(doubleEntry); }
valid_entry = true;
try { doubleEntry = double.Parse((string)dr["DespawnTime"]); }
catch { valid_entry = false; }
if (valid_entry) { m_DespawnTime = TimeSpan.FromHours(doubleEntry); }
valid_entry = true;
try { doubleEntry = double.Parse((string)dr["MinRefractory"]); }
catch { valid_entry = false; }
if (valid_entry) { m_MinRefractory = TimeSpan.FromMinutes(doubleEntry); }
valid_entry = true;
try { doubleEntry = double.Parse((string)dr["MaxRefractory"]); }
catch { valid_entry = false; }
if (valid_entry) { m_MaxRefractory = TimeSpan.FromMinutes(doubleEntry); }
valid_entry = true;
try { doubleEntry = double.Parse((string)dr["TODStart"]); }
catch { valid_entry = false; }
if (valid_entry) { m_TODStart = TimeSpan.FromMinutes(doubleEntry); }
valid_entry = true;
try { doubleEntry = double.Parse((string)dr["TODEnd"]); }
catch { valid_entry = false; }
if (valid_entry) { m_TODEnd = TimeSpan.FromMinutes(doubleEntry); }
valid_entry = true;
try { intEntry = int.Parse((string)dr["TODMode"]); }
catch { valid_entry = false; }
if (valid_entry) { m_TODMode = (TODModeType)intEntry; }
valid_entry = true;
try { intEntry = int.Parse((string)dr["Amount"]); }
catch { valid_entry = false; }
if (valid_entry) { m_StackAmount = intEntry; }
valid_entry = true;
try { intEntry = int.Parse((string)dr["MaxCount"]); }
catch { valid_entry = false; }
if (valid_entry) { m_Count = intEntry; }
valid_entry = true;
try { intEntry = int.Parse((string)dr["Range"]); }
catch { valid_entry = false; }
if (valid_entry) { m_HomeRange = intEntry; }
valid_entry = true;
try { intEntry = int.Parse((string)dr["Team"]); }
catch { valid_entry = false; }
if (valid_entry) { m_Team = intEntry; }
valid_entry = true;
try { strEntry = (string)dr["WayPoint"]; }
catch { valid_entry = false; }
if (valid_entry) { m_WayPoint = GetWaypoint(strEntry); }
valid_entry = true;
try { intEntry = int.Parse((string)dr["KillReset"]); }
catch { valid_entry = false; }
if (valid_entry) { m_KillReset = intEntry; }
valid_entry = true;
try { doubleEntry = double.Parse((string)dr["TriggerProbability"]); }
catch { valid_entry = false; }
if (valid_entry) { m_TriggerProbability = doubleEntry; }
valid_entry = true;
try { boolEntry = bool.Parse((string)dr["ExternalTriggering"]); }
catch { valid_entry = false; }
if (valid_entry) { m_ExternalTriggering = boolEntry; }
valid_entry = true;
try { boolEntry = bool.Parse((string)dr["IsGroup"]); }
catch { valid_entry = false; }
if (valid_entry) { m_Group = boolEntry; }
valid_entry = true;
try { boolEntry = bool.Parse((string)dr["IsHomeRangeRelative"]); }
catch { valid_entry = false; }
if (valid_entry) { m_HomeRangeIsRelative = boolEntry; }
valid_entry = true;
try { boolEntry = bool.Parse((string)dr["AllowGhostTriggering"]); }
catch { valid_entry = false; }
if (valid_entry) { m_AllowGhostTriggering = boolEntry; }
valid_entry = true;
try { boolEntry = bool.Parse((string)dr["AllowNPCTriggering"]); }
catch { valid_entry = false; }
if (valid_entry) { m_AllowNPCTriggering = boolEntry; }
valid_entry = true;
try { boolEntry = bool.Parse((string)dr["SpawnOnTrigger"]); }
catch { valid_entry = false; }
if (valid_entry) { m_SpawnOnTrigger = boolEntry; }
valid_entry = true;
try { boolEntry = bool.Parse((string)dr["SmartSpawning"]); }
catch { valid_entry = false; }
if (valid_entry) { m_SmartSpawning = boolEntry; }
valid_entry = true;
try { strEntry = (string)dr["RegionName"]; }
catch { valid_entry = false; }
if (valid_entry)
{
RegionName = strEntry;
}
valid_entry = true;
try { strEntry = (string)dr["PlayerPropertyName"]; }
catch { valid_entry = false; }
if (valid_entry)
{
m_PlayerPropertyName = strEntry;
}
valid_entry = true;
try { strEntry = (string)dr["MobPropertyName"]; }
catch { valid_entry = false; }
if (valid_entry)
{
m_MobPropertyName = strEntry;
}
valid_entry = true;
try { strEntry = (string)dr["MobTriggerName"]; }
catch { valid_entry = false; }
if (valid_entry)
{
m_MobTriggerName = strEntry;
}
valid_entry = true;
try { strEntry = (string)dr["ObjectPropertyName"]; }
catch { valid_entry = false; }
if (valid_entry)
{
m_ObjectPropertyName = strEntry;
}
valid_entry = true;
try { strEntry = (string)dr["ObjectPropertyItemName"]; }
catch { valid_entry = false; }
if (valid_entry)
{
string[] typeargs = strEntry.Split(",".ToCharArray(), 2);
string typestr = null;
string namestr = strEntry;
if (typeargs.Length > 1)
{
namestr = typeargs[0];
typestr = typeargs[1];
}
m_ObjectPropertyItem = BaseXmlSpawner.FindItemByName(this, namestr, typestr);
}
valid_entry = true;
try { strEntry = (string)dr["SetPropertyItemName"]; }
catch { valid_entry = false; }
if (valid_entry)
{
string[] typeargs = strEntry.Split(",".ToCharArray(), 2);
string typestr = null;
string namestr = strEntry;
if (typeargs.Length > 1)
{
namestr = typeargs[0];
typestr = typeargs[1];
}
m_SetPropertyItem = BaseXmlSpawner.FindItemByName(this, namestr, typestr);
}
valid_entry = true;
try { strEntry = (string)dr["Name"]; }
catch { valid_entry = false; }
if (valid_entry) { Name = strEntry; }
valid_entry = true;
try { strEntry = (string)dr["Map"]; }
catch { valid_entry = false; }
if (valid_entry)
{
// Convert the xml map value to a real map object
try
{
Map = Map.Parse(strEntry);
}
catch { }
}
// try loading the new spawn specifications first
SpawnObject[] Spawns = new SpawnObject[0];
bool havenew = true;
valid_entry = true;
try { Spawns = SpawnObject.LoadSpawnObjectsFromString2((string)dr["Objects2"]); }
catch { havenew = false; }
if (!havenew)
{
// try loading the new spawn specifications
try { Spawns = SpawnObject.LoadSpawnObjectsFromString((string)dr["Objects"]); }
catch { valid_entry = false; }
// can only have one of these defined
}
if (valid_entry)
{
// clear existing spawns
RemoveSpawnObjects();
// Create the new array of spawned objects
m_SpawnObjects = new List<XmlSpawner.SpawnObject>();
// Assign the list of objects to spawn
SpawnObjects = Spawns;
}
}
}
}
}
}
public void ReportStatus()
{
if (PropertyInfoList != null)
{
Console.WriteLine("PropertyInfoList: {0}", PropertyInfoList.Count);
foreach (BaseXmlSpawner.TypeInfo to in PropertyInfoList)
{
Console.WriteLine("\t{0}", to.t);
foreach (PropertyInfo p in to.plist)
{
Console.WriteLine("\t\t{0}", p);
}
}
}
ShowTagList(this);
int count = 0;
Console.WriteLine("Registered Skills");
Console.WriteLine("Felucca");
for (int i = 0; i < XmlSpawnerSkillCheck.RegisteredSkill.MaxSkills + 1; i++)
{
if (XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Felucca).Count > 0)
Console.WriteLine("\t{0} : {1}", (SkillName)i, XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Felucca).Count);
count += XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Felucca).Count;
}
Console.WriteLine("Trammel");
for (int i = 0; i < XmlSpawnerSkillCheck.RegisteredSkill.MaxSkills + 1; i++)
{
if (XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Trammel).Count > 0)
Console.WriteLine("\t{0} : {1}", (SkillName)i, XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Trammel).Count);
count += XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Trammel).Count;
}
Console.WriteLine("Ilshenar");
for (int i = 0; i < XmlSpawnerSkillCheck.RegisteredSkill.MaxSkills + 1; i++)
{
if (XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Ilshenar).Count > 0)
Console.WriteLine("\t{0} : {1}", (SkillName)i, XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Ilshenar).Count);
count += XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Ilshenar).Count;
}
Console.WriteLine("Malas");
for (int i = 0; i < XmlSpawnerSkillCheck.RegisteredSkill.MaxSkills + 1; i++)
{
if (XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Malas).Count > 0)
Console.WriteLine("\t{0} : {1}", (SkillName)i, XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Malas).Count);
count += XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Malas).Count;
}
Console.WriteLine("Tokuno");
for (int i = 0; i < XmlSpawnerSkillCheck.RegisteredSkill.MaxSkills + 1; i++)
{
if (XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Tokuno).Count > 0)
Console.WriteLine("\t{0} : {1}", (SkillName)i, XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Tokuno).Count);
count += XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Tokuno).Count;
}
Console.WriteLine("Total = {0}", count);
}
#endregion
#region Trace support
#if(TRACE)
string setname1 = _traceName[1] = "XmlFind";
string setname2 = _traceName[2] = "HasSector";
string setname4 = _traceName[4] = "AttachSpeech";
string setname5 = _traceName[5] = "HasHold";
string setname8 = _traceName[8] = "OnTick";
string setname9 = _traceName[9] = "Defrag";
string setname10 = _traceName[10] = "Respawn";
string setname11 = _traceName[11] = "SetProp";
string setname12 = _traceName[12] = "AttachMovement";
string setname13 = _traceName[13] = "ActiveSector";
string setname15 = _traceName[15] = "DistroTick";
string setname16 = _traceName[16] = "GetScaledFaction";
string setname17 = _traceName[17] = "FactionOnKill";
string setname18 = _traceName[18] = "CheckAcquire";
private const int MaxTraces = 20;
private static DateTime[] _traceStart = new DateTime[MaxTraces];
public static TimeSpan[] _traceTotal = new TimeSpan[MaxTraces];
public static string[] _traceName = new string[MaxTraces];
public static int[] _traceCount = new int[MaxTraces];
private static DateTime _traceStartTime = DateTime.UtcNow;
private static double _startProcessTime = 0;
public static void _TraceStart(int index)
{
if(index < MaxTraces){
_traceStart[index] = DateTime.UtcNow;
//_traceStart[index] = Process.GetCurrentProcess().UserProcessorTime;
}
}
public static void _TraceEnd(int index)
{
if(index < MaxTraces){
XmlSpawner._traceTotal[index] = XmlSpawner._traceTotal[index].Add(DateTime.UtcNow - _traceStart[index]);
//XmlSpawner._traceTotal[index] = XmlSpawner._traceTotal[index].Add(Process.GetCurrentProcess().UserProcessorTime - _traceStart[index]);
XmlSpawner._traceCount[index]++;
}
}
#else
public static void _TraceStart(int index) { }
public static void _TraceEnd(int index) { }
#endif
#endregion
#region Trigger Methods
private bool ValidPlayerTrig(Mobile m)
{
if (m == null || m.Deleted) return false;
return ((m.Player || m_AllowNPCTriggering) && (m.AccessLevel <= TriggerAccessLevel) && ((!m.Body.IsGhost && !m_AllowGhostTriggering) || (m.Body.IsGhost && m_AllowGhostTriggering)));
}
private bool AllowTriggering
{
get
{
return m_Running && !m_refractActivated && TODInRange && CanSpawn;
}
}
private void ActivateTrigger()
{
// reset the timer
DoTimer();
// start the refractory timer to set proximity activated to false, thus enabling another activation
if (m_MaxRefractory > TimeSpan.FromMinutes(0))
{
int minSeconds = (int)m_MinRefractory.TotalSeconds;
int maxSeconds = (int)m_MaxRefractory.TotalSeconds;
DoTimer3(TimeSpan.FromSeconds(Utility.RandomMinMax(minSeconds, maxSeconds)));
}
// if the spawnontrigger flag is set, then spawn immediately
if (m_SpawnOnTrigger)
{
NextSpawn = TimeSpan.Zero;
ResetNextSpawnTimes();
}
// reset speech triggering if it was set
m_speechTriggerActivated = false;
// reset skill triggering if it was set
m_skillTriggerActivated = false;
// reset external triggering if it was set
//this.m_ExternalTrigger = false;
}
public void CheckTriggers(Mobile m, Skill s, bool hasproximity)
{
// only proximity trigger when no spawns have already been triggered
if (AllowTriggering && !m_proximityActivated)
{
bool needs_item_trigger = false;
bool needs_speech_trigger = false;
bool needs_skill_trigger = false;
bool needs_object_trigger = false;
bool needs_mob_trigger = false;
bool needs_player_trigger = false;
bool needs_noitem_trigger = false;
bool has_object_trigger = false;
bool has_mob_trigger = false;
bool has_player_trigger = false;
bool has_item_trigger = false;
bool has_noitem_trigger = true; // assume the player doesnt have the trigger-blocking item until it is found by search
m_skipped = false;
// test for the various triggering options in the order of increasing computational demand. No point checking a high demand test
// if a low demand one has already failed.
// check for external triggering
if (m_ExternalTriggering && !m_ExternalTrigger) return;
// if speech triggering is set then test for successful activation
if (m_SpeechTrigger != null && m_SpeechTrigger.Length > 0)
{
needs_speech_trigger = true;
}
// check to see if we have to continue
if (needs_speech_trigger && !m_speechTriggerActivated) return;
// if skill triggering is set then test for successful activation
if (m_SkillTrigger != null && m_SkillTrigger.Length > 0)
{
needs_skill_trigger = true;
}
// check to see if we have to continue
if (needs_skill_trigger && !m_skillTriggerActivated) return;
// if item property triggering is set then test for the property value
//
if (m_ObjectPropertyName != null && m_ObjectPropertyName.Length > 0)
{
needs_object_trigger = true;
string status_str;
if (BaseXmlSpawner.TestItemProperty(this, m_ObjectPropertyItem, m_ObjectPropertyName, null, out status_str))
{
has_object_trigger = true;
}
else
has_object_trigger = false;
if (status_str != null && status_str.Length > 0)
{
this.status_str = status_str;
}
}
// check to see if we have to continue
if (needs_object_trigger && !has_object_trigger) return;
// if player property triggering is set then look for the mob and test properties
if (m_PlayerPropertyName != null && m_PlayerPropertyName.Length > 0)
{
needs_player_trigger = true;
string status_str;
if (BaseXmlSpawner.TestMobProperty(this, m, m_PlayerPropertyName, null, out status_str))
{
has_player_trigger = true;
}
else
has_player_trigger = false;
if (status_str != null && status_str.Length > 0)
{
this.status_str = status_str;
}
}
// check to see if we have to continue
if (needs_player_trigger && !has_player_trigger) return;
// if mob property triggering is set then look for the mob and test properties
if (m_MobPropertyName != null && m_MobPropertyName.Length > 0 &&
m_MobTriggerName != null && m_MobTriggerName.Length > 0)
{
needs_mob_trigger = true;
string status_str;
if (BaseXmlSpawner.TestMobProperty(this, MobTriggerId, m_MobPropertyName, null, out status_str))
{
has_mob_trigger = true;
}
else
has_mob_trigger = false;
if (status_str != null && status_str.Length > 0)
{
this.status_str = status_str;
}
}
// check to see if we have to continue
if (needs_mob_trigger && !has_mob_trigger) return;
// if player-carried item triggering is set then test for the presence of an item on the player an in their pack
if (m_ItemTriggerName != null && m_ItemTriggerName.Length > 0)
{
//enable_triggering = false;
needs_item_trigger = true;
has_item_trigger = BaseXmlSpawner.CheckForCarried(m, m_ItemTriggerName);
}
// check to see if we have to continue
if (needs_item_trigger && !has_item_trigger) return;
// if player-carried noitem triggering is set then test for the presence of an item in the players pack that should block triggering
if (m_NoItemTriggerName != null && m_NoItemTriggerName.Length > 0)
{
needs_noitem_trigger = true;
has_noitem_trigger = BaseXmlSpawner.CheckForNotCarried(m, m_NoItemTriggerName);
}
// check to see if we have to continue
if (needs_noitem_trigger && !has_noitem_trigger) return;
// if this was called without being proximity triggered then check to see that the non-movement triggers were enabled.
if (!hasproximity && !needs_object_trigger && !needs_mob_trigger && !m_ExternalTriggering) return;
// all of the necessary trigger conditions have been met so go ahead and trigger
// after you make the probability check
if (Utility.RandomDouble() < m_TriggerProbability)
{
// play a sound indicating the spawner has been triggered
if (m_ProximityTriggerSound > 0 && m != null && !m.Deleted)
m.PlaySound(m_ProximityTriggerSound);
// display the trigger message
if (m_ProximityTriggerMessage != null && m_ProximityTriggerMessage.Length > 0 && m != null && !m.Deleted)
m.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, m_ProximityTriggerMessage);
// enable spawning at the next ontick
// this will also start the refractory timer and send the triggering indicators
ProximityActivated = true;
// keep track of who triggered this
m_mob_who_triggered = m;
// keep track of the skill that triggered this
if (s != null)
{
m_skill_that_triggered = s.SkillName;
}
else
{
m_skill_that_triggered = XmlSpawnerSkillCheck.RegisteredSkill.Invalid;
}
}
else
{
m_skipped = true;
// reset speech triggering if it was set
m_speechTriggerActivated = false;
// reset skill triggering if it was set
m_skillTriggerActivated = false;
// reset external triggering if it was set
//this.m_ExternalTrigger = false;
}
}
}
public bool HandlesOnSkillUse { get { return (m_Running && m_SkillTrigger != null && m_SkillTrigger.Length > 0); } }
// this is the handler for skill use
public void OnSkillUse(Mobile m, Skill skill, bool success)
{
if (m_Running && m_ProximityRange >= 0 && ValidPlayerTrig(m) && CanSpawn && !m_refractActivated && TODInRange)
{
if (!Utility.InRange(m.Location, this.Location, m_ProximityRange))
return;
m_skillTriggerActivated = false;
// check the skill trigger conditions, Skillname[+/-][,min,max]
if (m_SkillTrigger != null && (skill.SkillName == m_SkillTriggerName) &&
((m_SkillTriggerMin < 0) || (skill.Value >= m_SkillTriggerMin)) &&
((m_SkillTriggerMax < 0) || (skill.Value <= m_SkillTriggerMax)) &&
((m_SkillTriggerSuccess == 3) || ((m_SkillTriggerSuccess == 1) && success) || ((m_SkillTriggerSuccess == 2) && !success)))
{
// have a skill trigger so flag it and test it
m_skillTriggerActivated = true;
CheckTriggers(m, skill, true);
}
}
}
public override bool HandlesOnSpeech { get { return (m_Running && m_SpeechTrigger != null && m_SpeechTrigger.Length > 0); } }
public override void OnSpeech(SpeechEventArgs e)
{
if ( /*!e.Handled && */m_Running && m_ProximityRange >= 0 && ValidPlayerTrig(e.Mobile) && CanSpawn && !m_refractActivated && TODInRange)
{
m_speechTriggerActivated = false;
if (!Utility.InRange(e.Mobile.Location, this.Location, m_ProximityRange))
return;
if (m_SpeechTrigger != null && e.Speech.ToLower().IndexOf(m_SpeechTrigger.ToLower()) >= 0)
{
e.Handled = true;
// found the speech trigger so flag it for testing in the onmovement handler where the other proximity features are tested
m_speechTriggerActivated = true;
CheckTriggers(e.Mobile, null, true);
}
}
}
public override bool HandlesOnMovement
{
get
{
return (m_Running && m_ProximityRange >= 0);
}
}
public void AddToMovementList(Mobile m)
{
// go through the list and check for redundancy
if (m_MovementList == null)
{
m_MovementList = new List<MovementInfo>();
}
// check to see if the movement timer is running
if (m_MovementTimer == null || !m_MovementTimer.Running)
{
DoMovementTimer(TimeSpan.FromSeconds(1));
}
bool add = true;
foreach (MovementInfo moveinfo in m_MovementList)
{
Mobile mtrig = moveinfo.trigMob;
if (mtrig == m)
{
add = false;
break;
}
}
// wasnt on the list so add it
if (add)
{
// is the list at max throttling length?
if (m_MovementList.Count > MaxMoveCheck)
{
// replace a random entry in the current list with this one
m_MovementList[Utility.Random(m_MovementList.Count)] = new MovementInfo(m);
}
else
{
m_MovementList.Add(new MovementInfo(m));
}
}
}
public void DoMovementTimer(TimeSpan delay)
{
if (m_MovementTimer != null)
m_MovementTimer.Stop();
m_MovementTimer = new MovementTimer(this, delay);
m_MovementTimer.Start();
}
private class MovementTimer : Timer
{
private XmlSpawner m_Spawner;
public MovementTimer(XmlSpawner spawner, TimeSpan delay)
: base(delay)
{
Priority = TimerPriority.OneSecond;
m_Spawner = spawner;
}
protected override void OnTick()
{
// check everyone on the movement list then clear the list
if (m_Spawner != null && !m_Spawner.Deleted)
{
if (m_Spawner.m_Running && !m_Spawner.m_proximityActivated && !m_Spawner.m_refractActivated && m_Spawner.TODInRange && m_Spawner.CanSpawn)
{
int count = 0;
int maxspeed = 0;
int speed = 0;
foreach (MovementInfo moveinfo in m_Spawner.m_MovementList)
{
Mobile m = moveinfo.trigMob;
if (m == null) continue;
// additional throttling in here by limiting number of mobs that can be checked in a single ontick
count++;
if (count > MaxMoveCheck) break;
speed = (int)GetDistance(m.Location, moveinfo.trigLocation);
if (speed > maxspeed) maxspeed = speed;
m_Spawner.CheckTriggers(m, null, true);
}
m_Spawner.MovingPlayerCount = m_Spawner.m_MovementList.Count;
m_Spawner.FastestPlayerSpeed = maxspeed;
}
m_Spawner.m_MovementList.Clear();
}
}
}
public static double GetDistance(Point3D p1, Point3D p2)
{
int xDelta = p1.X - p2.X;
int yDelta = p1.Y - p2.Y;
return Math.Sqrt((xDelta * xDelta) + (yDelta * yDelta));
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
if (m_Running && m_ProximityRange >= 0 && ValidPlayerTrig(m) && CanSpawn)
{
// check to see if player is within range of the spawner
if ((this.Parent == null) && Utility.InRange(m.Location, this.Location, m_ProximityRange))
{
// add some throttling code here.
// add the player to a list that gets cleared every few seconds, checking for redundancy then trigger off of the list instead of off of
// the actual movement stream
AddToMovementList(m);
// check the triggers in the OnTick for the list handler instead of here
}
else
{
// clear any speech triggering
m_speechTriggerActivated = false;
// clear any skill triggering
m_skillTriggerActivated = false;
}
}
base.OnMovement(m, oldLocation);
}
#endregion
#region Initialization
public static bool AssignSettings(string argname, string value)
{
switch (argname)
{
case "XmlSpawnDir":
XmlSpawnDir = value;
break;
case "DiskAccessLevel":
DiskAccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), value, true);
break;
case "SmartSpawnAccessLevel":
SmartSpawnAccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), value, true);
break;
case "XmlConfigsDir":
XmlConfigsDir = value;
break;
case "defaultTriggerSound":
defaultTriggerSound = ConvertToInt(value);
defProximityTriggerSound = defaultTriggerSound;
break;
case "BaseItemId":
BaseItemId = ConvertToInt(value);
break;
case "ShowItemId":
ShowItemId = ConvertToInt(value);
break;
case "MaxMoveCheck":
MaxMoveCheck = ConvertToInt(value);
break;
case "defMinDelay":
defMinDelay = TimeSpan.FromMinutes(ConvertToInt(value));
break;
case "defMaxDelay":
defMaxDelay = TimeSpan.FromMinutes(ConvertToInt(value));
break;
case "defRelativeHome":
defRelativeHome = bool.Parse(value);
break;
case "defSpawnRange":
defSpawnRange = ConvertToInt(value);
break;
case "defHomeRange":
defHomeRange = ConvertToInt(value);
break;
case "JournalNotifyColor":
XmlQuestHolder.JournalNotifyColor = ConvertToInt(value);
break;
case "JournalEchoColor":
XmlQuestHolder.JournalEchoColor = ConvertToInt(value);
break;
case "BlockKeyword":
{
// parse the keyword list and remove them from the keyword hashtables
string[] keywordlist = value.Split(',');
if (keywordlist != null && keywordlist.Length > 0)
{
for (int i = 0; i < keywordlist.Length; i++)
{
BaseXmlSpawner.RemoveKeyword(keywordlist[i]);
}
}
break;
}
case "BlockCommand":
case "ChangeCommand":
// delay processing of these settings until after all commands have been registered in their Initialize methods
Timer.DelayCall(TimeSpan.Zero, new TimerStateCallback(DelayedAssignSettings), new object[] { argname, value });
break;
default:
return false;
}
return true;
}
private static void DelayedAssignSettings(object state)
{
object[] args = (object[])state;
string argname = (string)args[0];
string value = (string)args[1];
switch (argname)
{
case "BlockCommand":
{
// delay processing of this until after all commands have been registered in their Initialize methods
// parse the command list and remove them from the command hashtables
// the syntax is "commandname, commandname, etc."
string[] keywordlist = value.Split(',');
if (keywordlist != null && keywordlist.Length > 0)
{
for (int i = 0; i < keywordlist.Length; i++)
{
string commandname = keywordlist[i].Trim().ToLower();
try
{
CommandSystem.Entries.Remove(commandname);
}
catch
{
Console.WriteLine("{0}: invalid command {1}", argname, commandname);
}
}
}
break;
}
case "ChangeCommand":
{
// delay processing of this until after all commands have been registered in their Initialize methods
// parse the command list and rehash them into the command hashtables
// the syntax is "oldname:newname[:accesslevel], oldname:newname[:accesslevel], etc."
string[] keywordlist = value.Split(',');
if (keywordlist != null && keywordlist.Length > 0)
{
for (int i = 0; i < keywordlist.Length; i++)
{
string[] namelist = keywordlist[i].Split(':');
if (namelist != null && namelist.Length > 1)
{
string oldname = namelist[0].Trim().ToLower();
string newname = namelist[1].Trim();
if (newname.Length == 0) newname = oldname;
AccessLevel access = AccessLevel.Player;
bool validaccess = false;
if (namelist.Length > 2)
{
// get the new accesslevel
try
{
access = (AccessLevel)Enum.Parse(typeof(AccessLevel), namelist[2].Trim(), true);
validaccess = true;
}
catch
{
Console.WriteLine("{0}: invalid accesslevel {1} for {2}", argname, namelist[2], newname);
}
}
// find the command entry for the old name
CommandEntry e = null;
try
{
e = CommandSystem.Entries[oldname];
}
catch
{
Console.WriteLine("{0}: invalid command {1}", argname, oldname);
}
if (e != null)
{
if (!validaccess)
{
// use the old accesslevel
access = e.AccessLevel;
}
// remove the old command entry
CommandSystem.Entries.Remove(oldname);
// register the new command using the old handler
CommandSystem.Register(newname, access, e.Handler);
}
// also look in the targetcommands list and adjust name and accesslevel there
foreach (BaseCommand b in TargetCommands.AllCommands)
{
if (b.Commands != null)
{
for (int j = 0; j < b.Commands.Length; j++)
{
string commandname = b.Commands[j];
if (commandname.ToLower() == oldname)
{
// modify the basecommand with the new name and access
b.Commands[j] = newname;
if (validaccess)
{
b.AccessLevel = access;
}
// re-register it in the implementors hashtable
List<BaseCommandImplementor> impls = BaseCommandImplementor.Implementors;
for (int k = 0; k < impls.Count; ++k)
{
BaseCommandImplementor impl = impls[k];
if ((b.Supports & impl.SupportRequirement) != 0)
{
try
{
impl.Commands.Remove(commandname);
}
catch { }
impl.Register(b);
}
}
break;
}
}
}
}
}
}
}
break;
}
}
}
public delegate bool AssignSettingsHandler(string argname, string value);
// load in settings from the xmlspawner2.cfg file in the Data directory
public static void LoadSettings(AssignSettingsHandler settingshandler, string section)
{
// Check if the file exists
string path = Path.Combine(Core.BaseDirectory, "Data/xmlspawner.cfg");
if (!File.Exists(path))
{
return;
}
Console.WriteLine("Loading {0} configuration", section);
using (StreamReader ip = new StreamReader(path))
{
string line;
string currentsection = null;
int nsettings = 0;
while ((line = ip.ReadLine()) != null)
{
line = line.Trim();
// skip comments
if (line.Length == 0 || line.StartsWith("#"))
continue;
if (line.StartsWith("["))
{
// parse the section name
string[] args = line.Split("[]".ToCharArray(), 3);
if (args.Length > 2)
{
currentsection = args[1].Trim();
}
}
// only process the matching classname section
if (currentsection != section)
continue;
string[] split = line.Split('=');
if (split.Length >= 2)
{
string argname = split[0].Trim();
string value = split[1].Trim();
if (argname.Length == 0 || value.Length == 0)
continue;
try
{
if (settingshandler(argname, value))
nsettings++;
else
Console.WriteLine("'{0}' setting is invalid in section [{1}]", argname, currentsection);
}
catch (Exception e)
{
Console.WriteLine("Config error '{0}'='{1}'", argname, value);
Console.WriteLine("Error: {0}", e.Message);
}
}
}
if (nsettings > 0)
{
Console.WriteLine("{0} settings processed", nsettings);
}
}
}
public static void Initialize()
{
XmlSpawner.LoadSettings(new XmlSpawner.AssignSettingsHandler(AssignSettings), "XmlSpawner");
// initialize the default waypoint name
WayPoint tmpwaypoint = new WayPoint();
if (tmpwaypoint != null)
{
defwaypointname = tmpwaypoint.Name;
tmpwaypoint.Delete();
}
// 2004.02.08 :: Omega Red
// initialize m_Region fields after world load (now, regions are loaded)
// Now this gets handled in OnTick
int count = 0;
int regional = 0;
//int timercount=0;
foreach (Item item in World.Items.Values)
{
if (item is XmlSpawner)
{
count++;
XmlSpawner spawner = ((XmlSpawner)item);
if (spawner.RegionName != null && spawner.RegionName != string.Empty)
{
spawner.RegionName = spawner.RegionName; // invoke set(RegionName)
regional++;
}
// check for smart spawning and restart timers after deser if needed
// note, HasActiveSectors will recalculate the sector list and UseSectorActivate property
bool recalc_sectors = spawner.HasActiveSectors;
/*
if(spawner.SmartSpawning && spawner.IsInactivated && !spawner.UseSectorActivate)
{
spawner.DoSectorTimer(TimeSpan.FromSeconds(1));
timercount++;
}
*/
// add in the totalitem mod to keep them from adding to container counts
//spawner.TotalItems = -1;
//spawner.UpdateTotal(spawner, TotalType.Items, -1);
spawner.RestoreISpawner();
}
}
// start the global smartspawning timer
if (SmartSpawningSystemEnabled)
{
DoGlobalSectorTimer(TimeSpan.FromSeconds(1));
}
// standard commands
CommandSystem.Register("XmlSpawnerShowAll", AccessLevel.Administrator, new CommandEventHandler(ShowSpawnPoints_OnCommand));
CommandSystem.Register("XmlSpawnerHideAll", AccessLevel.Administrator, new CommandEventHandler(HideSpawnPoints_OnCommand));
CommandSystem.Register("XmlSpawnerWipe", AccessLevel.Administrator, new CommandEventHandler(Wipe_OnCommand));
CommandSystem.Register("XmlSpawnerWipeAll", AccessLevel.Administrator, new CommandEventHandler(WipeAll_OnCommand));
CommandSystem.Register("XmlSpawnerLoad", DiskAccessLevel, new CommandEventHandler(Load_OnCommand));
CommandSystem.Register("XmlSpawnerSave", DiskAccessLevel, new CommandEventHandler(Save_OnCommand));
CommandSystem.Register("XmlSpawnerSaveAll", DiskAccessLevel, new CommandEventHandler(SaveAll_OnCommand));
//added respawn commands
CommandSystem.Register("XmlSpawnerRespawn", AccessLevel.Seer, new CommandEventHandler(Respawn_OnCommand));
CommandSystem.Register("XmlSpawnerRespawnAll", AccessLevel.Seer, new CommandEventHandler(RespawnAll_OnCommand));
// ok, I'm lazy. I dont like all that typing, so these are two aliases for the longer commands
CommandSystem.Register("XmlShow", AccessLevel.Administrator, new CommandEventHandler(ShowSpawnPoints_OnCommand));
CommandSystem.Register("XmlHide", AccessLevel.Administrator, new CommandEventHandler(HideSpawnPoints_OnCommand));
CommandSystem.Register("XmlHome", AccessLevel.GameMaster, new CommandEventHandler(XmlHome_OnCommand));
CommandSystem.Register("XmlUnLoad", DiskAccessLevel, new CommandEventHandler(UnLoad_OnCommand));
CommandSystem.Register("XmlSpawnerUnLoad", DiskAccessLevel, new CommandEventHandler(UnLoad_OnCommand));
CommandSystem.Register("XmlLoad", DiskAccessLevel, new CommandEventHandler(Load_OnCommand));
CommandSystem.Register("XmlLoadHere", DiskAccessLevel, new CommandEventHandler(LoadHere_OnCommand));
CommandSystem.Register("XmlNewLoad", DiskAccessLevel, new CommandEventHandler(NewLoad_OnCommand));
CommandSystem.Register("XmlNewLoadHere", DiskAccessLevel, new CommandEventHandler(NewLoadHere_OnCommand));
CommandSystem.Register("XmlSave", DiskAccessLevel, new CommandEventHandler(Save_OnCommand));
CommandSystem.Register("XmlSaveAll", DiskAccessLevel, new CommandEventHandler(SaveAll_OnCommand));
CommandSystem.Register("XmlSaveOld", DiskAccessLevel, new CommandEventHandler(SaveOld_OnCommand));
CommandSystem.Register("XmlImportSpawners", DiskAccessLevel, new CommandEventHandler(XmlImportSpawners_OnCommand));
CommandSystem.Register("XmlImportMSF", DiskAccessLevel, new CommandEventHandler(XmlImportMSF_OnCommand));
CommandSystem.Register("XmlImportMap", DiskAccessLevel, new CommandEventHandler(XmlImportMap_OnCommand));
CommandSystem.Register("XmlDefaults", AccessLevel.Administrator, new CommandEventHandler(XmlDefaults_OnCommand));
CommandSystem.Register("XmlGet", AccessLevel.GameMaster, new CommandEventHandler(XmlGetValue_OnCommand));
TargetCommands.Register(new XmlSetCommand());
//CommandSystem.Register( "XmlSet", AccessLevel.GameMaster, new CommandEventHandler( XmlSetValue_OnCommand ) );
CommandSystem.Register("OptimalSmartSpawning", AccessLevel.Administrator, new CommandEventHandler(OptimalSmartSpawning_OnCommand));
CommandSystem.Register("SmartStat", AccessLevel.GameMaster, new CommandEventHandler(SmartStat_OnCommand));
CommandSystem.Register("XmlGo", AccessLevel.GameMaster, new CommandEventHandler(SpawnEditorGo_OnCommand));
//CommandSystem.Register( "TagList", AccessLevel.Administrator, new CommandEventHandler( ShowTagList_OnCommand ) );
TargetCommands.Register( new XmlSaveSingle() );
#if(TRACE)
CommandSystem.Register( "XmlMake", AccessLevel.Administrator, new CommandEventHandler( XmlMake_OnCommand ) );
CommandSystem.Register( "XmlTrace", AccessLevel.Administrator, new CommandEventHandler( XmlTrace_OnCommand ) );
CommandSystem.Register( "XmlResetTrace", AccessLevel.Administrator, new CommandEventHandler( XmlResetTrace_OnCommand ) );
#endif
}
#endregion
#region Commands
[Usage("XmlGet property")]
[Description("Returns value of the property on the targeted object.")]
public static void XmlGetValue_OnCommand(CommandEventArgs e)
{
e.Mobile.Target = new GetValueTarget(e);
}
private class GetValueTarget : Target
{
private CommandEventArgs m_e;
public GetValueTarget(CommandEventArgs e)
: base(30, false, TargetFlags.None)
{
m_e = e;
}
protected override void OnTarget(Mobile from, object targeted)
{
string pname = m_e.GetString(0);
Type ptype;
string result = BaseXmlSpawner.GetPropertyValue(null, targeted, pname, out ptype);
// see if it was successful
if (ptype == null)
{
return;
}
from.SendMessage("{0}", result);
}
}
public class XmlSetCommand : BaseCommand
{
public XmlSetCommand()
{
AccessLevel = AccessLevel.Administrator;
Supports = CommandSupport.All;
Commands = new string[] { "XmlSet" };
ObjectTypes = ObjectTypes.Both;
Usage = "XmlSet <propertyName> <value>";
Description = "Sets a property value by name of a targeted object. Provides access to all public properties.";
}
public override void Execute(CommandEventArgs e, object obj)
{
if (e.Length >= 2)
{
string result = BaseXmlSpawner.SetPropertyValue(null, obj, e.GetString(0), e.GetString(1));
if (result == "Property has been set.")
AddResponse(result);
else
LogFailure(result);
}
else
{
LogFailure("Format: XmlSet <propertyName> <value>");
}
}
}
[Usage("TagList property")]
[Description("Lists the keyword taglist for a spawner")]
public static void ShowTagList_OnCommand(CommandEventArgs e)
{
e.Mobile.Target = new TagListTarget(e);
}
private class TagListTarget : Target
{
private CommandEventArgs m_e;
public TagListTarget(CommandEventArgs e)
: base(30, false, TargetFlags.None)
{
m_e = e;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (targeted is XmlSpawner)
((XmlSpawner)targeted).ShowTagList((XmlSpawner)targeted);
}
}
public void ShowTagList(XmlSpawner spawner)
{
int count = 0;
Console.WriteLine("{0} tags", spawner.m_KeywordTagList.Count);
foreach (BaseXmlSpawner.KeywordTag tag in spawner.m_KeywordTagList)
{
count++;
Console.WriteLine("tag {0} : {1}", count, BaseXmlSpawner.TagInfo(tag));
}
}
// added in targeting for the [xmlhome command
private class XmlHomeTarget : Target
{
private CommandEventArgs m_e;
public XmlHomeTarget(CommandEventArgs e)
: base(30, false, TargetFlags.None)
{
m_e = e;
}
protected override void OnTarget(Mobile from, object targeted)
{
XmlSpawner spawner = null;
if (targeted is XmlSpawner)
{
if (m_e.GetString(0) == "status")
{
((XmlSpawner)targeted).ReportStatus();
return;
}
}
if (targeted is Mobile)
{
spawner = ((Mobile)targeted).Spawner as XmlSpawner;
}
else
if (targeted is Item)
{
spawner = ((Item)targeted).Spawner as XmlSpawner;
}
if (spawner == null)
{
from.SendMessage("Unable to find spawner for this object");
return;
}
// check to make sure it is still on the spawner
foreach (SpawnObject so in spawner.m_SpawnObjects)
{
for (int x = 0; x < so.SpawnedObjects.Count; x++)
{
object o = so.SpawnedObjects[x];
if (o == targeted)
{
from.SendMessage("{0}, {1}, {2}", spawner.X, spawner.Y, spawner.Z);
if (m_e.GetString(0) == "go")
{
// make sure the spawner is not in a container.
if (spawner.Parent == null)
{
from.Location = new Point3D(spawner.Location);
from.Map = spawner.Map;
}
else
{
from.SendMessage("Spawner is in a container");
}
}
else
if (m_e.GetString(0) == "send")
{
// make sure the spawner is not in a container.
if (spawner.Parent == null)
{
if (o is Item)
{
((Item)o).Location = new Point3D(spawner.Location);
((Item)o).Map = spawner.Map;
}
if (o is Mobile)
{
((Mobile)o).Location = new Point3D(spawner.Location);
((Mobile)o).Map = spawner.Map;
}
}
else
{
from.SendMessage("Spawner is in a container");
}
}
else
if (m_e.GetString(0) == "gump")
{
spawner.OnDoubleClick(from);
}
return;
}
}
}
}
}
[Usage("XmlHome [go][gump][send]")]
[Description("Returns the coordinates of the spawner for the targeted object. Args: 'go' teleports to spawner, 'gump' opens spawner gump, 'send' sends mob home")]
public static void XmlHome_OnCommand(CommandEventArgs e)
{
e.Mobile.Target = new XmlHomeTarget(e);
}
private static void XmlSaveDefaults(string filePath, Mobile m)
{
if (filePath == null || filePath.Length < 1) return;
using (StreamWriter op = new StreamWriter(filePath))
{
if (op == null)
{
m.SendMessage("unable to open file {0}", filePath);
}
XmlTextWriter xml = new XmlTextWriter(op);
xml.Formatting = Formatting.Indented;
xml.IndentChar = '\t';
xml.Indentation = 1;
xml.WriteStartDocument(true);
xml.WriteStartElement("XmlDefaults");
xml.WriteStartElement("defProximityRange");
xml.WriteString(XmlSpawner.defProximityRange.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defTriggerProbability");
xml.WriteString(XmlSpawner.defTriggerProbability.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defProximityTriggerSound");
xml.WriteString(XmlSpawner.defProximityTriggerSound.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defMinRefractory");
xml.WriteString(XmlSpawner.defMinRefractory.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defMaxRefractory");
xml.WriteString(XmlSpawner.defMaxRefractory.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defTODStart");
xml.WriteString(XmlSpawner.defTODStart.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defTODEnd");
xml.WriteString(XmlSpawner.defTODEnd.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defStackAmount");
xml.WriteString(XmlSpawner.defAmount.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defDuration");
xml.WriteString(XmlSpawner.defDuration.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defIsGroup");
xml.WriteString(XmlSpawner.defIsGroup.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defTeam");
xml.WriteString(XmlSpawner.defTeam.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defRelativeHome");
xml.WriteString(XmlSpawner.defRelativeHome.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defSpawnRange");
xml.WriteString(XmlSpawner.defSpawnRange.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defHomeRange");
xml.WriteString(XmlSpawner.defHomeRange.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defMinDelay");
xml.WriteString(XmlSpawner.defMinDelay.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defMaxDelay");
xml.WriteString(XmlSpawner.defMaxDelay.ToString());
xml.WriteEndElement();
xml.WriteStartElement("defTODMode");
xml.WriteString(XmlSpawner.defTODMode.ToString());
xml.WriteEndElement();
xml.WriteEndElement();
xml.Close();
}
m.SendMessage("defaults saved to {0}", filePath);
}
public static void XmlLoadDefaults(string filePath, Mobile m)
{
if (m == null || m.Deleted) return;
if (filePath != null && filePath.Length >= 1)
{
if (File.Exists(filePath))
{
XmlDocument doc = new XmlDocument();
doc.Load(filePath);
XmlElement root = doc["XmlDefaults"];
LoadDefaults(root);
m.SendMessage("defaults loaded successfully from {0}", filePath);
}
else
{
m.SendMessage("File {0} does not exist.", filePath);
}
}
}
private static void LoadDefaults(XmlElement node)
{
try { XmlSpawner.defProximityRange = int.Parse(node["defProximityRange"].InnerText); }
catch { }
try { XmlSpawner.defTriggerProbability = double.Parse(node["defTriggerProbability"].InnerText); }
catch { }
try { XmlSpawner.defProximityTriggerSound = int.Parse(node["defProximityTriggerSound"].InnerText); }
catch { }
try { XmlSpawner.defMinRefractory = TimeSpan.Parse(node["defMinRefractory"].InnerText); }
catch { }
try { XmlSpawner.defMaxRefractory = TimeSpan.Parse(node["defMaxRefractory"].InnerText); }
catch { }
try { XmlSpawner.defTODStart = TimeSpan.Parse(node["defTODStart"].InnerText); }
catch { }
try { XmlSpawner.defTODEnd = TimeSpan.Parse(node["defTODEnd"].InnerText); }
catch { }
try { XmlSpawner.defAmount = int.Parse(node["defStackAmount"].InnerText); }
catch { }
try { XmlSpawner.defDuration = TimeSpan.Parse(node["defDuration"].InnerText); }
catch { }
try { XmlSpawner.defIsGroup = bool.Parse(node["defIsGroup"].InnerText); }
catch { }
try { XmlSpawner.defTeam = int.Parse(node["defTeam"].InnerText); }
catch { }
try { XmlSpawner.defRelativeHome = bool.Parse(node["defRelativeHome"].InnerText); }
catch { }
try { XmlSpawner.defSpawnRange = int.Parse(node["defSpawnRange"].InnerText); }
catch { }
try { XmlSpawner.defHomeRange = int.Parse(node["defHomeRange"].InnerText); }
catch { }
try { XmlSpawner.defMinDelay = TimeSpan.Parse(node["defMinDelay"].InnerText); }
catch { }
try { XmlSpawner.defMaxDelay = TimeSpan.Parse(node["defMaxDelay"].InnerText); }
catch { }
int todmode = 0;
try { todmode = int.Parse(node["defTODMode"].InnerText); }
catch { }
switch (todmode)
{
case (int)TODModeType.Realtime:
XmlSpawner.defTODMode = TODModeType.Realtime;
break;
case (int)TODModeType.Gametime:
XmlSpawner.defTODMode = TODModeType.Gametime;
break;
}
}
[Usage("XmlDefaults [defaultpropertyname value]")]
[Description("Returns or changes the default settings of the spawner.")]
public static void XmlDefaults_OnCommand(CommandEventArgs e)
{
Mobile m = e.Mobile;
if (m == null || m.Deleted) return;
if (e.Arguments.Length >= 1)
{
// leave open the possibility of just requesting display of a single property
if (e.Arguments.Length == 2)
{
if (e.Arguments[0].ToLower() == "save")
{
XmlSaveDefaults(e.Arguments[1], m);
}
else
if (e.Arguments[0].ToLower() == "load")
{
XmlLoadDefaults(e.Arguments[1], m);
}
else
// try to set the property
if (e.Arguments[0].ToLower() == "maxdelay")
{
try
{
XmlSpawner.defMaxDelay = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1]));
m.SendMessage("MaxDelay = {0}", XmlSpawner.defMaxDelay);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "mindelay")
{
try
{
XmlSpawner.defMinDelay = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1]));
m.SendMessage("MinDelay = {0}", XmlSpawner.defMinDelay);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "spawnrange")
{
try
{
XmlSpawner.defSpawnRange = Convert.ToInt32(e.Arguments[1]);
m.SendMessage("SpawnRange = {0}", XmlSpawner.defSpawnRange);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "homerange")
{
try
{
XmlSpawner.defHomeRange = Convert.ToInt32(e.Arguments[1]);
m.SendMessage("HomeRange = {0}", XmlSpawner.defHomeRange);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "relativehome")
{
try
{
XmlSpawner.defRelativeHome = Convert.ToBoolean(e.Arguments[1]);
m.SendMessage("RelativeHome = {0}", XmlSpawner.defRelativeHome);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "proximitytriggersound")
{
try
{
XmlSpawner.defProximityTriggerSound = Convert.ToInt32(e.Arguments[1]);
m.SendMessage("ProximityTriggerSound = {0}", XmlSpawner.defProximityTriggerSound);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "proximityrange")
{
try
{
XmlSpawner.defProximityRange = Convert.ToInt32(e.Arguments[1]);
m.SendMessage("ProximityRange = {0}", XmlSpawner.defProximityRange);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "triggerprobability")
{
try
{
XmlSpawner.defTriggerProbability = Convert.ToDouble(e.Arguments[1]);
m.SendMessage("TriggerProbability = {0}", XmlSpawner.defTriggerProbability);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "todstart")
{
try
{
XmlSpawner.defTODStart = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1]));
m.SendMessage("TODStart = {0}", XmlSpawner.defTODStart);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "todend")
{
try
{
XmlSpawner.defTODEnd = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1]));
m.SendMessage("TODEnd = {0}", XmlSpawner.defTODEnd);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "stackamount")
{
try
{
XmlSpawner.defAmount = Convert.ToInt32(e.Arguments[1]);
m.SendMessage("StackAmount = {0}", XmlSpawner.defAmount);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "duration")
{
try
{
XmlSpawner.defDuration = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1]));
m.SendMessage("Duration = {0}", XmlSpawner.defDuration);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "group")
{
try
{
XmlSpawner.defIsGroup = Convert.ToBoolean(e.Arguments[1]);
m.SendMessage("Group = {0}", XmlSpawner.defIsGroup);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "team")
{
try
{
XmlSpawner.defTeam = Convert.ToInt32(e.Arguments[1]);
m.SendMessage("Team = {0}", XmlSpawner.defTeam);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "todmode")
{
int todmode = (int)TODModeType.Realtime;
try
{
todmode = Convert.ToInt32(e.Arguments[1]);
switch (todmode)
{
case (int)TODModeType.Gametime:
XmlSpawner.defTODMode = TODModeType.Gametime;
break;
case (int)TODModeType.Realtime:
XmlSpawner.defTODMode = TODModeType.Realtime;
break;
}
m.SendMessage("TODMode = {0}", XmlSpawner.defTODMode);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "maxrefractory")
{
try
{
XmlSpawner.defMaxRefractory = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1]));
m.SendMessage("MaxRefractory = {0}", XmlSpawner.defMaxRefractory);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
if (e.Arguments[0].ToLower() == "minrefractory")
{
try
{
XmlSpawner.defMinRefractory = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1]));
m.SendMessage("MinRefractory = {0}", XmlSpawner.defMinRefractory);
}
catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); }
}
else
{
m.SendMessage("{0} : no such default value.", e.Arguments[0]);
}
}
}
else
{
// just display the values
m.SendMessage("TriggerProbability = {0}", XmlSpawner.defTriggerProbability);
m.SendMessage("ProximityRange = {0}", XmlSpawner.defProximityRange);
m.SendMessage("ProximityTriggerSound = {0}", XmlSpawner.defProximityTriggerSound);
m.SendMessage("MinRefractory = {0}", XmlSpawner.defMinRefractory);
m.SendMessage("MaxRefractory = {0}", XmlSpawner.defMaxRefractory);
m.SendMessage("TODStart = {0}", XmlSpawner.defTODStart);
m.SendMessage("TODEnd = {0}", XmlSpawner.defTODEnd);
m.SendMessage("TODMode = {0}", XmlSpawner.defTODMode);
m.SendMessage("StackAmount = {0}", XmlSpawner.defAmount);
m.SendMessage("Duration = {0}", XmlSpawner.defDuration);
m.SendMessage("Group = {0}", XmlSpawner.defIsGroup);
m.SendMessage("Team = {0}", XmlSpawner.defTeam);
m.SendMessage("RelativeHome = {0}", XmlSpawner.defRelativeHome);
m.SendMessage("SpawnRange = {0}", XmlSpawner.defSpawnRange);
m.SendMessage("HomeRange = {0}", XmlSpawner.defHomeRange);
m.SendMessage("MinDelay = {0}", XmlSpawner.defMinDelay);
m.SendMessage("MaxDelay = {0}", XmlSpawner.defMaxDelay);
}
}
[Usage("XmlSpawnerShowAll")]
[Aliases("XmlShow")]
[Description("Makes all XmlSpawner objects movable and also changes the item id to a blue ships mast for easy identification.")]
public static void ShowSpawnPoints_OnCommand(CommandEventArgs e)
{
List<Item> ToShow = new List<Item>();
foreach (Item item in World.Items.Values)
{
if (item is XmlSpawner)
{
//turned off visibility. Admins will still see masts but players will not.
item.Visible = false; // set the spawn item visibility
item.Movable = false; // Make the spawn item movable
item.Hue = 88; // Bright blue colour so its easy to spot
item.ItemID = ShowItemId; // Ship Mast (Very tall, easy to see if beneath other objects)
// find container-held spawners to be marked with an external static
if ((item.Parent != null) && (item.RootParent is Container))
{
ToShow.Add(item);
}
}
}
// place the statics
foreach (XmlSpawner xml_item in ToShow)
{
// does the spawner already have a static attached to it? could happen if two showall commands are issued in a row.
// if so then dont add another
if ((xml_item.m_ShowContainerStatic == null || xml_item.m_ShowContainerStatic.Deleted) && xml_item.RootParent is Container)
{
Container root_item = (Container)xml_item.RootParent;
// calculate a world location for the static. Position it just above the container
int x = root_item.Location.X;
int y = root_item.Location.Y;
int z = root_item.Location.Z + 10;
Static s = new Static(ShowItemId);
s.Visible = false;
s.MoveToWorld(new Point3D(x, y, z), root_item.Map);
xml_item.m_ShowContainerStatic = s;
}
}
}
[Usage("XmlSpawnerHideAll")]
[Aliases("XmlHide")]
[Description("Makes all XmlSpawner objects invisible and unmovable returns the object id to the default.")]
public static void HideSpawnPoints_OnCommand(CommandEventArgs e)
{
List<Item> ToDelete = new List<Item>();
foreach (Item item in World.Items.Values)
{
if (item is XmlSpawner)
{
item.Visible = false;
item.Movable = false;
item.Hue = 0;
item.ItemID = BaseItemId;
// get rid of the external static marker for container-held spawners
// check anything that might have been tagged with a container static
XmlSpawner xml_item = (XmlSpawner)item;
if (xml_item.m_ShowContainerStatic != null && !xml_item.m_ShowContainerStatic.Deleted)
{
ToDelete.Add(item);
}
}
}
foreach (XmlSpawner xml_item in ToDelete)
{
if (xml_item.m_ShowContainerStatic != null && !xml_item.m_ShowContainerStatic.Deleted)
{
xml_item.m_ShowContainerStatic.Delete();
}
}
}
[Usage("XmlGo <map> | <map> <x> <y> [z]")]
[Description("Go command used with spawn editor, takes the name of the map as the first parameter.")]
private static void SpawnEditorGo_OnCommand(CommandEventArgs e)
{
if (e == null) return;
Mobile from = e.Mobile;
// Make sure a map name was given at least
if (from != null && e.Length >= 1)
{
// Get the map
Map NewMap = null;
string MapName = e.Arguments[0];
// Convert the xml map value to a real map object
if (string.Compare(MapName, Map.Trammel.Name, true) == 0)
NewMap = Map.Trammel;
else if (string.Compare(MapName, Map.Felucca.Name, true) == 0)
NewMap = Map.Felucca;
else if (string.Compare(MapName, Map.Ilshenar.Name, true) == 0)
NewMap = Map.Ilshenar;
else if (string.Compare(MapName, Map.Malas.Name, true) == 0)
NewMap = Map.Malas;
else if (string.Compare(MapName, Map.Tokuno.Name, true) == 0)
NewMap = Map.Tokuno;
else
{
from.SendMessage("Map '{0}' does not exist!", MapName);
return;
}
// Now that the map has been determined, continue
// Check if the request is to simply change maps
if (e.Length == 1)
{
// Map Change ONLY
from.Map = NewMap;
}
else if (e.Length == 3)
{
// Map & X Y ONLY
if (NewMap != null)
{
int x = e.GetInt32(1);
int y = e.GetInt32(2);
int z = NewMap.GetAverageZ(x, y);
from.Map = NewMap;
from.Location = new Point3D(x, y, z);
}
}
else if (e.Length == 4)
{
// Map & X Y Z
from.Map = NewMap;
from.Location = new Point3D(e.GetInt32(1), e.GetInt32(2), e.GetInt32(3));
}
else
{
from.SendMessage("Format: XmlGo <map> | <map> <x> <y> [z]");
}
}
}
[Usage("SmartStat [accesslevel Player/Counselor/GameMaster/Seer/Administrator]")]
[Description("Returns the spawn reduction due to SmartSpawning.")]
public static void SmartStat_OnCommand(CommandEventArgs e)
{
if (e == null || e.Mobile == null) return;
if (e.Arguments.Length > 1 && e.Arguments[0].ToLower() == "accesslevel" && e.Mobile.AccessLevel >= AccessLevel.Administrator)
{
try
{
SmartSpawnAccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), e.Arguments[1], true);
}
catch { }
}
// handle the
// number of spawners
int count = 0;
// number of actual spawns
int currentcount = 0;
int smartcount = 0;
int inactivecount = 0;
// maximum possible spawns
int totalcount = 0;
int maxcount = 0;
// maximum possible of spawns that are currently inactivated
int savings = 0;
foreach (Item item in World.Items.Values)
{
if (item is XmlSpawner)
{
XmlSpawner spawner = (XmlSpawner)item;
if (spawner.Deleted) continue;
totalcount += spawner.MaxCount;
// get the current count without defragging
currentcount += spawner.SafeCurrentCount;
count++;
// check to see if smartspawning is set
if (spawner.SmartSpawning)
{
smartcount++;
maxcount += spawner.MaxCount;
}
if (spawner.IsInactivated)
{
inactivecount++;
savings += spawner.MaxCount;
}
}
}
int percent = 0;
//if((currentcount + savings) > 0)
//{
// percent = 100*savings/(currentcount + savings);
//}
int maxpercent = 0;
if (totalcount > 0)
{
percent = 100 * savings / totalcount;
maxpercent = 100 * maxcount / totalcount;
}
e.Mobile.SendMessage(
"Running XmlSpawner version {9}\n" +
"Smartspawning access level is {11}\n" +
"--------------------------------\n" +
"{0} XmlSpawners\n" +
"{1} are configured for SmartSpawning\n" +
"{2} are currently inactivated\n" +
"{10} sectors being monitored\n" +
"Maximum possible spawn count is {3}\n" +
"Maximum possible spawn reduction is {4}\n" +
"Current spawn count is {5}\n" +
"Current spawn reduction is {6}\n" +
"Maximum possible savings is {7}%\n" +
"Current savings is {8}%",
count, smartcount, inactivecount, totalcount, maxcount, currentcount, savings, maxpercent,
percent, Version, totalSectorsMonitored, SmartSpawnAccessLevel);
}
[Usage("OptimalSmartSpawning [max spawn/homerange diff]")]
[Description("Activates SmartSpawning on XmlSpawners that are well-suited for use of this feature.")]
public static void OptimalSmartSpawning_OnCommand(CommandEventArgs e)
{
int maxdiff = 1;
if (e.Arguments.Length > 0)
{
try
{
maxdiff = int.Parse(e.Arguments[0]);
}
catch { }
}
int count = 0;
int maxcount = 0;
foreach (Item item in World.Items.Values)
{
if (item is XmlSpawner)
{
XmlSpawner spawner = (XmlSpawner)item;
// determine whether this spawner is a good candidate
if (spawner.Deleted) continue;
// ignore spawners in towns
//if (Region.Find(spawner.Location, spawner.Map) is Regions.TownRegion) continue;
// dont bother setting it on triggered spawners
if (spawner.ProximityRange >= 0) continue;
// check the relative spawnrange and homerange. Dont set it on spawners with a larger homerange than spawnrange
int width = spawner.m_Width;
int height = spawner.m_Height;
if (spawner.HomeRange * 2 > width + maxdiff * 2 || spawner.HomeRange * 2 > height + maxdiff * 2 && spawner.m_Region != null) continue;
int nso = 0;
if (spawner.m_SpawnObjects != null) nso = spawner.m_SpawnObjects.Count;
// empty spawner so skip it
if (nso == 0) continue;
bool skipit = false;
// check the spawn types
for (int i = 0; i < nso; ++i)
{
SpawnObject so = spawner.m_SpawnObjects[i];
if (so == null) continue;
string typestr = so.TypeName;
Type type = SpawnerType.GetType(typestr);
// if it has basevendors on it or invalid types, then skip it
if (typestr == null || (type != null && (type == typeof(BaseVendor) || type.IsSubclassOf(typeof(BaseVendor)))) ||
((type == null) && (!BaseXmlSpawner.IsTypeOrItemKeyword(typestr) && typestr.IndexOf('{') == -1 && !typestr.StartsWith("*") && !typestr.StartsWith("#"))))
{
skipit = true;
break;
}
}
if (!skipit)
{
count++;
spawner.SmartSpawning = true;
maxcount += spawner.MaxCount;
}
}
}
e.Mobile.SendMessage("Configured {0} XmlSpawners for SmartSpawning using maxdiff of {1}", count, maxdiff);
e.Mobile.SendMessage("Estimated item/mob reduction is {0}", maxcount);
}
[Usage("XmlSpawnerWipe [SpawnerPrefixFilter]")]
[Description("Removes all XmlSpawner objects from the current map.")]
public static void Wipe_OnCommand(CommandEventArgs e)
{
WipeSpawners(e, false);
}
[Usage("XmlSpawnerWipeAll [SpawnerPrefixFilter]")]
[Description("Removes all XmlSpawner objects from the entire world.")]
public static void WipeAll_OnCommand(CommandEventArgs e)
{
WipeSpawners(e, true);
}
public static void XmlUnLoadFromFile(string filename, string SpawnerPrefix, Mobile from, out int processedmaps, out int processedspawners)
{
processedmaps = 0;
processedspawners = 0;
if (filename == null || filename.Length <= 0) return;
int total_processed_maps = 0;
int total_processed_spawners = 0;
// Check if the file exists
if (System.IO.File.Exists(filename) == true)
{
FileStream fs = null;
try
{
fs = File.Open(filename, FileMode.Open, FileAccess.Read);
}
catch { }
if (fs == null)
{
if (from != null)
from.SendMessage("Unable to open {0} for unloading", filename);
return;
}
XmlUnLoadFromStream(fs, filename, SpawnerPrefix, from, out processedmaps, out processedspawners);
}
else
// check to see if it is a directory
if (System.IO.Directory.Exists(filename) == true)
{
// if so then import all of the .xml files in the directory
string[] files = null;
try
{
files = Directory.GetFiles(filename, "*.xml");
}
catch { }
if (files != null && files.Length > 0)
{
if (from != null)
from.SendMessage("UnLoading {0} .xml files from directory {1}", files.Length, filename);
foreach (string file in files)
{
XmlUnLoadFromFile(file, SpawnerPrefix, from, out processedmaps, out processedspawners);
total_processed_maps += processedmaps;
total_processed_spawners += processedspawners;
}
}
// recursively search subdirectories for more .xml files
string[] dirs = null;
try
{
dirs = Directory.GetDirectories(filename);
}
catch { }
if (dirs != null && dirs.Length > 0)
{
foreach (string dir in dirs)
{
XmlUnLoadFromFile(dir, SpawnerPrefix, from, out processedmaps, out processedspawners);
total_processed_maps += processedmaps;
total_processed_spawners += processedspawners;
}
}
if (from != null)
from.SendMessage("UnLoaded a total of {0} .xml files and {2} spawners from directory {1}", total_processed_maps, filename, total_processed_spawners);
processedmaps = total_processed_maps;
processedspawners = total_processed_spawners;
}
else
{
if (from != null)
from.SendMessage("{0} does not exist", filename);
}
}
public static void XmlUnLoadFromStream(Stream fs, string filename, string SpawnerPrefix, Mobile from, out int processedmaps, out int processedspawners)
{
processedmaps = 0;
processedspawners = 0;
if (fs == null) return;
int TotalCount = 0;
int TrammelCount = 0;
int FeluccaCount = 0;
int IlshenarCount = 0;
int MalasCount = 0;
int TokunoCount = 0;
int OtherCount = 0;
int bad_spawner_count = 0;
int spawners_deleted = 0;
if (from != null)
from.SendMessage(string.Format("UnLoading {0} objects{1} from file {2}.",
"XmlSpawner", ((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty), filename));
// Create the data set
DataSet ds = new DataSet(SpawnDataSetName);
// Read in the file
//ds.ReadXml( e.Arguments[0].ToString() );
bool fileerror = false;
try
{
ds.ReadXml(fs);
}
catch
{
if (from != null)
from.SendMessage(33, "Error reading xml file {0}", filename);
fileerror = true;
}
// close the file
fs.Close();
if (fileerror) return;
// Check that at least a single table was loaded
if (ds.Tables != null && ds.Tables.Count > 0)
{
// Add each spawn point to the current map
if (ds.Tables[SpawnTablePointName] != null && ds.Tables[SpawnTablePointName].Rows.Count > 0)
{
foreach (DataRow dr in ds.Tables[SpawnTablePointName].Rows)
{
// load in the spawner info. Certain fields are required and therefore cannot be ignored
// the exception handler for those will flag bad_spawner and the result will be logged
// Each row makes up a single spawner
string SpawnName = "Spawner";
try { SpawnName = (string)dr["Name"]; }
catch { }
// Check if there is any spawner name criteria specified on the unload
if (SpawnerPrefix == null || (SpawnerPrefix.Length == 0) || (SpawnName.StartsWith(SpawnerPrefix) == true))
{
bool bad_spawner = false;
// Try load the GUID (might not work so create a new GUID)
Guid SpawnId = Guid.NewGuid();
try { SpawnId = new Guid((string)dr["UniqueId"]); }
catch { bad_spawner = true; }
// have to have a GUID or no point in continuing
if (bad_spawner)
{
bad_spawner_count++;
continue;
}
// Get the map (default to the mobiles map)
Map SpawnMap = Map.Internal;
string XmlMapName = SpawnMap.Name;
// Try to get the "map" field, but in case it doesn't exist, catch and discard the exception
try { XmlMapName = (string)dr["Map"]; }
catch { }
// Convert the xml map value to a real map object
if (string.Compare(XmlMapName, Map.Trammel.Name, true) == 0 || XmlMapName == "Trammel")
{
SpawnMap = Map.Trammel;
TrammelCount++;
}
else if (string.Compare(XmlMapName, Map.Felucca.Name, true) == 0 || XmlMapName == "Felucca")
{
SpawnMap = Map.Felucca;
FeluccaCount++;
}
else if (string.Compare(XmlMapName, Map.Ilshenar.Name, true) == 0 || XmlMapName == "Ilshenar")
{
SpawnMap = Map.Ilshenar;
IlshenarCount++;
}
else if (string.Compare(XmlMapName, Map.Malas.Name, true) == 0 || XmlMapName == "Malas")
{
SpawnMap = Map.Malas;
MalasCount++;
}
else if (string.Compare(XmlMapName, Map.Tokuno.Name, true) == 0 || XmlMapName == "Tokuno")
{
SpawnMap = Map.Tokuno;
TokunoCount++;
}
else
{
try
{
SpawnMap = Map.Parse(XmlMapName);
}
catch { }
OtherCount++;
}
// Check if this spawner already exists
XmlSpawner OldSpawner = null;
foreach (Item i in World.Items.Values)
{
if (i is XmlSpawner)
{
XmlSpawner CheckXmlSpawner = (XmlSpawner)i;
// Check if the spawners GUID is the same as the one being unloaded
// and that the spawners map is the same as the one being unloaded
if ((CheckXmlSpawner.UniqueId == SpawnId.ToString())
/*&& ( CheckXmlSpawner.Map == SpawnMap )*/ )
{
OldSpawner = (XmlSpawner)i;
if (OldSpawner != null)
{
spawners_deleted++;
OldSpawner.Delete();
}
break;
}
}
}
}
TotalCount++;
}
}
}
try
{
fs.Close();
}
catch { }
if (from != null)
from.SendMessage("{0}/{8} spawner(s) were unloaded using file {1} [Trammel={2}, Felucca={3}, Ilshenar={4}, Malas={5}, Tokuno={6}, Other={7}].",
spawners_deleted, filename, TrammelCount, FeluccaCount, IlshenarCount, MalasCount, TokunoCount, OtherCount, TotalCount);
if (bad_spawner_count > 0)
{
if (from != null)
from.SendMessage(33, "{0} bad spawners detected.", bad_spawner_count);
}
processedmaps = 1;
processedspawners = TotalCount;
}
[Usage("XmlSpawnerUnLoad <SpawnFile or directory> [SpawnerPrefixFilter]")]
[Aliases("XmlUnload")]
[Description("UnLoads XmlSpawner objects from the proper map as defined in the file supplied.")]
public static void UnLoad_OnCommand(CommandEventArgs e)
{
if (e.Mobile.AccessLevel >= DiskAccessLevel)
{
if (e.Arguments.Length >= 1)
{
// Spawner unload criteria (if any)
string SpawnerPrefix = string.Empty;
// Check if there is an argument provided (load criteria)
if (e.Arguments.Length > 1)
SpawnerPrefix = e.Arguments[1];
string filename = LocateFile(e.Arguments[0].ToString());
int processedmaps;
int processedspawners;
XmlUnLoadFromFile(filename, SpawnerPrefix, e.Mobile, out processedmaps, out processedspawners);
}
else
e.Mobile.SendMessage("Usage: {0} <SpawnFile or directory>", e.Command);
}
else
e.Mobile.SendMessage("You do not have rights to perform this command.");
}
[Usage("XmlImportMap <mapfile or directory>")]
[Description("Loads spawner definitions from a .map file")]
public static void XmlImportMap_OnCommand(CommandEventArgs e)
{
if (e.Mobile.AccessLevel >= DiskAccessLevel)
{
if (e.Arguments.Length >= 1)
{
string filename = e.Arguments[0].ToString();
int processedmaps;
int processedspawners;
XmlImportMap(filename, e.Mobile, out processedmaps, out processedspawners);
}
else
e.Mobile.SendMessage("Usage: {0} <MapFile>", e.Command);
}
else
e.Mobile.SendMessage("You do not have rights to perform this command.");
}
public static void XmlImportMap(string filename, Mobile from, out int processedmaps, out int processedspawners)
{
processedmaps = 0;
processedspawners = 0;
int total_processed_maps = 0;
int total_processed_spawners = 0;
if (filename == null || filename.Length <= 0 || from == null || from.Deleted) return;
// Check if the file exists
if (System.IO.File.Exists(filename) == true)
{
int spawnercount = 0;
int badspawnercount = 0;
int linenumber = 0;
// default is no map override, use the map spec from each spawn line
int overridemap = -1;
double overridemintime = -1;
double overridemaxtime = -1;
bool newformat = false;
try
{
// Create an instance of StreamReader to read from a file.
// The using statement also closes the StreamReader.
using (StreamReader sr = new StreamReader(filename))
{
string line;
// Read and display lines from the file until the end of
// the file is reached.
while ((line = sr.ReadLine()) != null)
{
// the old format of each .map line is * Dragon:Wyvern 5209 965 -40 2 2 10 50 30 1
// * typename:typename:... x y z map mindelay maxdelay homerange spawnrange maxcount
// * | typename:typename:... |s1 |s2 |s3 |s4 |s5 | x | y | z | map | mindelay maxdelay homerange spawnrange spawnid maxcount | maxcount1 | maxcount2 | maxcount3 | maxcount4 | maxcount5
// where s1-5 are additional spawn type entries with their own maxcounts
// the new format of each .map line is * |Dragon:Wyvern| spawns:spawns| | | | | 5209 | 965 | -40 | 2 | 2 | 10 | 50 | 30 | 1
linenumber++;
// is this the new format?
string[] args;
if (line.IndexOf('|') >= 0)
{
args = line.Trim().Split('|');
newformat = true;
}
else
{
args = line.Trim().Split(' ');
}
// determine the format of this line and parse accordingly
if (newformat)
{
ParseNewMapFormat(from, filename, line, args, linenumber, ref spawnercount, ref badspawnercount, ref overridemap, ref overridemintime, ref overridemaxtime);
}
else
{
ParseOldMapFormat(from, filename, line, args, linenumber, ref spawnercount, ref badspawnercount, ref overridemap, ref overridemintime, ref overridemaxtime);
}
}
sr.Close();
}
}
catch (Exception e)
{
// Let the user know what went wrong.
from.SendMessage("The file could not be read: {0}", e.Message);
}
from.SendMessage("Imported {0} spawners from {1}", spawnercount, filename);
from.SendMessage("{0} bad spawners detected", badspawnercount);
processedmaps = 1;
processedspawners = spawnercount;
}
else
// check to see if it is a directory
if (System.IO.Directory.Exists(filename) == true)
{
// if so then import all of the .map files in the directory
string[] files = null;
try
{
files = Directory.GetFiles(filename, "*.map");
}
catch { }
if (files != null && files.Length > 0)
{
from.SendMessage("Importing {0} .map files from directory {1}", files.Length, filename);
foreach (string file in files)
{
XmlImportMap(file, from, out processedmaps, out processedspawners);
total_processed_maps += processedmaps;
total_processed_spawners += processedspawners;
}
}
// recursively search subdirectories for more .map files
string[] dirs = null;
try
{
dirs = Directory.GetDirectories(filename);
}
catch { }
if (dirs != null && dirs.Length > 0)
{
foreach (string dir in dirs)
{
XmlImportMap(dir, from, out processedmaps, out processedspawners);
total_processed_maps += processedmaps;
total_processed_spawners += processedspawners;
}
}
from.SendMessage("Imported a total of {0} .map files and {2} spawners from directory {1}", total_processed_maps, filename, total_processed_spawners);
processedmaps = total_processed_maps;
processedspawners = total_processed_spawners;
}
else
{
from.SendMessage("{0} does not exist", filename);
}
}
private static void ParseNewMapFormat(Mobile from, string filename, string line, string[] args, int linenumber, ref int spawnercount, ref int badspawnercount, ref int overridemap, ref double overridemintime, ref double overridemaxtime)
{
// format of each .map line is * Dragon:Wyvern 5209 965 -40 2 2 10 50 30 1
// * typename:typename:... x y z map mindelay maxdelay homerange spawnrange maxcount
// or
// * typename:typename:... x y z map mindelay maxdelay homerange spawnrange spawnid maxcount
// ## are comments
// overridemap mapnumber
// map 0 is tram+fel
// map 1 is fel
// map 2 is tram
// map 3 is ilsh
// map 4 is mal
// map 5 is tokuno
//
// * | typename:typename:... | | | | | | x | y | z | map | mindelay maxdelay homerange spawnrange spawnid maxcount1 | maxcount2 | maxcount2 | maxcount3 | maxcount4 | maxcount5 | maxcount6
// the new format of each .map line is * |Dragon:Wyvern| spawns:spawns| | | | | 5209 | 965 | -40 | 2 | 2 | 10 | 50 | 30 | 1
if (args == null || from == null) return;
// look for the override keyword
if (args.Length == 2 && (args[0].ToLower() == "overridemap"))
{
try
{
overridemap = int.Parse(args[1]);
}
catch { }
}
else
if (args.Length == 2 && (args[0].ToLower() == "overridemintime"))
{
try
{
overridemintime = double.Parse(args[1]);
}
catch { }
}
else
if (args.Length == 2 && (args[0].ToLower() == "overridemaxtime"))
{
try
{
overridemaxtime = double.Parse(args[1]);
}
catch { }
}
else
// look for a spawn spec line
if (args.Length > 0 && (args[0] == "*"))
{
bool badspawn = false;
int x = 0;
int y = 0;
int z = 0;
int map = 0;
double mindelay = 0;
double maxdelay = 0;
int homerange = 0;
int spawnrange = 0;
int spawnid = 0;
string[][] typenames = new string[6][];
int[] maxcount = new int[6];
// parse the main args
try
{
// get the list of spawns
for (int k = 0; k < 6; k++)
typenames[k] = args[k + 1].Split(':');
x = int.Parse(args[7]);
y = int.Parse(args[8]);
z = int.Parse(args[9]);
map = int.Parse(args[10]);
mindelay = double.Parse(args[11]);
maxdelay = double.Parse(args[12]);
homerange = int.Parse(args[13]);
spawnrange = int.Parse(args[14]);
spawnid = int.Parse(args[15]);
for (int k = 0; k < 6; k++)
maxcount[k] = int.Parse(args[k + 16]);
}
catch { from.SendMessage("Parsing error at line {0}", linenumber); badspawn = true; }
// compute the total number of spawns
int totalspawns = 0;
int totalmaxcount = 0;
for (int k = 0; k < 6; k++)
{
if (typenames[k] == null) continue;
for (int i = 0; i < typenames[k].Length; i++)
{
if (typenames[k][i] == null || typenames[k][i].Length == 0) continue;
totalspawns++;
}
totalmaxcount += maxcount[k];
}
// apply min/maxdelay overrides
if (overridemintime != -1)
{
mindelay = overridemintime;
}
if (overridemaxtime != -1)
{
maxdelay = overridemaxtime;
}
if (mindelay > maxdelay) maxdelay = mindelay;
if (!badspawn && totalspawns > 0)
{
// everything seems ok so go ahead and make the spawner
// check for map override
if (overridemap >= 0) map = overridemap;
Map spawnmap = Map.Internal;
switch (map)
{
case 0:
spawnmap = Map.Felucca;
// note it also does trammel
break;
case 1:
spawnmap = Map.Felucca;
break;
case 2:
spawnmap = Map.Trammel;
break;
case 3:
spawnmap = Map.Ilshenar;
break;
case 4:
spawnmap = Map.Malas;
break;
case 5:
spawnmap = Map.Tokuno;
break;
}
if (!IsValidMapLocation(x, y, spawnmap))
{
// invalid so dont spawn it
badspawnercount++;
from.SendMessage("Invalid map/location at line {0}", linenumber);
from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber);
return;
}
// allow it to make an xmlspawner instead
// first add all of the creatures on the list
SpawnObject[] so = new SpawnObject[totalspawns];
int count = 0;
bool hasvendor = true;
for (int k = 0; k < 6; k++)
{
if (typenames[k] == null) continue;
for (int i = 0; i < typenames[k].Length; i++)
{
if (typenames[k][i] == null || typenames[k][i].Length == 0 || count > totalspawns) continue;
so[count++] = new SpawnObject(typenames[k][i], maxcount[k]);
// check the type to see if there are vendors on it
Type type = SpawnerType.GetType(typenames[k][i]);
// check for vendor-only spawners which get special spawnrange treatment
if (type != null && (type != typeof(BaseVendor) && !type.IsSubclassOf(typeof(BaseVendor))))
{
hasvendor = false;
}
}
}
// assign it a unique id
Guid SpawnId = Guid.NewGuid();
// and give it a name based on the spawner count and file
string spawnername = String.Format("{0}#{1}", Path.GetFileNameWithoutExtension(filename), spawnercount);
// Create the new xml spawner
XmlSpawner spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, totalmaxcount,
TimeSpan.FromMinutes(mindelay), TimeSpan.FromMinutes(maxdelay), TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1,
0, homerange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0),
TimeSpan.FromMinutes(0), null, null, null, null, null,
null, null, null, null, 1, null, false, defTODMode, defKillReset, false, -1, null, false, false, false, null,
TimeSpan.FromHours(0), null, false, null);
if (hasvendor)
{
// force vendor spawners to behave like the distro
spawner.SpawnRange = 0;
}
else
{
spawner.SpawnRange = spawnrange;
}
spawner.m_PlayerCreated = true;
string fromname = null;
if (from != null) fromname = from.Name;
spawner.LastModifiedBy = fromname;
spawner.FirstModifiedBy = fromname;
spawner.MoveToWorld(new Point3D(x, y, z), spawnmap);
if (spawner.Map == Map.Internal)
{
badspawnercount++;
spawner.Delete();
from.SendMessage("Invalid map at line {0}", linenumber);
from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber);
return;
}
spawnercount++;
// handle the special case of map 0 that also needs to do trammel
if (map == 0)
{
spawnmap = Map.Trammel;
// assign it a unique id
SpawnId = Guid.NewGuid();
// Create the new xml spawner
spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, totalmaxcount,
TimeSpan.FromMinutes(mindelay), TimeSpan.FromMinutes(maxdelay), TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1,
0, homerange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0),
TimeSpan.FromMinutes(0), null, null, null, null, null,
null, null, null, null, 1, null, false, defTODMode, defKillReset, false, -1, null, false, false, false, null,
TimeSpan.FromHours(0), null, false, null);
spawner.SpawnRange = spawnrange;
spawner.m_PlayerCreated = true;
spawner.LastModifiedBy = fromname;
spawner.FirstModifiedBy = fromname;
spawner.MoveToWorld(new Point3D(x, y, z), spawnmap);
if (spawner.Map == Map.Internal)
{
badspawnercount++;
spawner.Delete();
from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber);
return;
}
spawnercount++;
}
}
else
{
badspawnercount++;
from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber);
}
}
}
private static void ParseOldMapFormat(Mobile from, string filename, string line, string[] args, int linenumber, ref int spawnercount, ref int badspawnercount, ref int overridemap, ref double overridemintime, ref double overridemaxtime)
{
// format of each .map line is * Dragon:Wyvern 5209 965 -40 2 2 10 50 30 1
// * typename:typename:... x y z map mindelay maxdelay homerange spawnrange maxcount
// or
// * typename:typename:... x y z map mindelay maxdelay homerange spawnrange spawnid maxcount
// ## are comments
// overridemap mapnumber
// map 0 is tram+fel
// map 1 is fel
// map 2 is tram
// map 3 is ilsh
// map 4 is mal
// map 5 is tokuno
//
// * | typename:typename:... | | | | | | x | y | z | map | mindelay maxdelay homerange spawnrange spawnid maxcount | maxcount2 | maxcount2 | maxcount3 | maxcount4 | maxcount5
// the new format of each .map line is * |Dragon:Wyvern| spawns:spawns| | | | | 5209 | 965 | -40 | 2 | 2 | 10 | 50 | 30 | 1
if (args == null || from == null) return;
// look for the override keyword
if (args.Length == 2 && (args[0].ToLower() == "overridemap"))
{
try
{
overridemap = int.Parse(args[1]);
}
catch { }
}
else
if (args.Length == 2 && (args[0].ToLower() == "overridemintime"))
{
try
{
overridemintime = double.Parse(args[1]);
}
catch { }
}
else
if (args.Length == 2 && (args[0].ToLower() == "overridemaxtime"))
{
try
{
overridemaxtime = double.Parse(args[1]);
}
catch { }
}
else
// look for a spawn spec line
if (args.Length > 0 && (args[0] == "*"))
{
bool badspawn = false;
int x = 0;
int y = 0;
int z = 0;
int map = 0;
double mindelay = 0;
double maxdelay = 0;
int homerange = 0;
int spawnrange = 0;
int maxcount = 0;
int spawnid = 0;
string[] typenames = null;
if (args.Length != 11 && args.Length != 12)
{
badspawn = true;
from.SendMessage("Invalid arg count {1} at line {0}", linenumber, args.Length);
}
else
{
// get the list of spawns
typenames = args[1].Split(':');
// parse the rest of the args
if (args.Length == 11)
{
try
{
x = int.Parse(args[2]);
y = int.Parse(args[3]);
z = int.Parse(args[4]);
map = int.Parse(args[5]);
mindelay = double.Parse(args[6]);
maxdelay = double.Parse(args[7]);
homerange = int.Parse(args[8]);
spawnrange = int.Parse(args[9]);
maxcount = int.Parse(args[10]);
}
catch { from.SendMessage("Parsing error at line {0}", linenumber); badspawn = true; }
}
else
if (args.Length == 12)
{
try
{
x = int.Parse(args[2]);
y = int.Parse(args[3]);
z = int.Parse(args[4]);
map = int.Parse(args[5]);
mindelay = double.Parse(args[6]);
maxdelay = double.Parse(args[7]);
homerange = int.Parse(args[8]);
spawnrange = int.Parse(args[9]);
spawnid = int.Parse(args[10]);
maxcount = int.Parse(args[11]);
}
catch { from.SendMessage("Parsing error at line {0}", linenumber); badspawn = true; }
}
}
// apply mi/maxdelay overrides
if (overridemintime != -1)
{
mindelay = overridemintime;
}
if (overridemaxtime != -1)
{
maxdelay = overridemaxtime;
}
if (mindelay > maxdelay) maxdelay = mindelay;
if (!badspawn && typenames != null && typenames.Length > 0)
{
// everything seems ok so go ahead and make the spawner
// check for map override
if (overridemap >= 0) map = overridemap;
Map spawnmap = Map.Internal;
switch (map)
{
case 0:
spawnmap = Map.Felucca;
// note it also does trammel
break;
case 1:
spawnmap = Map.Felucca;
break;
case 2:
spawnmap = Map.Trammel;
break;
case 3:
spawnmap = Map.Ilshenar;
break;
case 4:
spawnmap = Map.Malas;
break;
case 5:
spawnmap = Map.Tokuno;
break;
}
if (!IsValidMapLocation(x, y, spawnmap))
{
// invalid so dont spawn it
badspawnercount++;
from.SendMessage("Invalid map/location at line {0}", linenumber);
from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber);
return;
}
// allow it to make an xmlspawner instead
// first add all of the creatures on the list
SpawnObject[] so = new SpawnObject[typenames.Length];
bool hasvendor = true;
for (int i = 0; i < typenames.Length; i++)
{
so[i] = new SpawnObject(typenames[i], maxcount);
// check the type to see if there are vendors on it
Type type = SpawnerType.GetType(typenames[i]);
// check for vendor-only spawners which get special spawnrange treatment
if (type != null && (type != typeof(BaseVendor) && !type.IsSubclassOf(typeof(BaseVendor))))
{
hasvendor = false;
}
}
// assign it a unique id
Guid SpawnId = Guid.NewGuid();
// and give it a name based on the spawner count and file
string spawnername = String.Format("{0}#{1}", Path.GetFileNameWithoutExtension(filename), spawnercount);
// Create the new xml spawner
XmlSpawner spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, maxcount,
TimeSpan.FromMinutes(mindelay), TimeSpan.FromMinutes(maxdelay), TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1,
0, homerange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0),
TimeSpan.FromMinutes(0), null, null, null, null, null,
null, null, null, null, 1, null, false, defTODMode, defKillReset, false, -1, null, false, false, false, null,
TimeSpan.FromHours(0), null, false, null);
if (hasvendor)
{
// force vendor spawners to behave like the distro
spawner.SpawnRange = 0;
}
else
{
spawner.SpawnRange = spawnrange;
}
spawner.m_PlayerCreated = true;
string fromname = null;
if (from != null) fromname = from.Name;
spawner.LastModifiedBy = fromname;
spawner.FirstModifiedBy = fromname;
spawner.MoveToWorld(new Point3D(x, y, z), spawnmap);
if (spawner.Map == Map.Internal)
{
badspawnercount++;
spawner.Delete();
from.SendMessage("Invalid map at line {0}", linenumber);
from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber);
return;
}
spawnercount++;
// handle the special case of map 0 that also needs to do trammel
if (map == 0)
{
spawnmap = Map.Trammel;
// assign it a unique id
SpawnId = Guid.NewGuid();
// Create the new xml spawner
spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, maxcount,
TimeSpan.FromMinutes(mindelay), TimeSpan.FromMinutes(maxdelay), TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1,
0, homerange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0),
TimeSpan.FromMinutes(0), null, null, null, null, null,
null, null, null, null, 1, null, false, defTODMode, defKillReset, false, -1, null, false, false, false, null,
TimeSpan.FromHours(0), null, false, null);
spawner.SpawnRange = spawnrange;
spawner.m_PlayerCreated = true;
spawner.LastModifiedBy = fromname;
spawner.FirstModifiedBy = fromname;
spawner.MoveToWorld(new Point3D(x, y, z), spawnmap);
if (spawner.Map == Map.Internal)
{
badspawnercount++;
spawner.Delete();
from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber);
return;
}
spawnercount++;
}
}
else
{
badspawnercount++;
from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber);
}
}
}
//------------------------------------------------------------------------------------------------------------------------------------
// The following code was taken from Sno's xml exporter package and slightly modified to create xmlspawners instead of regular spawners
//------------------------------------------------------------------------------------------------------------------------------------
[Usage("XmlImportSpawners filename")]
[Description("Loads xml files created by Sno's xml exporter as xmlspawners.")]
public static void XmlImportSpawners_OnCommand(CommandEventArgs e)
{
if (e.Arguments.Length >= 1)
{
string filename = e.GetString(0);
string filePath = Path.Combine("Saves/Spawners", filename);
if (File.Exists(filePath))
{
XmlDocument doc = new XmlDocument();
try
{
doc.Load(filePath);
}
catch
{
e.Mobile.SendMessage("unable to load file {0}.", filePath);
return;
}
XmlElement root = doc["spawners"];
int successes = 0, failures = 0;
if (root != null && root.GetElementsByTagName("spawner") != null)
{
foreach (XmlElement spawner in root.GetElementsByTagName("spawner"))
{
try
{
ImportSpawner(spawner, e.Mobile);
successes++;
}
catch (Exception ex) { e.Mobile.SendMessage(33, "{0} {1}", ex.Message, spawner.InnerText); failures++; }
}
}
e.Mobile.SendMessage("{0} spawners loaded successfully from {1}, {2} failures.", successes, filePath, failures);
}
else
e.Mobile.SendMessage("File {0} does not exist.", filePath);
}
else
e.Mobile.SendMessage("Usage: [XmlImportSpawners <filename>");
}
private static string GetText(XmlElement node, string defaultValue)
{
if (node == null)
return defaultValue;
return node.InnerText;
}
private static void ImportSpawner(XmlElement node, Mobile from)
{
int count = int.Parse(GetText(node["count"], "1"));
int homeRange = int.Parse(GetText(node["homerange"], "4"));
int walkingRange = int.Parse(GetText(node["walkingrange"], "-1"));
// width of the spawning area
int spawnwidth = homeRange * 2;
if (walkingRange >= 0) spawnwidth = walkingRange * 2;
int team = int.Parse(GetText(node["team"], "0"));
bool group = bool.Parse(GetText(node["group"], "False"));
TimeSpan maxDelay = TimeSpan.Parse(GetText(node["maxdelay"], "10:00"));
TimeSpan minDelay = TimeSpan.Parse(GetText(node["mindelay"], "05:00"));
List<string> creaturesName = LoadCreaturesName(node["creaturesname"]);
string name = GetText(node["name"], "Spawner");
Point3D location = Point3D.Parse(GetText(node["location"], "Error"));
Map map = Map.Parse(GetText(node["map"], "Error"));
// allow it to make an xmlspawner instead
// first add all of the creatures on the list
SpawnObject[] so = new SpawnObject[creaturesName.Count];
bool hasvendor = false;
for (int i = 0; i < creaturesName.Count; i++)
{
so[i] = new SpawnObject(creaturesName[i], count);
// check the type to see if there are vendors on it
Type type = SpawnerType.GetType(creaturesName[i]);
// if it has basevendors on it or invalid types, then skip it
if (type != null && (type == typeof(BaseVendor) || type.IsSubclassOf(typeof(BaseVendor))))
{
hasvendor = true;
}
}
// assign it a unique id
Guid SpawnId = Guid.NewGuid();
// Create the new xml spawner
XmlSpawner spawner = new XmlSpawner(SpawnId, location.X, location.Y, spawnwidth, spawnwidth, name, count,
minDelay, maxDelay, TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1,
team, homeRange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0),
TimeSpan.FromMinutes(0), null, null, null, null, null,
null, null, null, null, 1, null, group, defTODMode, defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null);
if (hasvendor)
{
spawner.SpawnRange = 0;
}
else
{
spawner.SpawnRange = homeRange;
}
spawner.m_PlayerCreated = true;
string fromname = null;
if (from != null) fromname = from.Name;
spawner.LastModifiedBy = fromname;
spawner.FirstModifiedBy = fromname;
spawner.MoveToWorld(location, map);
if (!IsValidMapLocation(location, spawner.Map))
{
spawner.Delete();
throw new Exception("Invalid spawner location.");
}
}
private static List<string> LoadCreaturesName(XmlElement node)
{
List<string> names = new List<string>();
if (node != null)
{
foreach (XmlElement ele in node.GetElementsByTagName("creaturename"))
{
if (ele != null)
names.Add(ele.InnerText);
}
}
return names;
}
//------------------------------------------------------------------------------------------------------------------------------------
// end of modified xml importer by Sno
//------------------------------------------------------------------------------------------------------------------------------------
[Usage("XmlImportMSF filename")]
[Description("Loads msf files created by Morxeton's megaspawner as xmlspawners.")]
public static void XmlImportMSF_OnCommand(CommandEventArgs e)
{
if (e.Arguments.Length >= 1)
{
/*
// I'm not sure what the default location for .msf files is
string filename = e.GetString( 0 );
string filePath = Path.Combine( "Data/Megaspawner", filename );
*/
string filePath = e.GetString(0);
if (File.Exists(filePath))
{
XmlDocument doc = new XmlDocument();
doc.Load(filePath);
XmlElement root = doc["MegaSpawners"];
if (root != null)
{
int successes = 0, failures = 0;
foreach (XmlElement spawner in root.GetElementsByTagName("MegaSpawner"))
{
try
{
ImportMegaSpawner(e.Mobile, spawner);
successes++;
}
catch (Exception ex) { e.Mobile.SendMessage(33, "{0} {1}", ex.Message, spawner.InnerText); failures++; }
}
e.Mobile.SendMessage("{0} megaspawners loaded successfully from {1}, {2} failures.", successes, filePath, failures);
}
else
{
e.Mobile.SendMessage("Invalid .msf file. No MegaSpawners node found");
}
}
else
e.Mobile.SendMessage("File {0} does not exist.", filePath);
}
else
e.Mobile.SendMessage("Usage: [XmlImportMSF <filename>");
}
private static void ImportMegaSpawner(Mobile from, XmlElement node)
{
string name = GetText(node["Name"], "MegaSpawner");
bool running = bool.Parse(GetText(node["Active"], "True"));
Point3D location = Point3D.Parse(GetText(node["Location"], "Error"));
Map map = Map.Parse(GetText(node["Map"], "Error"));
int team = 0;
bool group = false;
int maxcount = 0; // default maxcount of the spawner
int homeRange = 4; // default homerange
int spawnRange = 4; // default homerange
TimeSpan maxDelay = TimeSpan.FromMinutes(10);
TimeSpan minDelay = TimeSpan.FromMinutes(5);
XmlElement listnode = node["EntryLists"];
int nentries = 0;
SpawnObject[] so = null;
if (listnode != null)
{
// get the number of entries
if (listnode.HasAttributes)
{
XmlAttributeCollection attr = listnode.Attributes;
nentries = int.Parse(attr.GetNamedItem("count").Value);
}
if (nentries > 0)
{
so = new SpawnObject[nentries];
int entrycount = 0;
bool diff = false;
foreach (XmlElement entrynode in listnode.GetElementsByTagName("EntryList"))
{
// go through each entry and add a spawn object for it
if (entrynode != null)
{
if (entrycount == 0)
{
// get the spawner defaults from the first entry
// dont handle the individually specified entry attributes
group = bool.Parse(GetText(entrynode["GroupSpawn"], "False"));
maxDelay = TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MaxDelay"], "10:00")));
minDelay = TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MinDelay"], "05:00")));
homeRange = int.Parse(GetText(entrynode["WalkRange"], "10"));
spawnRange = int.Parse(GetText(entrynode["SpawnRange"], "4"));
}
else
{
// just check for consistency with other entries and report discrepancies
if (group != bool.Parse(GetText(entrynode["GroupSpawn"], "False")))
{
diff = true;
// log it
try
{
using (StreamWriter op = new StreamWriter("badimport.log", true))
{
op.WriteLine("MSFimport : individual group entry difference: {0} vs {1}",
GetText(entrynode["GroupSpawn"], "False"), group);
}
}
catch { }
}
if (minDelay != TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MinDelay"], "05:00"))))
{
diff = true;
// log it
try
{
using (StreamWriter op = new StreamWriter("badimport.log", true))
{
op.WriteLine("MSFimport : individual mindelay entry difference: {0} vs {1}",
GetText(entrynode["MinDelay"], "05:00"), minDelay);
}
}
catch { }
}
if (maxDelay != TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MaxDelay"], "10:00"))))
{
diff = true;
// log it
try
{
using (StreamWriter op = new StreamWriter("badimport.log", true))
{
op.WriteLine("MSFimport : individual maxdelay entry difference: {0} vs {1}",
GetText(entrynode["MaxDelay"], "10:00"), maxDelay);
}
}
catch { }
}
if (homeRange != int.Parse(GetText(entrynode["WalkRange"], "10")))
{
diff = true;
// log it
try
{
using (StreamWriter op = new StreamWriter("badimport.log", true))
{
op.WriteLine("MSFimport : individual homerange entry difference: {0} vs {1}",
GetText(entrynode["WalkRange"], "10"), homeRange);
}
}
catch { }
}
if (spawnRange != int.Parse(GetText(entrynode["SpawnRange"], "4")))
{
diff = true;
// log it
try
{
using (StreamWriter op = new StreamWriter("badimport.log", true))
{
op.WriteLine("MSFimport : individual spawnrange entry difference: {0} vs {1}",
GetText(entrynode["SpawnRange"], "4"), spawnRange);
}
}
catch { }
}
}
// these apply to individual entries
int amount = int.Parse(GetText(entrynode["Amount"], "1"));
string entryname = GetText(entrynode["EntryType"], "");
// keep track of the maxcount for the spawner by adding the individual amounts
maxcount += amount;
// add the creature entry
so[entrycount] = new SpawnObject(entryname, amount);
entrycount++;
if (entrycount > nentries)
{
// log it
try
{
using (StreamWriter op = new StreamWriter("badimport.log", true))
{
op.WriteLine("{0} MSFImport Error; inconsistent entry count {1} {2}", DateTime.UtcNow, location, map);
op.WriteLine();
}
}
catch { }
from.SendMessage("Inconsistent entry count detected at {0} {1}.", location, map);
break;
}
}
}
if (diff)
{
from.SendMessage("Individual entry setting detected at {0} {1}.", location, map);
// log it
try
{
using (StreamWriter op = new StreamWriter("badimport.log", true))
{
op.WriteLine("{0} MSFImport: Individual entry setting differences listed above from spawner at {1} {2}", DateTime.UtcNow, location, map);
op.WriteLine();
}
}
catch { }
}
}
}
// assign it a unique id
Guid SpawnId = Guid.NewGuid();
// Create the new xml spawner
XmlSpawner spawner = new XmlSpawner(SpawnId, location.X, location.Y, 0, 0, name, maxcount,
minDelay, maxDelay, TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1,
team, homeRange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0),
TimeSpan.FromMinutes(0), null, null, null, null, null,
null, null, null, null, 1, null, group, defTODMode, defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null);
spawner.SpawnRange = spawnRange;
spawner.m_PlayerCreated = true;
string fromname = null;
if (from != null) fromname = from.Name;
spawner.LastModifiedBy = fromname;
spawner.FirstModifiedBy = fromname;
// Try to find a valid Z height if required (Z == -999)
if (location.Z == -999)
{
int NewZ = map.GetAverageZ(location.X, location.Y);
if (map.CanFit(location.X, location.Y, NewZ, SpawnFitSize) == false)
{
for (int x = 1; x <= 39; x++)
{
if (map.CanFit(location.X, location.Y, NewZ + x, SpawnFitSize))
{
NewZ += x;
break;
}
}
}
location.Z = NewZ;
}
spawner.MoveToWorld(location, map);
if (!IsValidMapLocation(location, spawner.Map))
{
spawner.Delete();
throw new Exception("Invalid spawner location.");
}
}
public static void XmlLoadFromFile(string filename, string SpawnerPrefix, Mobile from, Point3D fromloc, Map frommap, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners)
{
processedmaps = 0;
processedspawners = 0;
int total_processed_maps = 0;
int total_processed_spawners = 0;
if (filename == null || filename.Length <= 0) return;
// Check if the file exists
if (System.IO.File.Exists(filename) == true)
{
FileStream fs = null;
try
{
fs = File.Open(filename, FileMode.Open, FileAccess.Read);
}
catch { }
if (fs == null)
{
if (from != null)
from.SendMessage("Unable to open {0} for loading", filename);
return;
}
// load the file
XmlLoadFromStream(fs, filename, SpawnerPrefix, from, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners);
}
else
// check to see if it is a directory
if (System.IO.Directory.Exists(filename) == true)
{
// if so then load all of the .xml files in the directory
string[] files = null;
try
{
files = Directory.GetFiles(filename, "*.xml");
}
catch { }
if (files != null && files.Length > 0)
{
if (from != null)
from.SendMessage("Loading {0} .xml files from directory {1}", files.Length, filename);
foreach (string file in files)
{
XmlLoadFromFile(file, SpawnerPrefix, from, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners);
total_processed_maps += processedmaps;
total_processed_spawners += processedspawners;
}
}
// recursively search subdirectories for more .xml files
string[] dirs = null;
try
{
dirs = Directory.GetDirectories(filename);
}
catch { }
if (dirs != null && dirs.Length > 0)
{
foreach (string dir in dirs)
{
XmlLoadFromFile(dir, SpawnerPrefix, from, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners);
total_processed_maps += processedmaps;
total_processed_spawners += processedspawners;
}
}
if (from != null)
from.SendMessage("Loaded a total of {0} .xml files and {2} spawners from directory {1}", total_processed_maps, filename, total_processed_spawners);
processedmaps = total_processed_maps;
processedspawners = total_processed_spawners;
}
else
{
if (from != null)
from.SendMessage("{0} does not exist", filename);
}
}
public static void XmlLoadFromFile(string filename, string SpawnerPrefix, Mobile from, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners)
{
processedmaps = 0;
processedspawners = 0;
if (from == null) return;
XmlLoadFromFile(filename, SpawnerPrefix, from, from.Location, from.Map, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners);
}
public static void XmlLoadFromFile(string filename, string SpawnerPrefix, Point3D fromloc, Map frommap, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners)
{
processedmaps = 0;
processedspawners = 0;
XmlLoadFromFile(filename, SpawnerPrefix, null, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners);
}
public static void XmlLoadFromFile(string filename, string SpawnerPrefix, bool loadnew, out int processedmaps, out int processedspawners)
{
processedmaps = 0;
processedspawners = 0;
XmlLoadFromFile(filename, SpawnerPrefix, null, Point3D.Zero, Map.Internal, false, 0, loadnew, out processedmaps, out processedspawners);
}
public static void XmlLoadFromStream(Stream fs, string filename, string SpawnerPrefix, Mobile from, Point3D fromloc, Map frommap, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners)
{
XmlLoadFromStream(fs, filename, SpawnerPrefix, from, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners, false);
}
public static void XmlLoadFromStream(Stream fs, string filename, string SpawnerPrefix, Mobile from, Point3D fromloc, Map frommap, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners, bool verbose)
{
processedmaps = 0;
processedspawners = 0;
if (fs == null) return;
// assign an id that will be used to distinguish the newly loaded spawners by appending it to their name
Guid newloadid = Guid.NewGuid();
int TotalCount = 0;
int TrammelCount = 0;
int FeluccaCount = 0;
int IlshenarCount = 0;
int MalasCount = 0;
int TokunoCount = 0;
int OtherCount = 0;
bool questionable_spawner = false;
bool bad_spawner = false;
int badcount = 0;
int questionablecount = 0;
int failedobjectitemcount = 0;
int failedsetitemcount = 0;
int relativex = -1;
int relativey = -1;
int relativez = 0;
Map relativemap = null;
if (from != null)
from.SendMessage(string.Format("Loading {0} objects{1} from file {2}.", "XmlSpawner",
((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty), filename));
// Create the data set
DataSet ds = new DataSet(SpawnDataSetName);
// Read in the file
bool fileerror = false;
try
{
ds.ReadXml(fs);
}
catch
{
if (from != null)
from.SendMessage(33, "Error reading xml file {0}", filename);
fileerror = true;
}
// close the file
fs.Close();
if (fileerror) return;
// Check that at least a single table was loaded
if (ds.Tables != null && ds.Tables.Count > 0)
{
// Add each spawn point to the current map
if (ds.Tables[SpawnTablePointName] != null && ds.Tables[SpawnTablePointName].Rows.Count > 0)
foreach (DataRow dr in ds.Tables[SpawnTablePointName].Rows)
{
// load in the spawner info. Certain fields are required and therefore cannot be ignored
// the exception handler for those will flag bad_spawner and the result will be logged
// Each row makes up a single spawner
string SpawnName = "Spawner";
try { SpawnName = (string)dr["Name"]; }
catch { questionable_spawner = true; }
if (loadnew)
{
// append the new id to the name
SpawnName = String.Format("{0}-{1}", SpawnName, newloadid);
}
// Check if there is any spawner name criteria specified on the load
if ((SpawnerPrefix == null) || (SpawnerPrefix.Length == 0) || (SpawnName.StartsWith(SpawnerPrefix) == true))
{
// Try load the GUID (might not work so create a new GUID)
Guid SpawnId = Guid.NewGuid();
if (!loadnew)
{
try { SpawnId = new Guid((string)dr["UniqueId"]); }
catch { }
}
else
{
// change the dataset guid to the newly created one when new loading
try
{
dr["UniqueId"] = SpawnId;
}
catch { Console.WriteLine("unable to set UniqueId"); }
}
int SpawnCentreX = fromloc.X;
int SpawnCentreY = fromloc.Y;
int SpawnCentreZ = fromloc.Z;
try { SpawnCentreX = int.Parse((string)dr["CentreX"]); }
catch { bad_spawner = true; }
try { SpawnCentreY = int.Parse((string)dr["CentreY"]); }
catch { bad_spawner = true; }
try { SpawnCentreZ = int.Parse((string)dr["CentreZ"]); }
catch { bad_spawner = true; }
int SpawnX = SpawnCentreX;
int SpawnY = SpawnCentreY;
int SpawnWidth = 0;
int SpawnHeight = 0;
try { SpawnX = int.Parse((string)dr["X"]); }
catch { questionable_spawner = true; }
try { SpawnY = int.Parse((string)dr["Y"]); }
catch { questionable_spawner = true; }
try { SpawnWidth = int.Parse((string)dr["Width"]); }
catch { questionable_spawner = true; }
try { SpawnHeight = int.Parse((string)dr["Height"]); }
catch { questionable_spawner = true; }
// Try load the InContainer (default to false)
bool InContainer = false;
int ContainerX = 0;
int ContainerY = 0;
int ContainerZ = 0;
try { InContainer = bool.Parse((string)dr["InContainer"]); }
catch { }
if (InContainer)
{
try { ContainerX = int.Parse((string)dr["ContainerX"]); }
catch { }
try { ContainerY = int.Parse((string)dr["ContainerY"]); }
catch { }
try { ContainerZ = int.Parse((string)dr["ContainerZ"]); }
catch { }
}
// Get the map (default to the mobiles map) if the relative distance is too great, then use the defined map
Map SpawnMap = frommap;
string XmlMapName = frommap.Name;
//if(!loadrelative && !loadnew)
{
// Try to get the "map" field, but in case it doesn't exist, catch and discard the exception
try { XmlMapName = (string)dr["Map"]; }
catch { questionable_spawner = true; }
// Convert the xml map value to a real map object
if (string.Compare(XmlMapName, Map.Trammel.Name, true) == 0 || XmlMapName == "Trammel")
{
SpawnMap = Map.Trammel;
TrammelCount++;
}
else if (string.Compare(XmlMapName, Map.Felucca.Name, true) == 0 || XmlMapName == "Felucca")
{
SpawnMap = Map.Felucca;
FeluccaCount++;
}
else if (string.Compare(XmlMapName, Map.Ilshenar.Name, true) == 0 || XmlMapName == "Ilshenar")
{
SpawnMap = Map.Ilshenar;
IlshenarCount++;
}
else if (string.Compare(XmlMapName, Map.Malas.Name, true) == 0 || XmlMapName == "Malas")
{
SpawnMap = Map.Malas;
MalasCount++;
}
else if (string.Compare(XmlMapName, Map.Tokuno.Name, true) == 0 || XmlMapName == "Tokuno")
{
SpawnMap = Map.Tokuno;
TokunoCount++;
}
else
{
try
{
SpawnMap = Map.Parse(XmlMapName);
}
catch { }
OtherCount++;
}
}
// test to see whether the distance between the relative center point and the spawner is too great. If so then dont do relative
if (relativex == -1 && relativey == -1)
{
// the first xml entry in the file will determine the origin
relativex = SpawnCentreX;
relativey = SpawnCentreY;
relativez = SpawnCentreZ;
// and also the relative map to relocate from
relativemap = SpawnMap;
}
int SpawnRelZ = 0;
int OrigZ = SpawnCentreZ;
if (loadrelative && (Math.Abs(relativex - SpawnCentreX) <= maxrange) && (Math.Abs(relativey - SpawnCentreY) <= maxrange)
&& (SpawnMap == relativemap))
{
// its within range so shift it
SpawnCentreX -= relativex - fromloc.X;
SpawnCentreY -= relativey - fromloc.Y;
SpawnX -= relativex - fromloc.X;
SpawnY -= relativey - fromloc.Y;
// force it to autosearch for Z when it places it but hold onto relative Z info just in case it can be placed there
SpawnRelZ = relativez - fromloc.Z;
SpawnCentreZ = short.MinValue;
}
// if relative loading has been specified, see if the loaded map is the same as the relativemap and relocate.
// if it doesnt match then just leave it
if (loadrelative && (relativemap == SpawnMap))
{
SpawnMap = frommap;
}
if (SpawnMap == Map.Internal) bad_spawner = true;
// Try load the IsRelativeHomeRange (default to true)
bool SpawnIsRelativeHomeRange = true;
try { SpawnIsRelativeHomeRange = bool.Parse((string)dr["IsHomeRangeRelative"]); }
catch { }
int SpawnHomeRange = 5;
try { SpawnHomeRange = int.Parse((string)dr["Range"]); }
catch { questionable_spawner = true; }
int SpawnMaxCount = 1;
try { SpawnMaxCount = int.Parse((string)dr["MaxCount"]); }
catch { questionable_spawner = true; }
//deal with double format for delay. default is the old minute format
bool delay_in_sec = false;
try { delay_in_sec = bool.Parse((string)dr["DelayInSec"]); }
catch { }
TimeSpan SpawnMinDelay = TimeSpan.FromMinutes(5);
TimeSpan SpawnMaxDelay = TimeSpan.FromMinutes(10);
if (delay_in_sec)
{
try { SpawnMinDelay = TimeSpan.FromSeconds(int.Parse((string)dr["MinDelay"])); }
catch { }
try { SpawnMaxDelay = TimeSpan.FromSeconds(int.Parse((string)dr["MaxDelay"])); }
catch { }
}
else
{
try { SpawnMinDelay = TimeSpan.FromMinutes(int.Parse((string)dr["MinDelay"])); }
catch { }
try { SpawnMaxDelay = TimeSpan.FromMinutes(int.Parse((string)dr["MaxDelay"])); }
catch { }
}
TimeSpan SpawnMinRefractory = TimeSpan.FromMinutes(0);
try { SpawnMinRefractory = TimeSpan.FromMinutes(double.Parse((string)dr["MinRefractory"])); }
catch { }
TimeSpan SpawnMaxRefractory = TimeSpan.FromMinutes(0);
try { SpawnMaxRefractory = TimeSpan.FromMinutes(double.Parse((string)dr["MaxRefractory"])); }
catch { }
TimeSpan SpawnTODStart = TimeSpan.FromMinutes(0);
try { SpawnTODStart = TimeSpan.FromMinutes(double.Parse((string)dr["TODStart"])); }
catch { }
TimeSpan SpawnTODEnd = TimeSpan.FromMinutes(0);
try { SpawnTODEnd = TimeSpan.FromMinutes(double.Parse((string)dr["TODEnd"])); }
catch { }
int todmode = (int)TODModeType.Realtime;
TODModeType SpawnTODMode = TODModeType.Realtime;
try { todmode = int.Parse((string)dr["TODMode"]); }
catch { }
switch ((int)todmode)
{
case (int)TODModeType.Gametime:
SpawnTODMode = TODModeType.Gametime;
break;
case (int)TODModeType.Realtime:
SpawnTODMode = TODModeType.Realtime;
break;
}
int SpawnKillReset = defKillReset;
try { SpawnKillReset = int.Parse((string)dr["KillReset"]); }
catch { }
string SpawnProximityMessage = null;
// proximity message
try { SpawnProximityMessage = (string)dr["ProximityTriggerMessage"]; }
catch { }
string SpawnItemTriggerName = null;
try { SpawnItemTriggerName = (string)dr["ItemTriggerName"]; }
catch { }
string SpawnNoItemTriggerName = null;
try { SpawnNoItemTriggerName = (string)dr["NoItemTriggerName"]; }
catch { }
string SpawnSpeechTrigger = null;
try { SpawnSpeechTrigger = (string)dr["SpeechTrigger"]; }
catch { }
string SpawnSkillTrigger = null;
try { SpawnSkillTrigger = (string)dr["SkillTrigger"]; }
catch { }
string SpawnMobTriggerName = null;
try { SpawnMobTriggerName = (string)dr["MobTriggerName"]; }
catch { }
string SpawnMobPropertyName = null;
try { SpawnMobPropertyName = (string)dr["MobPropertyName"]; }
catch { }
string SpawnPlayerPropertyName = null;
try { SpawnPlayerPropertyName = (string)dr["PlayerPropertyName"]; }
catch { }
double SpawnTriggerProbability = 1;
try { SpawnTriggerProbability = double.Parse((string)dr["TriggerProbability"]); }
catch { }
int SpawnSequentialSpawning = -1;
try { SpawnSequentialSpawning = int.Parse((string)dr["SequentialSpawning"]); }
catch { }
string SpawnRegionName = null;
try { SpawnRegionName = (string)dr["RegionName"]; }
catch { }
string SpawnConfigFile = null;
try { SpawnConfigFile = (string)dr["ConfigFile"]; }
catch { }
bool SpawnAllowGhost = false;
try { SpawnAllowGhost = bool.Parse((string)dr["AllowGhostTriggering"]); }
catch { }
bool SpawnAllowNPC = false;
try { SpawnAllowNPC = bool.Parse((string)dr["AllowNPCTriggering"]); }
catch { }
bool SpawnSpawnOnTrigger = false;
try { SpawnSpawnOnTrigger = bool.Parse((string)dr["SpawnOnTrigger"]); }
catch { }
bool SpawnSmartSpawning = false;
try { SpawnSmartSpawning = bool.Parse((string)dr["SmartSpawning"]); }
catch { }
bool TickReset = false;
try { TickReset = bool.Parse((string)dr["TickReset"]); }
catch { }
string SpawnObjectPropertyName = null;
try { SpawnObjectPropertyName = (string)dr["ObjectPropertyName"]; }
catch { }
// read in the object proximity target, this will be an object name, so have to do a search
// to find the item in the world. Also have to test for redundancy
string triggerObjectName = null;
try { triggerObjectName = (string)dr["ObjectPropertyItemName"]; }
catch { }
// read in the target for the set command, this will be an object name, so have to do a search
// to find the item in the world. Also have to test for redundancy
string setObjectName = null;
try { setObjectName = (string)dr["SetPropertyItemName"]; }
catch { }
// we will assign this during the self-reference resolution pass
Item SpawnSetPropertyItem = null;
// we will assign this during the self-reference resolution pass
Item SpawnObjectPropertyItem = null;
// read the duration parameter from the xml file
// but older files wont have it so deal with that condition and set it to the default of "0", i.e. infinite duration
// Try to get the "Duration" field, but in case it doesn't exist, catch and discard the exception
TimeSpan SpawnDuration = TimeSpan.FromMinutes(0);
try { SpawnDuration = TimeSpan.FromMinutes(double.Parse((string)dr["Duration"])); }
catch { }
TimeSpan SpawnDespawnTime = TimeSpan.FromHours(0);
try { SpawnDespawnTime = TimeSpan.FromHours(double.Parse((string)dr["DespawnTime"])); }
catch { }
int SpawnProximityRange = -1;
// Try to get the "ProximityRange" field, but in case it doesn't exist, catch and discard the exception
try { SpawnProximityRange = int.Parse((string)dr["ProximityRange"]); }
catch { }
int SpawnProximityTriggerSound = 0;
// Try to get the "ProximityTriggerSound" field, but in case it doesn't exist, catch and discard the exception
try { SpawnProximityTriggerSound = int.Parse((string)dr["ProximityTriggerSound"]); }
catch { }
int SpawnAmount = 1;
try { SpawnAmount = int.Parse((string)dr["Amount"]); }
catch { }
bool SpawnExternalTriggering = false;
try { SpawnExternalTriggering = bool.Parse((string)dr["ExternalTriggering"]); }
catch { }
string waypointstr = null;
try { waypointstr = (string)dr["Waypoint"]; }
catch { }
WayPoint SpawnWaypoint = GetWaypoint(waypointstr);
int SpawnTeam = 0;
try { SpawnTeam = int.Parse((string)dr["Team"]); }
catch { questionable_spawner = true; }
bool SpawnIsGroup = false;
try { SpawnIsGroup = bool.Parse((string)dr["IsGroup"]); }
catch { questionable_spawner = true; }
bool SpawnIsRunning = false;
try { SpawnIsRunning = bool.Parse((string)dr["IsRunning"]); }
catch { questionable_spawner = true; }
// try loading the new spawn specifications first
SpawnObject[] Spawns = new SpawnObject[0];
bool havenew = true;
try { Spawns = SpawnObject.LoadSpawnObjectsFromString2((string)dr["Objects2"]); }
catch { havenew = false; }
if (!havenew)
{
// try loading the new spawn specifications
try { Spawns = SpawnObject.LoadSpawnObjectsFromString((string)dr["Objects"]); }
catch { questionable_spawner = true; }
// can only have one of these defined
}
// do a check on the location of the spawner
if (!IsValidMapLocation(SpawnCentreX, SpawnCentreY, SpawnMap))
{
if (from != null)
from.SendMessage(33, "Invalid location '{0}' at [{1} {2}] in {3}",
SpawnName, SpawnCentreX, SpawnCentreY, XmlMapName);
bad_spawner = true;
}
// Check if this spawner already exists
XmlSpawner OldSpawner = null;
bool found_container = false;
bool found_spawner = false;
Container spawn_container = null;
if (!bad_spawner)
{
foreach (Item i in World.Items.Values)
{
if (i is XmlSpawner)
{
XmlSpawner CheckXmlSpawner = (XmlSpawner)i;
// Check if the spawners GUID is the same as the one being loaded
// and that the spawners map is the same as the one being loaded
if ((CheckXmlSpawner.UniqueId == SpawnId.ToString())
/* && ( CheckXmlSpawner.Map == SpawnMap || loadrelative)*/ )
{
OldSpawner = (XmlSpawner)i;
found_spawner = true;
}
}
//look for containers with the spawn coordinates if the incontainer flag is set
if (InContainer && !found_container && (i is Container) && (SpawnCentreX == i.Location.X) && (SpawnCentreY == i.Location.Y) &&
(SpawnCentreZ == i.Location.Z || SpawnCentreZ == short.MinValue))
{
// assume this is the container that the spawner was in
found_container = true;
spawn_container = i as Container;
}
// ok we can break if we have handled both the spawner and any containers
if (found_spawner && (found_container || !InContainer))
break;
}
}
// test to see whether the spawner specification was valid, bad, or questionable
if (bad_spawner)
{
badcount++;
if (from != null)
from.SendMessage(33, "Invalid spawner");
// log it
long fileposition = -1;
try { fileposition = fs.Position; }
catch { }
try
{
using (StreamWriter op = new StreamWriter("badxml.log", true))
{
op.WriteLine("# Invalid spawner : {0}: Fileposition {1} {2}", DateTime.UtcNow, fileposition, filename);
op.WriteLine();
}
}
catch { }
}
else
if (questionable_spawner)
{
questionablecount++;
if (from != null)
from.SendMessage(33, "Questionable spawner '{0}' at [{1} {2}] in {3}",
SpawnName, SpawnCentreX, SpawnCentreY, XmlMapName);
// log it
long fileposition = -1;
try { fileposition = fs.Position; }
catch { }
try
{
using (StreamWriter op = new StreamWriter("badxml.log", true))
{
op.WriteLine("# Questionable spawner : {0}: Format: X Y Z Map SpawnerName Fileposition Xmlfile", DateTime.UtcNow);
op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", SpawnCentreX, SpawnCentreY, SpawnCentreZ, XmlMapName, SpawnName, fileposition, filename);
op.WriteLine();
}
}
catch { }
}
if (!bad_spawner)
{
// Delete the old spawner if it exists
if (OldSpawner != null)
OldSpawner.Delete();
// Create the new spawner
XmlSpawner TheSpawn = new XmlSpawner(SpawnId, SpawnX, SpawnY, SpawnWidth, SpawnHeight, SpawnName, SpawnMaxCount,
SpawnMinDelay, SpawnMaxDelay, SpawnDuration, SpawnProximityRange, SpawnProximityTriggerSound, SpawnAmount,
SpawnTeam, SpawnHomeRange, SpawnIsRelativeHomeRange, Spawns, SpawnMinRefractory, SpawnMaxRefractory, SpawnTODStart,
SpawnTODEnd, SpawnObjectPropertyItem, SpawnObjectPropertyName, SpawnProximityMessage, SpawnItemTriggerName, SpawnNoItemTriggerName,
SpawnSpeechTrigger, SpawnMobTriggerName, SpawnMobPropertyName, SpawnPlayerPropertyName, SpawnTriggerProbability,
SpawnSetPropertyItem, SpawnIsGroup, SpawnTODMode, SpawnKillReset, SpawnExternalTriggering, SpawnSequentialSpawning,
SpawnRegionName, SpawnAllowGhost, SpawnAllowNPC, SpawnSpawnOnTrigger, SpawnConfigFile, SpawnDespawnTime, SpawnSkillTrigger, SpawnSmartSpawning, SpawnWaypoint);
TheSpawn.m_DisableGlobalAutoReset=TickReset;
//TheSpawn.Group = SpawnIsGroup;\
string fromname = null;
if (from != null) fromname = from.Name;
TheSpawn.LastModifiedBy = fromname;
TheSpawn.FirstModifiedBy = fromname;
// Try to find a valid Z height if required (SpawnCentreZ = short.MinValue)
int NewZ = 0;
// Check if relative loading is set. If so then try loading at the z-offset position first with no surface requirement, then try auto
/*if(loadrelative && SpawnMap.CanFit( SpawnCentreX, SpawnCentreY, OrigZ - SpawnRelZ, SpawnFitSize,true, false,false )) */
if (loadrelative && HasTileSurface(SpawnMap, SpawnCentreX, SpawnCentreY, OrigZ - SpawnRelZ))
{
NewZ = OrigZ - SpawnRelZ;
}
else
if (SpawnCentreZ == short.MinValue)
{
NewZ = SpawnMap.GetAverageZ(SpawnCentreX, SpawnCentreY);
if (SpawnMap.CanFit(SpawnCentreX, SpawnCentreY, NewZ, SpawnFitSize) == false)
{
for (int x = 1; x <= 39; x++)
{
if (SpawnMap.CanFit(SpawnCentreX, SpawnCentreY, NewZ + x, SpawnFitSize))
{
NewZ += x;
break;
}
}
}
}
else
{
// This spawn point already has a defined Z location, so use it
NewZ = SpawnCentreZ;
}
// if this is a container held spawner, drop it in the container
if (found_container && (spawn_container != null) && !spawn_container.Deleted)
{
TheSpawn.Location = (new Point3D(ContainerX, ContainerY, ContainerZ));
spawn_container.AddItem(TheSpawn);
}
else
{
// disable the X_Y adjustments in OnLocationChange
IgnoreLocationChange = true;
TheSpawn.MoveToWorld(new Point3D(SpawnCentreX, SpawnCentreY, NewZ), SpawnMap);
}
// reset the spawner
TheSpawn.Reset();
TheSpawn.Running = SpawnIsRunning;
// update subgroup-specific next spawn times
TheSpawn.NextSpawn = TimeSpan.Zero;
TheSpawn.ResetNextSpawnTimes();
// Send a message to the client that the spawner is created
if (from != null && verbose)
from.SendMessage(188, "Created '{0}' in {1} at {2}", TheSpawn.Name, TheSpawn.Map.Name, TheSpawn.Location.ToString());
// Do a total respawn
//TheSpawn.Respawn();
// Increment the count
TotalCount++;
}
bad_spawner = false;
questionable_spawner = false;
}
}
if (from != null)
from.SendMessage("Resolving spawner self references");
if (ds.Tables[SpawnTablePointName] != null && ds.Tables[SpawnTablePointName].Rows.Count > 0)
foreach (DataRow dr in ds.Tables[SpawnTablePointName].Rows)
{
// Try load the GUID
bool badid = false;
Guid SpawnId = Guid.NewGuid();
try { SpawnId = new Guid((string)dr["UniqueId"]); }
catch { badid = true; }
if (badid) continue;
// Get the map
Map SpawnMap = frommap;
string XmlMapName = frommap.Name;
if (!loadrelative)
{
try { XmlMapName = (string)dr["Map"]; }
catch { }
// Convert the xml map value to a real map object
try
{
SpawnMap = Map.Parse(XmlMapName);
}
catch { }
}
bool found_spawner = false;
XmlSpawner OldSpawner = null;
foreach (Item i in World.Items.Values)
{
if (i is XmlSpawner)
{
XmlSpawner CheckXmlSpawner = (XmlSpawner)i;
// Check if the spawners GUID is the same as the one being loaded
// and that the spawners map is the same as the one being loaded
if ((CheckXmlSpawner.UniqueId == SpawnId.ToString())
/* && ( CheckXmlSpawner.Map == SpawnMap || loadrelative) */)
{
OldSpawner = (XmlSpawner)i;
found_spawner = true;
}
}
if (found_spawner)
break;
}
if (found_spawner && OldSpawner != null && !OldSpawner.Deleted)
{
// resolve item name references since they may have referred to spawners that were just created
string setObjectName = null;
try { setObjectName = (string)dr["SetPropertyItemName"]; }
catch { }
if (setObjectName != null && setObjectName.Length > 0)
{
// try to parse out the type information if it has also been saved
string[] typeargs = setObjectName.Split(",".ToCharArray(), 2);
string typestr = null;
string namestr = setObjectName;
if (typeargs.Length > 1)
{
namestr = typeargs[0];
typestr = typeargs[1];
}
// if this is a new load then assume that it will be referring to another newly loaded object so append the newloadid
if (loadnew)
{
string tmpsetObjectName = String.Format("{0}-{1}", namestr, newloadid);
OldSpawner.m_SetPropertyItem = BaseXmlSpawner.FindItemByName(null, tmpsetObjectName, typestr);
}
// if this fails then try the original
if (OldSpawner.m_SetPropertyItem == null)
{
OldSpawner.m_SetPropertyItem = BaseXmlSpawner.FindItemByName(null, namestr, typestr);
}
if (OldSpawner.m_SetPropertyItem == null)
{
failedsetitemcount++;
if (from != null)
from.SendMessage(33, "Failed to initialize SetItemProperty Object '{0}' on ' '{1}' at [{2} {3}] in {4}",
setObjectName, OldSpawner.Name, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Map);
// log it
try
{
using (StreamWriter op = new StreamWriter("badxml.log", true))
{
op.WriteLine("# Failed SetItemProperty Object initialization : {0}: Format: ObjectName X Y Z Map SpawnerName Xmlfile",
DateTime.UtcNow);
op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}",
setObjectName, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Location.Z, OldSpawner.Map, OldSpawner.Name, filename);
op.WriteLine();
}
}
catch { }
}
}
string triggerObjectName = null;
try { triggerObjectName = (string)dr["ObjectPropertyItemName"]; }
catch { }
if (triggerObjectName != null && triggerObjectName.Length > 0)
{
string[] typeargs = triggerObjectName.Split(",".ToCharArray(), 2);
string typestr = null;
string namestr = triggerObjectName;
if (typeargs.Length > 1)
{
namestr = typeargs[0];
typestr = typeargs[1];
}
// if this is a new load then assume that it will be referring to another newly loaded object so append the newloadid
if (loadnew)
{
string tmptriggerObjectName = String.Format("{0}-{1}", namestr, newloadid);
OldSpawner.m_ObjectPropertyItem = BaseXmlSpawner.FindItemByName(null, tmptriggerObjectName, typestr);
}
// if this fails then try the original
if (OldSpawner.m_ObjectPropertyItem == null)
{
OldSpawner.m_ObjectPropertyItem = BaseXmlSpawner.FindItemByName(null, namestr, typestr);
}
if (OldSpawner.m_ObjectPropertyItem == null)
{
failedobjectitemcount++;
if (from != null)
from.SendMessage(33, "Failed to initialize TriggerObject '{0}' on ' '{1}' at [{2} {3}] in {4}",
triggerObjectName, OldSpawner.Name, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Map);
// log it
try
{
using (StreamWriter op = new StreamWriter("badxml.log", true))
{
op.WriteLine("# Failed TriggerObject initialization : {0}: Format: ObjectName X Y Z Map SpawnerName Xmlfile",
DateTime.UtcNow);
op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}",
triggerObjectName, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Location.Z, OldSpawner.Map, OldSpawner.Name, filename);
op.WriteLine();
}
}
catch { }
}
}
}
}
}
// close the file
try
{
fs.Close();
}
catch { }
if (from != null)
from.SendMessage("{0} spawner(s) were created from file {1} [Trammel={2}, Felucca={3}, Ilshenar={4}, Malas={5}, Tokuno={6} Other={7}].",
TotalCount, filename, TrammelCount, FeluccaCount, IlshenarCount, MalasCount, TokunoCount, OtherCount);
if (failedobjectitemcount > 0)
{
if (from != null)
from.SendMessage(33, "Failed to initialize TriggerObjects in {0} spawners. Saved to 'badxml.log'", failedobjectitemcount);
}
if (failedsetitemcount > 0)
{
if (from != null)
from.SendMessage(33, "Failed to initialize SetItemProperty Objects in {0} spawners. Saved to 'badxml.log'", failedsetitemcount);
}
if (badcount > 0)
{
if (from != null)
from.SendMessage(33, "{0} bad spawners detected. Saved to 'badxml.log'", badcount);
}
if (questionablecount > 0)
{
if (from != null)
from.SendMessage(33, "{0} questionable spawners detected. Saved to 'badxml.log'", questionablecount);
}
processedmaps = 1;
processedspawners = TotalCount;
}
public static string LocateFile(string filename)
{
bool found = false;
string dirname = null;
if (System.IO.Directory.Exists(XmlSpawnDir) == true)
{
// get it from the defaults directory if it exists
dirname = String.Format("{0}/{1}", XmlSpawnDir, filename);
found = System.IO.File.Exists(dirname) || System.IO.Directory.Exists(dirname);
}
if (!found)
{
// otherwise just get it from the main installation dir
dirname = filename;
}
return dirname;
}
public static string LocateMultiFile(string filename)
{
bool found = false;
string dirname = null;
if (System.IO.Directory.Exists(XmlMultiDir) == true)
{
// get it from the defaults directory if it exists
dirname = String.Format("{0}/{1}", XmlMultiDir, filename);
found = System.IO.File.Exists(dirname) || System.IO.Directory.Exists(dirname);
}
if (!found)
{
// otherwise just get it from the main installation dir
dirname = filename;
}
return dirname;
}
[Usage("XmlNewLoad <SpawnFile or directory> [SpawnerPrefixFilter]")]
[Description("Loads new XmlSpawner objects with new GUIDs (no replacement) into the current map of the player.")]
public static void NewLoad_OnCommand(CommandEventArgs e)
{
if (e.Mobile.AccessLevel >= DiskAccessLevel)
{
if (e.Arguments.Length >= 1)
{
string filename = LocateFile(e.Arguments[0].ToString());
// Spawner load criteria (if any)
string SpawnerPrefix = string.Empty;
// Check if there is an argument provided (load criteria)
if (e.Arguments.Length > 1)
SpawnerPrefix = e.Arguments[1];
int processedmaps;
int processedspawners;
XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, false, 0, true, out processedmaps, out processedspawners);
}
else
e.Mobile.SendMessage("Usage: {0} <SpawnFile or directory> [SpawnerPrefixFilter]", e.Command);
}
else
e.Mobile.SendMessage("You do not have rights to perform this command.");
}
[Usage("XmlLoad <SpawnFile or directory> [SpawnerPrefixFilter]")]
[Description("Loads XmlSpawner objects (replacing existing spawners with matching GUIDs) into the proper map as defined in the file supplied.")]
public static void Load_OnCommand(CommandEventArgs e)
{
if (e.Mobile.AccessLevel >= DiskAccessLevel)
{
if (e.Arguments.Length >= 1)
{
string filename = LocateFile(e.Arguments[0].ToString());
// Spawner load criteria (if any)
string SpawnerPrefix = string.Empty;
// Check if there is an argument provided (load criteria)
if (e.Arguments.Length > 1)
SpawnerPrefix = e.Arguments[1];
int processedmaps;
int processedspawners;
XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, false, 0, false, out processedmaps, out processedspawners);
}
else
e.Mobile.SendMessage("Usage: {0} <SpawnFile or directory> [SpawnerPrefixFilter]", e.Command);
}
else
e.Mobile.SendMessage("You do not have rights to perform this command.");
}
[Usage("XmlNewLoadHere <SpawnFile or directory> [SpawnerPrefixFilter][-maxrange range]")]
[Description("Loads new XmlSpawner objects with new GUIDs (no replacement) to the current map and location of the player. Spawners beyond maxrange (default=48 tiles) are not moved relative to the player")]
public static void NewLoadHere_OnCommand(CommandEventArgs e)
{
if (e.Mobile.AccessLevel >= DiskAccessLevel)
{
if (e.Arguments.Length >= 1)
{
string filename = LocateFile(e.Arguments[0].ToString());
// Spawner load criteria (if any)
string SpawnerPrefix = string.Empty;
bool badargs = false;
int maxrange = 48;
// Check if there is an argument provided (load criteria)
try
{
// Check if there is an argument provided (load criteria)
for (int nxtarg = 1; nxtarg < e.Arguments.Length; nxtarg++)
{
// is it a maxrange option?
if (e.Arguments[nxtarg].ToLower() == "-maxrange")
{
maxrange = int.Parse(e.Arguments[++nxtarg]);
}
else
{
SpawnerPrefix = e.Arguments[nxtarg];
}
}
}
catch { e.Mobile.SendMessage("Usage: {0} <SpawnFile or directory> [SpawnerPrefixFilter][-maxrange range]", e.Command); badargs = true; }
if (!badargs)
{
int processedmaps;
int processedspawners;
XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, true, maxrange, true, out processedmaps, out processedspawners);
}
}
else
e.Mobile.SendMessage("Usage: {0} <SpawnFile or directory> [SpawnerPrefixFilter][-maxrange range]", e.Command);
}
else
e.Mobile.SendMessage("You do not have rights to perform this command.");
}
[Usage("XmlLoadHere <SpawnFile or directory> [SpawnerPrefixFilter][-maxrange range]")]
[Description("Loads XmlSpawner objects to the current map and location of the player. Spawners beyond maxrange (default=48 tiles) are not moved relative to the player")]
public static void LoadHere_OnCommand(CommandEventArgs e)
{
if (e.Mobile.AccessLevel >= DiskAccessLevel)
{
if (e.Arguments.Length >= 1)
{
string filename = LocateFile(e.Arguments[0].ToString());
// Spawner load criteria (if any)
string SpawnerPrefix = string.Empty;
bool badargs = false;
int maxrange = 48;
try
{
// Check if there is an argument provided (load criteria)
for (int nxtarg = 1; nxtarg < e.Arguments.Length; nxtarg++)
{
// is it a maxrange option?
if (e.Arguments[nxtarg].ToLower() == "-maxrange")
{
maxrange = int.Parse(e.Arguments[++nxtarg]);
}
else
{
SpawnerPrefix = e.Arguments[nxtarg];
}
}
}
catch { e.Mobile.SendMessage("Usage: {0} <SpawnFile or directory> [SpawnerPrefixFilter][-maxrange range]", e.Command); badargs = true; }
if (!badargs)
{
int processedmaps;
int processedspawners;
XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, true, maxrange, false, out processedmaps, out processedspawners);
}
}
else
e.Mobile.SendMessage("Usage: {0} <SpawnFile or directory> [SpawnerPrefixFilter][-maxrange range]", e.Command);
}
else
e.Mobile.SendMessage("You do not have rights to perform this command.");
}
[Usage("XmlSaveOld <SpawnFile> [SpawnerPrefixFilter]")]
[Description("Saves all XmlSpawner objects from the current map into the file supplied in the old xmlspawner format.")]
public static void SaveOld_OnCommand(CommandEventArgs e)
{
SaveSpawns(e, false, true);
}
[Usage("XmlSpawnerSave <SpawnFile> [SpawnerPrefixFilter]")]
[Description("Saves all XmlSpawner objects from the current map into the file supplied.")]
public static void Save_OnCommand(CommandEventArgs e)
{
SaveSpawns(e, false, false);
}
[Usage("XmlSpawnerSaveAll <SpawnFile> [SpawnerPrefixFilter]")]
[Description("Saves ALL XmlSpawner objects from the entire world into the file supplied.")]
public static void SaveAll_OnCommand(CommandEventArgs e)
{
SaveSpawns(e, true, false);
}
public class XmlSaveSingle : BaseCommand
{
public XmlSaveSingle()
{
AccessLevel = DiskAccessLevel;
Supports = CommandSupport.Single;
Commands = new string[]{ "XmlSaveSingle" };
ObjectTypes = ObjectTypes.Items;
Usage = "XmlSaveSingle <filename>";
Description = "Saves single xmlspawner to specified file.";
}
public override void Execute( CommandEventArgs e, object obj )
{
if (e == null || e.Mobile == null || e.Arguments == null) return;
if (e.Arguments.Length < 1)
{
e.Mobile.SendMessage("Usage: {0} <SpawnFile> (without spaces!!)", e.Command);
return;
}
string filename = e.Arguments[0].ToString();
XmlSpawner xmlspawner = obj as XmlSpawner;
if(xmlspawner==null)
{
e.Mobile.SendMessage("You can select only XmlSpawner objects!");
return;
}
Mobile m = e.Mobile;
CommandLogging.WriteLine( m, "{0} {1} Saving XmlSpawner {2} on file {3}", m.AccessLevel, CommandLogging.Format( m ), CommandLogging.Format(xmlspawner), CommandLogging.Format(filename) );
SaveSpawns(m, xmlspawner, filename);
}
}
private static void SaveSpawns(Mobile m, XmlSpawner xmlspawner, string filename)
{
if (m.AccessLevel < DiskAccessLevel)
{
m.SendMessage("You do not have rights to perform this command.");
return;
}
string dirname;
if (System.IO.Directory.Exists(XmlSpawner.XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\"))
{
// put it in the defaults directory if it exists
dirname = String.Format("{0}/{1}", XmlSpawnDir, filename);
}
else
{
// otherwise just put it in the main installation dir
dirname = filename;
}
m.SendMessage("Saving object in folder {0} - file {1} - spawner {2}.", dirname, filename, xmlspawner);
List<XmlSpawner> saveslist = new List<XmlSpawner>(1);
saveslist.Add(xmlspawner);
SaveSpawnList(m, saveslist, dirname, false, true);
}
private static void SaveSpawns(CommandEventArgs e, bool SaveAllMaps, bool oldformat)
{
if (e == null || e.Mobile == null || e.Arguments == null || e.Arguments.Length < 1) return;
if (e.Mobile.AccessLevel < DiskAccessLevel)
{
e.Mobile.SendMessage("You do not have rights to perform this command.");
return;
}
if (e.Arguments != null && e.Arguments.Length < 1)
{
e.Mobile.SendMessage("Usage: {0} <SpawnFile> [SpawnerPrefixFilter]", e.Command);
return;
}
// Spawner save criteria (if any)
string SpawnerPrefix = string.Empty;
// Check if there is an argument provided (save criteria)
if (e.Arguments.Length > 1)
SpawnerPrefix = e.Arguments[1];
string filename = e.Arguments[0].ToString();
string dirname;
if (System.IO.Directory.Exists(XmlSpawner.XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\"))
{
// put it in the defaults directory if it exists
dirname = String.Format("{0}/{1}", XmlSpawnDir, filename);
}
else
{
// otherwise just put it in the main installation dir
dirname = filename;
}
if (SaveAllMaps == true)
e.Mobile.SendMessage(string.Format("Saving {0} objects{1} to file {2} from {3}.", "XmlSpawner",
((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty), dirname, e.Mobile.Map));
else
e.Mobile.SendMessage(string.Format("Saving {0} obejcts{1} to file {2} from the entire world.", "XmlSpawner",
((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty), dirname));
List<XmlSpawner> saveslist = new List<XmlSpawner>();
// Add each spawn point to the list
foreach (Item i in World.Items.Values)
{
if (i is XmlSpawner && !i.Deleted && ((SaveAllMaps == true) || (i.Map == e.Mobile.Map))
//check for mob carried spawners and ignore them
&& !(i.RootParent is Mobile)
&& (SpawnerPrefix == null || (SpawnerPrefix.Length == 0) || (i.Name != null && i.Name.StartsWith(SpawnerPrefix))))
{
saveslist.Add((XmlSpawner)i);
}
}
// save the list
SaveSpawnList(e.Mobile, saveslist, dirname, oldformat, true);
}
public static bool SaveSpawnList(List<XmlSpawner> savelist, Stream stream)
{
return SaveSpawnList(null, savelist, null, stream, false, false);
}
public static bool SaveSpawnList(Mobile from, List<XmlSpawner> savelist, string dirname, bool oldformat, bool verbose)
{
if (dirname == null || dirname.Length == 0) return false;
bool save_ok = true;
System.IO.FileStream fs = null;
try
{
// Create the FileStream to write with.
fs = new System.IO.FileStream(dirname, System.IO.FileMode.Create);
}
catch
{
if (from != null)
from.SendMessage("Error creating file {0}", dirname);
save_ok = false;
}
// so far so good
if (save_ok)
{
save_ok = SaveSpawnList(from, savelist, dirname, fs, oldformat, verbose);
}
if (!save_ok && from != null)
{
from.SendMessage("Unable to complete save operation.");
}
return save_ok;
}
public static bool SaveSpawnList(Mobile from, List<XmlSpawner> savelist, string dirname, Stream stream, bool oldformat, bool verbose)
{
if (savelist == null || stream == null) return false;
int TotalCount = 0;
int TrammelCount = 0;
int FeluccaCount = 0;
int IlshenarCount = 0;
int MalasCount = 0;
int TokunoCount = 0;
int OtherCount = 0;
// Create the data set
DataSet ds = new DataSet(SpawnDataSetName);
// Load the data set up
ds.Tables.Add(SpawnTablePointName);
// Create spawn point schema
ds.Tables[SpawnTablePointName].Columns.Add("Name");
ds.Tables[SpawnTablePointName].Columns.Add("UniqueId");
ds.Tables[SpawnTablePointName].Columns.Add("Map");
ds.Tables[SpawnTablePointName].Columns.Add("X");
ds.Tables[SpawnTablePointName].Columns.Add("Y");
ds.Tables[SpawnTablePointName].Columns.Add("Width");
ds.Tables[SpawnTablePointName].Columns.Add("Height");
ds.Tables[SpawnTablePointName].Columns.Add("CentreX");
ds.Tables[SpawnTablePointName].Columns.Add("CentreY");
ds.Tables[SpawnTablePointName].Columns.Add("CentreZ");
ds.Tables[SpawnTablePointName].Columns.Add("Range");
ds.Tables[SpawnTablePointName].Columns.Add("MaxCount");
ds.Tables[SpawnTablePointName].Columns.Add("MinDelay");
ds.Tables[SpawnTablePointName].Columns.Add("MaxDelay");
// deal with the double format for delay. old format stored them as minutes in int format. that meant that short delays were lost
// proper solution would simply be to store as doubles, but older progs still assume int format (like spawneditor)
// so this is the solution. add a flag and do it both ways.
ds.Tables[SpawnTablePointName].Columns.Add("DelayInSec");
// add the duration and proximity range and sound parameters, and in container flag and coords inside the container
ds.Tables[SpawnTablePointName].Columns.Add("Duration");
ds.Tables[SpawnTablePointName].Columns.Add("DespawnTime");
ds.Tables[SpawnTablePointName].Columns.Add("ProximityRange");
ds.Tables[SpawnTablePointName].Columns.Add("ProximityTriggerSound");
ds.Tables[SpawnTablePointName].Columns.Add("ProximityTriggerMessage");
ds.Tables[SpawnTablePointName].Columns.Add("ObjectPropertyName");
ds.Tables[SpawnTablePointName].Columns.Add("ObjectPropertyItemName");
ds.Tables[SpawnTablePointName].Columns.Add("SetPropertyItemName");
ds.Tables[SpawnTablePointName].Columns.Add("ItemTriggerName");
ds.Tables[SpawnTablePointName].Columns.Add("NoItemTriggerName");
ds.Tables[SpawnTablePointName].Columns.Add("MobTriggerName");
ds.Tables[SpawnTablePointName].Columns.Add("MobPropertyName");
ds.Tables[SpawnTablePointName].Columns.Add("PlayerPropertyName");
ds.Tables[SpawnTablePointName].Columns.Add("TriggerProbability");
ds.Tables[SpawnTablePointName].Columns.Add("SpeechTrigger");
ds.Tables[SpawnTablePointName].Columns.Add("SkillTrigger");
ds.Tables[SpawnTablePointName].Columns.Add("InContainer");
ds.Tables[SpawnTablePointName].Columns.Add("ContainerX");
ds.Tables[SpawnTablePointName].Columns.Add("ContainerY");
ds.Tables[SpawnTablePointName].Columns.Add("ContainerZ");
ds.Tables[SpawnTablePointName].Columns.Add("MinRefractory");
ds.Tables[SpawnTablePointName].Columns.Add("MaxRefractory");
ds.Tables[SpawnTablePointName].Columns.Add("TODStart");
ds.Tables[SpawnTablePointName].Columns.Add("TODEnd");
ds.Tables[SpawnTablePointName].Columns.Add("TODMode");
ds.Tables[SpawnTablePointName].Columns.Add("KillReset");
ds.Tables[SpawnTablePointName].Columns.Add("ExternalTriggering");
ds.Tables[SpawnTablePointName].Columns.Add("SequentialSpawning");
ds.Tables[SpawnTablePointName].Columns.Add("RegionName");
ds.Tables[SpawnTablePointName].Columns.Add("AllowGhostTriggering");
ds.Tables[SpawnTablePointName].Columns.Add("AllowNPCTriggering");
ds.Tables[SpawnTablePointName].Columns.Add("SpawnOnTrigger");
ds.Tables[SpawnTablePointName].Columns.Add("ConfigFile");
ds.Tables[SpawnTablePointName].Columns.Add("SmartSpawning");
ds.Tables[SpawnTablePointName].Columns.Add("TickReset");
ds.Tables[SpawnTablePointName].Columns.Add("WayPoint");
ds.Tables[SpawnTablePointName].Columns.Add("Team");
// amount for stacked item spawns
ds.Tables[SpawnTablePointName].Columns.Add("Amount");
ds.Tables[SpawnTablePointName].Columns.Add("IsGroup");
ds.Tables[SpawnTablePointName].Columns.Add("IsRunning");
ds.Tables[SpawnTablePointName].Columns.Add("IsHomeRangeRelative");
if (oldformat)
{
ds.Tables[SpawnTablePointName].Columns.Add("Objects");
}
else
{
ds.Tables[SpawnTablePointName].Columns.Add("Objects2");
}
// Always export sorted by UUID to help diffs
savelist.Sort((a, b) =>
{
return a.UniqueId.CompareTo(b.UniqueId);
});
// Add each spawn point to the new table
foreach (XmlSpawner sp in savelist)
{
if (sp == null || sp.Map == null || sp.Deleted)
continue;
if (verbose && from != null)
// Send a message to the client that the spawner is being saved
from.SendMessage(68, "Saving '{0}' in {1} at {2}", sp.Name, sp.Map.Name, sp.Location.ToString());
// Create a new data row
DataRow dr = ds.Tables[SpawnTablePointName].NewRow();
// Populate the data
dr["Name"] = (string)sp.Name;
// Set the unqiue id
dr["UniqueId"] = (string)sp.m_UniqueId;
// Get the map name
dr["Map"] = (string)sp.Map.Name;
// Convert the xml map value to a real map object
if (string.Compare(sp.Map.Name, Map.Trammel.Name, true) == 0)
TrammelCount++;
else if (string.Compare(sp.Map.Name, Map.Felucca.Name, true) == 0)
FeluccaCount++;
else if (string.Compare(sp.Map.Name, Map.Ilshenar.Name, true) == 0)
IlshenarCount++;
else if (string.Compare(sp.Map.Name, Map.Malas.Name, true) == 0)
MalasCount++;
else if (string.Compare(sp.Map.Name, Map.Tokuno.Name, true) == 0)
TokunoCount++;
else
OtherCount++;
dr["X"] = (int)sp.m_X;
dr["Y"] = (int)sp.m_Y;
dr["Width"] = (int)sp.m_Width;
dr["Height"] = (int)sp.m_Height;
// check to see if this is in a container
if (sp.RootParent is Container)
{
dr["CentreX"] = (int)(((Container)(sp.RootParent)).Location.X);
dr["CentreY"] = (int)(((Container)(sp.RootParent)).Location.Y);
dr["CentreZ"] = (int)(((Container)(sp.RootParent)).Location.Z);
dr["ContainerX"] = (int)(sp.Location.X);
dr["ContainerY"] = (int)(sp.Location.Y);
dr["ContainerZ"] = (int)(sp.Location.Z);
dr["InContainer"] = true;
}
else
{
dr["CentreX"] = (int)sp.Location.X;
dr["CentreY"] = (int)sp.Location.Y;
dr["CentreZ"] = (int)sp.Location.Z;
//dr["ContainerX"] = 0;
//dr["ContainerY"] = 0;
//dr["ContainerZ"] = 0;
dr["InContainer"] = false;
}
dr["Range"] = (int)sp.m_HomeRange;
dr["MaxCount"] = (int)sp.m_Count;
// need to deal with the fact that the old xmlspawner xml format only saved delays in minutes as ints, so shorter spawn times
// are lost
// flag it then on reading it can be properly handled and still
// maintain backward compatibility with older xml files
if (((int)sp.m_MinDelay.TotalSeconds - 60 * (int)sp.m_MinDelay.TotalMinutes) > 0 ||
((int)sp.m_MaxDelay.TotalSeconds - 60 * (int)sp.m_MaxDelay.TotalMinutes) > 0)
{
dr["DelayInSec"] = true;
dr["MinDelay"] = (int)sp.m_MinDelay.TotalSeconds;
dr["MaxDelay"] = (int)sp.m_MaxDelay.TotalSeconds;
}
else
{
dr["DelayInSec"] = false;
dr["MinDelay"] = (int)sp.m_MinDelay.TotalMinutes;
dr["MaxDelay"] = (int)sp.m_MaxDelay.TotalMinutes;
}
// additional parameters
dr["TODStart"] = (double)sp.m_TODStart.TotalMinutes;
dr["TODEnd"] = (double)sp.m_TODEnd.TotalMinutes;
dr["TODMode"] = (int)sp.m_TODMode;
dr["KillReset"] = (int)sp.m_KillReset;
dr["MinRefractory"] = (double)sp.m_MinRefractory.TotalMinutes;
dr["MaxRefractory"] = (double)sp.m_MaxRefractory.TotalMinutes;
dr["Duration"] = (double)sp.m_Duration.TotalMinutes;
dr["DespawnTime"] = (double)sp.m_DespawnTime.TotalHours;
dr["ExternalTriggering"] = (bool)sp.m_ExternalTriggering;
dr["ProximityRange"] = (int)sp.m_ProximityRange;
dr["ProximityTriggerSound"] = (int)sp.m_ProximityTriggerSound;
dr["ProximityTriggerMessage"] = sp.m_ProximityTriggerMessage;
if (sp.m_ObjectPropertyItem != null && !sp.m_ObjectPropertyItem.Deleted)
dr["ObjectPropertyItemName"] = String.Format("{0},{1}", sp.m_ObjectPropertyItem.Name,
sp.m_ObjectPropertyItem.GetType().Name);
else
dr["ObjectPropertyItemName"] = null;
dr["ObjectPropertyName"] = sp.m_ObjectPropertyName;
if (sp.m_SetPropertyItem != null && !sp.m_SetPropertyItem.Deleted)
dr["SetPropertyItemName"] = String.Format("{0},{1}", sp.m_SetPropertyItem.Name,
sp.m_SetPropertyItem.GetType().Name);
else
dr["SetPropertyItemName"] = null;
dr["ItemTriggerName"] = sp.m_ItemTriggerName;
dr["NoItemTriggerName"] = sp.m_NoItemTriggerName;
dr["MobTriggerName"] = sp.m_MobTriggerName;
dr["MobPropertyName"] = sp.m_MobPropertyName;
dr["PlayerPropertyName"] = sp.m_PlayerPropertyName;
dr["TriggerProbability"] = sp.m_TriggerProbability;
dr["SequentialSpawning"] = sp.m_SequentialSpawning;
dr["RegionName"] = sp.m_RegionName;
dr["AllowGhostTriggering"] = sp.m_AllowGhostTriggering;
dr["AllowNPCTriggering"] = sp.m_AllowNPCTriggering;
dr["SpawnOnTrigger"] = sp.m_SpawnOnTrigger;
dr["ConfigFile"] = sp.m_ConfigFile;
dr["SmartSpawning"] = sp.m_SmartSpawning;
dr["TickReset"] = sp.m_DisableGlobalAutoReset;
dr["SpeechTrigger"] = sp.m_SpeechTrigger;
dr["SkillTrigger"] = sp.m_SkillTrigger;
dr["Amount"] = (int)sp.m_StackAmount;
dr["Team"] = (int)sp.m_Team;
// assign the waypoint based on the waypoint name if it deviates from the default waypoint name, otherwise do it by serial
string waystr = null;
if (sp.m_WayPoint != null)
{
if ((sp.m_WayPoint.Name != defwaypointname) && (sp.m_WayPoint.Name != null) && (sp.m_WayPoint.Name.Length > 0))
{
waystr = sp.m_WayPoint.Name;
}
else
{
waystr = String.Format("SERIAL,{0}", sp.m_WayPoint.Serial);
}
}
dr["WayPoint"] = waystr;
dr["IsGroup"] = (bool)sp.m_Group;
dr["IsRunning"] = (bool)sp.m_Running;
dr["IsHomeRangeRelative"] = (bool)sp.m_HomeRangeIsRelative;
if (oldformat)
{
dr["Objects"] = (string)sp.GetSerializedObjectList();
}
else
{
dr["Objects2"] = (string)sp.GetSerializedObjectList2();
}
// Add the row the the table
ds.Tables[SpawnTablePointName].Rows.Add(dr);
// Increment the count
TotalCount++;
}
// Write out the file
bool file_error = false;
if (TotalCount > 0)
{
try
{
ds.WriteXml(stream);
}
catch { file_error = true; }
if (file_error)
{
return false;
}
}
try
{
stream.Close();
}
catch { }
// Indicate how many spawners were written
if (from != null)
{
from.SendMessage("{0} spawner(s) were saved to file {1} [Trammel={2}, Felucca={3}, Ilshenar={4}, Malas={5}, Tokuno={6}, Other={7}].",
TotalCount, dirname, TrammelCount, FeluccaCount, IlshenarCount, MalasCount, TokunoCount, OtherCount);
}
return true;
}
private static void WipeSpawners(CommandEventArgs e, bool WipeAll)
{
if (e == null || e.Mobile == null) return;
if (e.Mobile.AccessLevel >= AccessLevel.Administrator)
{
// Spawner delete criteria (if any)
string SpawnerPrefix = string.Empty;
// Check if there is an argument provided (delete criteria)
if (e.Arguments != null && e.Arguments.Length > 0)
SpawnerPrefix = e.Arguments[0];
if (WipeAll == true)
e.Mobile.SendMessage("Removing ALL XmlSpawner objects from the world{0}.", ((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty));
else
e.Mobile.SendMessage("Removing ALL XmlSpawner objects from {0}{1}.", e.Mobile.Map, ((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty));
// Delete Xml spawner's in the world based on the mobiles current map
int Count = 0;
List<Item> ToDelete = new List<Item>();
foreach (Item i in World.Items.Values)
{
if ((i is XmlSpawner) && (WipeAll == true || i.Map == e.Mobile.Map) && (i.Deleted == false))
{
// Check if there is a delete condition
if (SpawnerPrefix == null || (SpawnerPrefix.Length == 0) || (i.Name.StartsWith(SpawnerPrefix)))
{
// Send a message to the client that the spawner is being deleted
//e.Mobile.SendMessage(33, "Removing '{0}' in {1} at {2}", i.Name, i.Map.Name, i.Location.ToString());
ToDelete.Add(i);
Count++;
}
}
}
// Delete the items in the array list
foreach (Item i in ToDelete)
i.Delete();
if (WipeAll == true)
e.Mobile.SendMessage("Removed {0} XmlSpawner objects from the world.", Count);
else
e.Mobile.SendMessage("Removed {0} XmlSpawner objects from {1}.", Count, e.Mobile.Map);
}
else
e.Mobile.SendMessage("You do not have rights to perform this command.");
}
[Usage("XmlSpawnerRespawn [SpawnerPrefixFilter]")]
[Description("Respawns all XmlSpawner objects from the current map.")]
public static void Respawn_OnCommand(CommandEventArgs e)
{
RespawnSpawners(e, false);
}
[Usage("XmlSpawnerRespawnAll [SpawnerPrefixFilter]")]
[Description("Respawns all XmlSpawner objects from the entire world.")]
public static void RespawnAll_OnCommand(CommandEventArgs e)
{
RespawnSpawners(e, true);
}
private static void RespawnSpawners(CommandEventArgs e, bool RespawnAll)
{
if (e == null || e.Mobile == null) return;
if (e.Mobile.AccessLevel >= AccessLevel.Administrator)
{
// Spawner Respawn criteria (if any)
string SpawnerPrefix = string.Empty;
// Check if there is an argument provided (respawn criteria)
if (e.Arguments != null && e.Arguments.Length > 0)
SpawnerPrefix = e.Arguments[0];
if (RespawnAll == true)
e.Mobile.SendMessage("Respawning ALL XmlSpawner objects from the world{0}.", ((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty));
else
e.Mobile.SendMessage("Respawning ALL XmlSpawner objects from {0}{1}.", e.Mobile.Map, ((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty));
// Respawn Xml spawner's in the world based on the mobiles current map
int Count = 0;
List<Item> ToRespawn = new List<Item>();
foreach (Item i in World.Items.Values)
{
try
{
if ((i is XmlSpawner) && (RespawnAll == true || i.Map == e.Mobile.Map) && (i.Deleted == false))
{
// Check if there is a respawn condition
if ((SpawnerPrefix == null) || (SpawnerPrefix.Length == 0) || (i.Name != null && i.Name.StartsWith(SpawnerPrefix)))
{
ToRespawn.Add(i);
Count++;
}
}
}
catch (Exception ex) { Console.WriteLine("Error attempting to add {0}, {1}", i, ex.Message); }
}
// Respawn the items in the array list
foreach (Item i in ToRespawn)
{
// Send a message to the client that the spawner is being respawned
e.Mobile.SendMessage(33, "Respawning '{0}' in {1} at {2}", i.Name, i.Map.Name, i.Location.ToString());
XmlSpawner CheckXmlSpawner = (XmlSpawner)i;
CheckXmlSpawner.Respawn();
}
if (RespawnAll == true)
e.Mobile.SendMessage("Respawned {0} XmlSpawner objects from the world.", Count);
else
e.Mobile.SendMessage("Respawned {0} XmlSpawner objects from {1}.", Count, e.Mobile.Map);
}
else
e.Mobile.SendMessage("You do not have rights to perform this command.");
}
#if(TRACE)
public static void XmlMake_OnCommand( CommandEventArgs e )
{
if( e.Arguments.Length > 0 ){
int count = 0;
try{
count = Convert.ToInt32( e.Arguments[0],10);
} catch{}
for(int i=0;i<count;i++)
{
if( e.Arguments.Length > 2)
{
Spawner x = new Spawner(10,1,1,0,2,e.Arguments[1]);
x.Location = new Point3D(5400+Utility.Random(700),1090+Utility.Random(180),0);
x.Map = Map.Trammel;
} else
if( e.Arguments.Length > 1)
{
XmlSpawner x = new XmlSpawner(10,1,1,0,2,e.Arguments[1]);
x.Location = new Point3D(5400+Utility.Random(700),1090+Utility.Random(180),0);
x.Map = Map.Trammel;
//x.MinDelay = TimeSpan.FromSeconds(1);
//x.MaxDelay = TimeSpan.FromSeconds(1);
//x.ProximityRange = 0;
}
}
if( e.Arguments.Length > 2)
{
e.Mobile.SendMessage( "Created {0} Spawner objects.", count );
} else {
e.Mobile.SendMessage( "Created {0} XmlSpawner objects.", count );
}
}
}
public static void XmlTrace_OnCommand( )
{
XmlTrace_OnCommand( null );
}
public static void XmlTrace_OnCommand( CommandEventArgs e )
{
Process currentprocess = Process.GetCurrentProcess();
TimeSpan runningtime = DateTime.UtcNow - XmlSpawner._traceStartTime;
double processtime = currentprocess.UserProcessorTime.TotalMilliseconds - _startProcessTime;
double sysload = 0;
if(runningtime.TotalMilliseconds > 0)
{
sysload = processtime/runningtime.TotalMilliseconds;
}
Console.WriteLine( "______________");
Console.WriteLine( "Active Traces:");
Console.WriteLine( "Running Time = {0}",runningtime);
Console.WriteLine( "Adjusted Process Time = {0:####.####} secs",processtime/1000);
Console.WriteLine( "Processor Time = {0} ({1:p3} avg sys load)",currentprocess.UserProcessorTime,sysload);
for(int i=0;i<MaxTraces;i++)
{
if( XmlSpawner._traceCount[i] > 0)
{
double load = 0;
if(processtime > 0)
{
load = ((double)XmlSpawner._traceTotal[i].TotalMilliseconds)/processtime;
}
Console.WriteLine( "{0} ({4}) {1,21} / {2} calls = {3:####.####} ms/call, {5:p3}",
i,XmlSpawner._traceTotal[i], XmlSpawner._traceCount[i],((double)XmlSpawner._traceTotal[i].TotalMilliseconds)/XmlSpawner._traceCount[i],
XmlSpawner._traceName[i], load);
}
}
}
public static void XmlResetTrace_OnCommand( CommandEventArgs e )
{
if( e.Arguments.Length >= 0 )
{
for(int i=0;i<MaxTraces;i++)
{
XmlSpawner._traceCount[i] = 0;
XmlSpawner._traceTotal[i] = TimeSpan.Zero;
}
XmlSpawner._traceStartTime = DateTime.UtcNow;
Process currentprocess = Process.GetCurrentProcess();
_startProcessTime = currentprocess.UserProcessorTime.TotalMilliseconds;
Console.WriteLine( "Traces reset");
}
}
#endif
#endregion
#region Constructors
[Constructable]
public XmlSpawner()
: base(BaseItemId)
{
m_PlayerCreated = true;
m_UniqueId = Guid.NewGuid().ToString();
SpawnRange = defSpawnRange;
InitSpawn(0, 0, m_Width, m_Height, string.Empty, 0, defMinDelay, defMaxDelay, defDuration,
defProximityRange, defProximityTriggerSound, defAmount, defTeam, defHomeRange, defRelativeHome, new SpawnObject[0], defMinRefractory, defMaxRefractory,
defTODStart, defTODEnd, null, null, null, null, null, null, null, null, null, defTriggerProbability, null, defIsGroup, defTODMode,
defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null);
}
[Constructable]
public XmlSpawner(int amount, int minDelay, int maxDelay, int team, int homeRange, string creatureName)
: base(BaseItemId)
{
m_PlayerCreated = true;
m_UniqueId = Guid.NewGuid().ToString();
SpawnRange = homeRange;
SpawnObject[] so = new SpawnObject[1];
so[0] = new SpawnObject(creatureName, amount);
InitSpawn(0, 0, m_Width, m_Height, string.Empty, amount, TimeSpan.FromMinutes(minDelay), TimeSpan.FromMinutes(maxDelay), defDuration,
defProximityRange, defProximityTriggerSound, defAmount, team, homeRange, defRelativeHome, so, defMinRefractory, defMaxRefractory,
defTODStart, defTODEnd, null, null, null, null, null, null, null, null, null, defTriggerProbability, null, defIsGroup, defTODMode,
defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null);
}
[Constructable]
public XmlSpawner(int amount, int minDelay, int maxDelay, int team, int homeRange, int spawnRange, string creatureName)
: base(BaseItemId)
{
m_PlayerCreated = true;
m_UniqueId = Guid.NewGuid().ToString();
SpawnRange = spawnRange;
SpawnObject[] so = new SpawnObject[1];
so[0] = new SpawnObject(creatureName, amount);
InitSpawn(0, 0, m_Width, m_Height, string.Empty, amount, TimeSpan.FromMinutes(minDelay), TimeSpan.FromMinutes(maxDelay), defDuration,
defProximityRange, defProximityTriggerSound, defAmount, team, homeRange, defRelativeHome, so, defMinRefractory, defMaxRefractory,
defTODStart, defTODEnd, null, null, null, null, null, null, null, null, null, defTriggerProbability, null, defIsGroup, defTODMode,
defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null);
}
[Constructable]
public XmlSpawner(string creatureName)
: base(BaseItemId)
{
m_PlayerCreated = true;
m_UniqueId = Guid.NewGuid().ToString();
SpawnObject[] so = new SpawnObject[1];
so[0] = new SpawnObject(creatureName, 1);
SpawnRange = defSpawnRange;
InitSpawn(0, 0, m_Width, m_Height, string.Empty, 1, defMinDelay, defMaxDelay, defDuration,
defProximityRange, defProximityTriggerSound, defAmount, defTeam, defHomeRange, defRelativeHome, so, defMinRefractory, defMaxRefractory,
defTODStart, defTODEnd, null, null, null, null, null, null, null, null, null, defTriggerProbability, null, defIsGroup, defTODMode,
defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null);
}
public XmlSpawner(Guid uniqueId, int x, int y, int width, int height, string name, int maxCount, TimeSpan minDelay, TimeSpan maxDelay, TimeSpan duration,
int proximityRange, int proximityTriggerSound, int amount, int team, int homeRange, bool isRelativeHomeRange, SpawnObject[] spawnObjects,
TimeSpan minRefractory, TimeSpan maxRefractory, TimeSpan todstart, TimeSpan todend, Item objectPropertyItem, string objectPropertyName, string proximityMessage,
string itemTriggerName, string noitemTriggerName, string speechTrigger, string mobTriggerName, string mobPropertyName, string playerPropertyName, double triggerProbability,
Item setPropertyItem, bool isGroup, TODModeType todMode, int killReset, bool externalTriggering, int sequentialSpawning, string regionName,
bool allowghost, bool allownpc, bool spawnontrigger, string configfile, TimeSpan despawnTime, string skillTrigger, bool smartSpawning, WayPoint wayPoint)
: base(BaseItemId)
{
m_UniqueId = uniqueId.ToString();
InitSpawn(x, y, width, height, name, maxCount, minDelay, maxDelay, duration,
proximityRange, proximityTriggerSound, amount, team, homeRange, isRelativeHomeRange, spawnObjects, minRefractory, maxRefractory, todstart, todend,
objectPropertyItem, objectPropertyName, proximityMessage, itemTriggerName, noitemTriggerName, speechTrigger, mobTriggerName, mobPropertyName, playerPropertyName,
triggerProbability, setPropertyItem, isGroup, todMode, killReset, externalTriggering, sequentialSpawning, regionName, allowghost, allownpc, spawnontrigger, configfile,
despawnTime, skillTrigger, smartSpawning, wayPoint);
}
public void InitSpawn(int x, int y, int width, int height, string name, int maxCount, TimeSpan minDelay, TimeSpan maxDelay, TimeSpan duration,
int proximityRange, int proximityTriggerSound, int amount, int team, int homeRange, bool isRelativeHomeRange, SpawnObject[] objectsToSpawn,
TimeSpan minRefractory, TimeSpan maxRefractory, TimeSpan todstart, TimeSpan todend, Item objectPropertyItem, string objectPropertyName, string proximityMessage,
string itemTriggerName, string noitemTriggerName, string speechTrigger, string mobTriggerName, string mobPropertyName, string playerPropertyName, double triggerProbability,
Item setPropertyItem, bool isGroup, TODModeType todMode, int killReset, bool externalTriggering, int sequentialSpawning, string regionName, bool allowghost, bool allownpc, bool spawnontrigger,
string configfile, TimeSpan despawnTime, string skillTrigger, bool smartSpawning, WayPoint wayPoint)
{
Visible = false;
Movable = false;
m_X = x;
m_Y = y;
m_Width = width;
m_Height = height;
// init spawn range if compatible
if (width == height)
m_SpawnRange = width / 2;
else
m_SpawnRange = -1;
m_Running = true;
m_Group = isGroup;
if ((name != null) && (name.Length > 0))
Name = name;
else
Name = "Spawner";
m_MinDelay = minDelay;
m_MaxDelay = maxDelay;
// duration and proximity range parameter
m_MinRefractory = minRefractory;
m_MaxRefractory = maxRefractory;
m_TODStart = todstart;
m_TODEnd = todend;
m_TODMode = todMode;
m_KillReset = killReset;
m_Duration = duration;
m_DespawnTime = despawnTime;
m_ProximityRange = proximityRange;
m_ProximityTriggerSound = proximityTriggerSound;
m_proximityActivated = false;
m_durActivated = false;
m_refractActivated = false;
m_Count = maxCount;
m_Team = team;
m_StackAmount = amount;
m_HomeRange = homeRange;
m_HomeRangeIsRelative = isRelativeHomeRange;
m_ObjectPropertyItem = objectPropertyItem;
m_ObjectPropertyName = objectPropertyName;
m_ProximityTriggerMessage = proximityMessage;
m_ItemTriggerName = itemTriggerName;
m_NoItemTriggerName = noitemTriggerName;
m_SpeechTrigger = speechTrigger;
SkillTrigger = skillTrigger; // note this will register the skill as well
m_MobTriggerName = mobTriggerName;
m_MobPropertyName = mobPropertyName;
m_PlayerPropertyName = playerPropertyName;
m_TriggerProbability = triggerProbability;
m_SetPropertyItem = setPropertyItem;
m_ExternalTriggering = externalTriggering;
m_ExternalTrigger = false;
m_SequentialSpawning = sequentialSpawning;
RegionName = regionName;
m_AllowGhostTriggering = allowghost;
m_AllowNPCTriggering = allownpc;
m_SpawnOnTrigger = spawnontrigger;
m_SmartSpawning = smartSpawning;
ConfigFile = configfile;
m_WayPoint = wayPoint;
// set the totalitem property to -1 so that it doesnt show up in the item count of containers
//TotalItems = -1;
//UpdateTotal(this, TotalType.Items, -1);
// Create the array of spawned objects
m_SpawnObjects = new List<XmlSpawner.SpawnObject>();
// Assign the list of objects to spawn
SpawnObjects = objectsToSpawn;
// Kick off the process
DoTimer(TimeSpan.FromSeconds(1));
}
public XmlSpawner(Serial serial)
: base(serial)
{
}
#endregion
#region Defrag methods
public void Defrag(bool killtest)
{
if (m_SpawnObjects == null) return;
bool removed = false;
int total_removed = 0;
List<Item> deleteilist = new List<Item>();
List<Mobile> deletemlist = new List<Mobile>();
foreach (SpawnObject so in m_SpawnObjects)
{
for (int x = 0; x < so.SpawnedObjects.Count; x++)
{
object o = so.SpawnedObjects[x];
if (o is Item)
{
Item item = (Item)o;
bool despawned = false;
// check to see if the despawn time has elapsed. If so, then delete it if it hasnt been picked up or stolen.
if (DespawnTime.TotalHours > 0 && !item.Deleted && (item.LastMoved < DateTime.UtcNow - DespawnTime) && (item.Parent == this.Parent)
&& (!ItemFlags.GetTaken(item) || (item.Parent != null && (item.Parent == this.Parent)))) // can despawn if just moved within the same container
{
//item.Delete();
deleteilist.Add(item);
despawned = true;
}
// Check if the items has been deleted or
// if something else now owns the item (picked it up for example)
// also check the stolen/placed in container flag. If any of those are true then the spawner doesnt own it any more so take it off the list.
// the stolen/container flag prevents spawns from being left on the list when players take them and lock them back down on the ground.
// If you have made the changes to stealing.cs and container.cs described in xmlspawner2.txt then just uncomment the line below to
// enable this check
if (item.Deleted || despawned || (item.Parent != this.Parent) // different container
|| (ItemFlags.GetTaken(item) && (item.Parent == null || (item.Parent != this.Parent)))) // taken and in the world, or a different container
{
so.SpawnedObjects.Remove(o);
x--;
removed = true;
// if sequential spawning is active and the RestrictKillsToSubgroup flag is set, then check to see if
// the object is in the current subgroup before adding to the total
if (SequentialSpawn >= 0 && so.RestrictKillsToSubgroup)
{
if (so.SubGroup == SequentialSpawn)
total_removed++;
}
else
{
// just add it
total_removed++;
}
}
}
else if (o is Mobile)
{
Mobile m = (Mobile)o;
// check to see if the spawn has been idle for a long time
// if it has then reposition it because it might be in an inaccessible location
// note, vendors and special cases of positioning from the Spawn method will not get relocated
// i'm not saying I like those special cases, but they should be treated consistently
// doesnt work properly under RunUO 2.0 and also doesnt properly take spawn control keywords into consideration
// when repositioning, so disable this for now
/*
if (SpawnIdleTime > 0 && !m.Deleted && !(m is BaseVendor) && (m.CreationTime < DateTime.UtcNow - TimeSpan.FromHours(SpawnIdleTime))
&& m.Map != null && m.Map != Map.Internal && !m.Map.GetSector(m.Location).Active)
{
// determine whether the requiresurface flag is set
m.Location = GetSpawnPosition(so.RequireSurface, m);
// and reset the creation time (simulates respawning the identical mob at a new location)
//m.CreationTime = DateTime.UtcNow;
}
* */
bool despawned = false;
// check to see if the despawn time has elapsed. If so, and the sector is not active then delete it.
if (DespawnTime.TotalHours > 0 && !m.Deleted && (m.CreationTime < DateTime.UtcNow - DespawnTime)
&& m.Map != null && m.Map != Map.Internal && !m.Map.GetSector(m.Location).Active)
{
//m.Delete();
deletemlist.Add(m);
despawned = true;
}
if (m.Deleted || despawned)
{
// Remove the delete mobile from the list
so.SpawnedObjects.Remove(o);
x--;
removed = true;
// if sequential spawning is active and the RestrictKillsToSubgroup flag is set, then check to see if
// the object is in the current subgroup before adding to the total
if (SequentialSpawn >= 0 && so.RestrictKillsToSubgroup)
{
if (so.SubGroup == SequentialSpawn)
total_removed++;
}
else
{
// just add it
total_removed++;
}
}
else if (m is BaseCreature)
{
BaseCreature b = (BaseCreature)m;
// Check if the creature has been tamed or previously tamed and released
// and if it is, remove it from the list of spawns
if (b.Controlled || b.IsStabled || (b.Owners != null && b.Owners.Count > 0))
{
so.SpawnedObjects.Remove(o);
x--;
removed = true;
// if sequential spawning is active and the RestrictKillsToSubgroup flag is set, then check to see if
// the object is in the current subgroup before adding to the total
if (SequentialSpawn >= 0 && so.RestrictKillsToSubgroup)
{
if (so.SubGroup == SequentialSpawn)
total_removed++;
}
else
{
// just add it
total_removed++;
}
}
}
}
else
if (o is BaseXmlSpawner.KeywordTag)
{
BaseXmlSpawner.KeywordTag tag = (BaseXmlSpawner.KeywordTag)o;
if (tag.Deleted)
{
so.SpawnedObjects.Remove(o);
x--;
removed = true;
}
}
else
{
// Don't know what this is, so remove it
Console.WriteLine("removing unknown {0} from spawnlist", so);
so.SpawnedObjects.Remove(o);
x--;
removed = true;
}
}
}
DeleteFromList(deleteilist, deletemlist);
// Check if anything has been removed
if (removed == true)
InvalidateProperties();
// increment the killcount based upon the number of items that were removed from the spawnlist (i.e. were spawned but now are gone, presumed killed)
if (killtest) m_killcount += total_removed;
}
// special defrag pass to remove GOTO keyword tags
public void ClearGOTOTags()
{
if (m_SpawnObjects == null) return;
List<BaseXmlSpawner.KeywordTag> ToDelete = new List<BaseXmlSpawner.KeywordTag>();
foreach (SpawnObject so in m_SpawnObjects)
{
for (int x = 0; x < so.SpawnedObjects.Count; x++)
{
object o = so.SpawnedObjects[x];
if (o is BaseXmlSpawner.KeywordTag)
{
BaseXmlSpawner.KeywordTag sot = (BaseXmlSpawner.KeywordTag)o;
// clear the tags except for gump and delay tags
if (sot != null && sot.Type == 2)
{
ToDelete.Add(sot);
so.SpawnedObjects.Remove(o);
x--;
}
}
}
}
for(int x=ToDelete.Count - 1; x>=0; --x)//BaseXmlSpawner.KeywordTag i in ToDelete)
{
BaseXmlSpawner.KeywordTag i = ToDelete[x];
if (i != null && !i.Deleted)
{
i.Delete();
}
}
}
// special defrag pass to remove spawn object tags, which are placeholders for the special keyword spawn spec entries
public void ClearTags(bool all)
{
if (m_SpawnObjects == null) return;
bool removed = false;
List<BaseXmlSpawner.KeywordTag> ToDelete = new List<BaseXmlSpawner.KeywordTag>();
foreach (SpawnObject so in m_SpawnObjects)
{
for (int x = 0; x < so.SpawnedObjects.Count; x++)
{
object o = so.SpawnedObjects[x];
if (o is BaseXmlSpawner.KeywordTag)
{
BaseXmlSpawner.KeywordTag sot = (BaseXmlSpawner.KeywordTag)o;
// clear the tags except for gump and delay tags
if (sot != null && (all || ((sot.Flags & BaseXmlSpawner.KeywordFlags.Defrag) != 0)))
{
ToDelete.Add(sot);
so.SpawnedObjects.Remove(o);
x--;
removed = true;
}
}
}
}
for(int x=ToDelete.Count - 1; x>=0; --x)//each (BaseXmlSpawner.KeywordTag i in ToDelete)
{
BaseXmlSpawner.KeywordTag i = ToDelete[x];
if (i != null && !i.Deleted)
{
i.Delete();
}
}
// full clear of the taglist
if (all) m_KeywordTagList.Clear();
// Check if anything has been removed
if (removed == true)
InvalidateProperties();
}
public void DeleteGumpTags()
{
if (m_SpawnObjects == null) return;
bool removed = false;
List<BaseXmlSpawner.KeywordTag> ToDelete = new List<BaseXmlSpawner.KeywordTag>();
foreach (SpawnObject so in m_SpawnObjects)
{
for (int x = 0; x < so.SpawnedObjects.Count; x++)
{
object o = so.SpawnedObjects[x];
if (o is BaseXmlSpawner.KeywordTag)
{
BaseXmlSpawner.KeywordTag sot = (BaseXmlSpawner.KeywordTag)o;
// clear the gump tags
if (sot != null && sot.Type == 1)
{
ToDelete.Add(sot);
so.SpawnedObjects.Remove(o);
x--;
removed = true;
}
}
}
}
for(int x=ToDelete.Count - 1; x>=0; --x)//BaseXmlSpawner.KeywordTag i in ToDelete)
{
BaseXmlSpawner.KeywordTag i = ToDelete[x];
if (i != null && !i.Deleted)
{
i.Delete();
}
}
// Check if anything has been removed
if (removed == true)
InvalidateProperties();
}
public void DeleteTag(BaseXmlSpawner.KeywordTag tag)
{
if (m_SpawnObjects == null) return;
bool removed = false;
List<BaseXmlSpawner.KeywordTag> ToDelete = new List<BaseXmlSpawner.KeywordTag>();
foreach (SpawnObject so in m_SpawnObjects)
{
for (int x = 0; x < so.SpawnedObjects.Count; x++)
{
object o = so.SpawnedObjects[x];
if (o is BaseXmlSpawner.KeywordTag)
{
BaseXmlSpawner.KeywordTag sot = (BaseXmlSpawner.KeywordTag)o;
// clear the matching tags
if (sot != null && sot == tag)
{
ToDelete.Add(sot);
so.SpawnedObjects.Remove(o);
x--;
removed = true;
}
}
}
}
for(int x=ToDelete.Count - 1; x>=0; --x)//BaseXmlSpawner.KeywordTag i in ToDelete)
{
BaseXmlSpawner.KeywordTag i = ToDelete[x];
if (i != null && !i.Deleted)
{
i.Delete();
}
}
// Check if anything has been removed
if (removed == true)
InvalidateProperties();
}
#endregion
#region SequentialSpawning methods
private int SubGroupCount(int sgroup)
{
if (m_SpawnObjects == null) return (0);
int nsub = 0;
for (int i = 0; i < m_SpawnObjects.Count; i++)
{
SpawnObject s = m_SpawnObjects[i];
if (s.SubGroup == sgroup)
nsub++;
}
return nsub;
}
private int RandomAvailableSpawnIndex()
{
// get spawn indices randomly from all available spawns independent of group
return (RandomAvailableSpawnIndex(-1));
}
// get spawn indices randomly from all available spawns of a group
private int RandomAvailableSpawnIndex(int sgroup)
{
if (m_SpawnObjects == null) return (-1);
int maxrange = 0;
List<int> sgrouplist = null;
int totalcount = 0;
// make a pass to determine which subgroups are available for spawning
// by finding any subgroups that do not have available spawns
for (int i = 0; i < m_SpawnObjects.Count; i++)
{
SpawnObject s = m_SpawnObjects[i];
if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) continue;
totalcount += s.SpawnedObjects.Count;
if (s.SubGroup > 0 && s.SpawnedObjects.Count >= s.MaxCount)
{
// this subgroup is not available so add it to the list
if (sgrouplist == null)
{
sgrouplist = new List<int>();
}
sgrouplist.Add(s.SubGroup);
}
}
for (int i = 0; i < m_SpawnObjects.Count; i++)
{
SpawnObject s = m_SpawnObjects[i];
if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) continue;
if ((s.MaxCount > s.SpawnedObjects.Count) && (sgroup < 0 || sgroup == s.SubGroup)
&& (sgrouplist == null || !sgrouplist.Contains(s.SubGroup)) && (s.SubGroup <= 0 || SubGroupCount(s.SubGroup) + totalcount <= MaxCount))
{
// keep track of the number of spawn objects that are not at max (hence available for spawning)
// this will be used to compute the probabilistic weighting function based on the relative
// maxcounts of each entry
maxrange += s.MaxCount;
s.Available = true;
}
else
{
s.Available = false;
}
}
// now generate a random number over the available spawnobjects
// but only if the entire subgroup is available for spawning
// note, subgroup zero is exempt from this check.
if (maxrange > 0)
{
int randindex = Utility.Random(maxrange);
// and map it into the avail spawns
int currentrange = 0;
for (int i = 0; i < m_SpawnObjects.Count; i++)
{
SpawnObject s = m_SpawnObjects[i];
if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) continue;
// keep track of the number of spawn objects that are not at max (hence available for spawning)
if (s.Available)
{
// check to see if the random value maps into the range of the current index
if (randindex >= currentrange && randindex < currentrange + s.MaxCount)
{
return (i);
}
currentrange += s.MaxCount;
}
}
// should never get here
return (-1);
}
else
{
// no spawns are available
return (-1);
}
}
// get spawn indices randomly from all available spawns of a group
private int RandomSpawnIndex(int sgroup)
{
if (m_SpawnObjects == null) return (-1);
int avail = 0;
int maxrange = 0;
for (int i = 0; i < m_SpawnObjects.Count; i++)
{
SpawnObject s = m_SpawnObjects[i];
// keep track of the number of spawn objects that are not at max (hence available for spawning)
if (sgroup < 0 || (sgroup == s.SubGroup))
{
avail++;
maxrange += s.MaxCount;
}
}
// now generate a random number over the available spawnobjects
if (avail > 0 && maxrange > 0)
{
int randindex = Utility.Random(maxrange);
// and map it into the avail spawns
int currentrange = 0;
for (int i = 0; i < m_SpawnObjects.Count; i++)
{
SpawnObject s = m_SpawnObjects[i];
// keep track of the number of spawn objects that are not at max (hence available for spawning)
if (sgroup < 0 || (sgroup == s.SubGroup))
{
if (randindex >= currentrange && randindex < currentrange + s.MaxCount)
return (i);
currentrange += s.MaxCount;
}
}
// should never get here
return (-1);
}
else
{
// no spawns are available
return (-1);
}
}
// return the next subgroup in the sequence.
public int NextSequentialIndex(int sgroup)
{
if (m_SpawnObjects == null || m_SpawnObjects.Count == 0) return (0);
int finddirection = 1;
int largergroup = -1;
//find the next subgroup that is greater than the current one
for (int j = 0; j < m_SpawnObjects.Count; j++)
{
SpawnObject s = m_SpawnObjects[j];
if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) continue;
int thisgroup = s.SubGroup;
// start off by finding a subgroup that is larger
if (finddirection == 1)
{
if (thisgroup > sgroup)
{
largergroup = thisgroup;
// then work backward to find the group that is less than this but still larger than the current
finddirection = -1;
}
}
else
{
if ((thisgroup > sgroup) && (thisgroup < largergroup))
{
largergroup = thisgroup;
finddirection = -1;
}
}
}
// if couldnt find one larger, then it is time to wraparound
if (largergroup < 0 && sgroup >= 0)
return (NextSequentialIndex(-1));
else
return (largergroup);
}
// returns the spawn index of a spawn entry in the current sequential subgroup
public int GetCurrentAvailableSequentialSpawnIndex(int sgroup)
{
if (sgroup < 0) return (-1);
if (m_SpawnObjects == null) return (-1);
if (sgroup == 0) return (RandomAvailableSpawnIndex(0));
//return the first instance of a spawn object that is an available member of the requested subgroup
for (int j = 0; j < m_SpawnObjects.Count; j++)
{
SpawnObject s = m_SpawnObjects[j];
if (s.SubGroup == sgroup && s.MaxCount > s.SpawnedObjects.Count)
{
return (j);
}
}
// failed to find any spawn entry of the requested subgroup
return (-1);
}
// returns the spawn index of a spawn entry in the current sequential subgroup
public int GetCurrentSequentialSpawnIndex(int sgroup)
{
if (sgroup < 0) return (-1);
if (m_SpawnObjects == null) return (-1);
if (sgroup == 0) return (RandomSpawnIndex(0));
//return the first instance of a spawn object that is an available member of the requested subgroup
for (int j = 0; j < m_SpawnObjects.Count; j++)
{
if (m_SpawnObjects[j].SubGroup == sgroup)
{
return (j);
}
}
// failed to find any spawn entry of the requested subgroup
return (-1);
}
private void SeqResetTo(int sgroup)
{
// check the SequentialResetTo on the subgroup
// cant do resets on subgroup 0
if (sgroup == 0) return;
// this will get the index of the first spawn entry in the subgroup
// it will have the subgroup timer settings
int spawnindex = GetCurrentSequentialSpawnIndex(sgroup);
if (spawnindex >= 0)
{
// if it is greater than zero then initiate reset
SpawnObject s = m_SpawnObjects[spawnindex];
m_SequentialSpawning = s.SequentialResetTo;
InitiateSequentialReset(sgroup);
// clear the spawns
//RemoveSpawnObjects();
ClearSubgroup(s.SubGroup);
// and reset the kill count
KillCount = 0;
}
}
private bool CheckForSequentialReset()
{
// check the SequentialResetTime on the subgroup
// cant do resets on subgroup 0
if (m_SequentialSpawning == 0) return false;
// this will get the index of the first spawn entry in the subgroup
// it will have the subgroup timer settings
int spawnindex = GetCurrentSequentialSpawnIndex(m_SequentialSpawning);
if (spawnindex >= 0)
{
// check the reset time on it
SpawnObject s = m_SpawnObjects[spawnindex];
// if it is greater than zero then resetting is possible
if (s.SequentialResetTime > 0)
{
// so check the reset timer
if (NextSeqReset <= TimeSpan.Zero)
{
// it has expired so time to reset
return true;
}
}
}
return false;
}
private void InitiateSequentialReset(int sgroup)
{
// check the SequentialResetTime on the subgroup
// cant do resets on subgroup 0
if (sgroup == 0) return;
// this will get the index of the first spawn entry in the subgroup
// it will have the subgroup timer settings
int spawnindex = GetCurrentSequentialSpawnIndex(sgroup);
if (spawnindex >= 0)
{
// if it is greater than zero then initiate reset
SpawnObject s = m_SpawnObjects[spawnindex];
NextSeqReset = TimeSpan.FromMinutes(s.SequentialResetTime);
}
}
public void ResetSequential()
{
// go back to the lowest level
if (m_SequentialSpawning >= 0)
{
m_SequentialSpawning = NextSequentialIndex(-1);
}
// reset the nextspawn times
ResetNextSpawnTimes();
// and reset the kill count
KillCount = 0;
}
public bool AdvanceSequential()
{
// check for a sequence hold
if (HoldSequence) return false;
// check for triggering
if (!((m_proximityActivated || CanFreeSpawn) && TODInRange)) return false;
// if kills needed is greater than zero then check the killcount as well
int spawnindex = GetCurrentSequentialSpawnIndex(m_SequentialSpawning);
int killsneeded = 0;
int subgroup = -1;
bool clearedobjects = false;
if (spawnindex >= 0)
{
SpawnObject s = m_SpawnObjects[spawnindex];
subgroup = s.SubGroup;
killsneeded = s.KillsNeeded;
}
// advance the sequential spawn index if it is enabled and kills needed have been satisfied
if (m_SequentialSpawning >= 0 && (killsneeded == 0 || KillCount >= killsneeded))
{
m_SequentialSpawning = NextSequentialIndex(m_SequentialSpawning);
// set the sequential reset based on the current sequence state
// this will be checked in the spawner OnTick to determine whether to Reset the sequential state
InitiateSequentialReset(m_SequentialSpawning);
// clear the spawns if there is a killcount on the level
if (killsneeded >= 0)
{
ClearSubgroup(subgroup);
clearedobjects = true;
}
// and reset the kill count
KillCount = 0;
}
// returning true will indicate that all spawns have been cleared and therefore a new spawn can be initiated in the same OnTick
return (clearedobjects);
}
#endregion
#region Spawn methods
int killcount_held = 0;
public void OnTick()
{
_TraceStart(8);
// start up the timer again for the next Ontick
DoTimer();
// reset the protection against runaway looping
ClearSpawnedThisTick = true;
// if regional spawning is enabled, update the region in case new regions were added after the initialization pass
CheckRegionAssignment = true;
// reset the killcount whenever a spawntick goes by in which it could have spawned, ie the spawner is full, or proximity triggered
// spawns were not activated. Note that killcount gets incremented within Defrag whenever a spawn is that had been generated is removed from the active list.
// Check the count before and then after the spawn passes.
// if the spawner is still refractory then dont do a reset of the killcount.
//int startcount = this.m_killcount;
int startcount = killcount_held;
if (!m_skipped)
{
killcount_held = m_killcount;
}
// killcount will be updated in Defrag
Defrag(true);
// remove any keyword tags that were made
// note, tags only last a single ontick except for WAIT type
ClearTags(false);
if (!m_DisableGlobalAutoReset && startcount == m_killcount && !m_refractActivated && !m_skipped)
{
m_spawncheck--;
}
m_skipped = false;
// allow for some slack in the killcount reset by resetting after a certain number of spawn ticks without kills pass
if (m_spawncheck <= 0)
{
m_killcount = 0;
m_spawncheck = m_KillReset; // wait for 1 spawn ticks to pass before resetting. This can be set to anything you like
}
// check for smart spawning
if (SmartSpawning && IsFull && !HasActiveSectors && !HasDamagedOrDistantSpawns /*&& !HasHoldSmartSpawning */ )
{
IsInactivated = true;
// for multiple sector spawning ranges use the sector timer, otherwise just rely on OnSectorActivate to detect sector activation
//if(!UseSectorActivate)
//DoSectorTimer(TimeSpan.FromSeconds(1));
SmartRemoveSpawnObjects();
}
// dont process spawn ticks while inactivated if smart spawning is enabled
if (SmartSpawning && IsInactivated)
{
_TraceEnd(8);
return;
}
IsInactivated = false;
// check to see if spawning is on hold due to a WAIT keyword
if (!OnHold)
{
// look for triggers that are not player activated.
if (m_ProximityRange == -1 && CanSpawn)
{
CheckTriggers(null, null, false);
}
// check for proximity triggers without movement activation
if (m_ProximityRange >= 0 && CanSpawn)
{
// check all nearby players
IPooledEnumerable eable = GetMobilesInRange(m_ProximityRange);
foreach (Mobile p in eable)
{
if (ValidPlayerTrig(p))
CheckTriggers(p, null, true);
}
eable.Free();
}
if (m_Group)
{
// check the seq reset time on the current subgroup
// if the reset time is greater than zero then check the timer
// if it has expired then reset the sequential subgroup
// only do this if it can actually spawn
if (CheckForSequentialReset())
{
// it has expired so reset the sequential spawn level
SeqResetTo(m_SequentialSpawning);
bool triedtospawn = Respawn();
if (triedtospawn) ClearGOTOTags();
// dont advance if the spawn isnt triggered after resetting
if (!triedtospawn) HoldSequence = true;
}
else
if (TotalSpawnedObjects <= 0)
{
// advance the sequential spawn index if it is enabled
AdvanceSequential();
//bool hadhold = HoldSequence;
//HoldSequence = false;
bool triedtospawn = Respawn();
if (triedtospawn) ClearGOTOTags();
//if(!triedtospawn) HoldSequence = hadhold;
}
}
else
{
if (CheckForSequentialReset())
{
// it has expired so reset the sequential spawn level
SeqResetTo(m_SequentialSpawning);
// dont advance if the spawn isnt triggered after resetting
HoldSequence = true;
}
else
{
// advance the sequence before spawning
AdvanceSequential();
}
// keep track of the hold flag before trying to spawn in case no spawn attempt is made
//bool hadhold = HoldSequence;
// clear the hold flag to see if any of the spawned entries try to set it
//HoldSequence = false;
// try to spawn. If spawning conditions such as triggering or TOD are not met, then it returns false
bool triedtospawn = Spawn(false, 0);
if (triedtospawn) ClearGOTOTags();
// this will maintain any sequential holds if spawning was suppressed due to triggering
// if nothing was spawned or triggered, then restore the hold status to previous state
//if(!triedtospawn) HoldSequence = hadhold;
if (!FreeRun)
{
m_mob_who_triggered = null;
m_skill_that_triggered = XmlSpawnerSkillCheck.RegisteredSkill.Invalid;
}
}
// remove any keyword tags that were made except for WAIT type
ClearTags(false);
// and clear triggering flags
if (!OnHold && !FreeRun)
{
m_proximityActivated = false;
}
}
if (FreeRun && SpawnOnTrigger && m_proximityActivated)
{
// if it is in free run and was triggered, then just keep spawning as though it was triggered immediately
NextSpawn = TimeSpan.Zero;
ResetNextSpawnTimes();
}
//this.m_ExternalTrigger = false;
// if it is out of the TOD range then delete the spawns
if (!TODInRange)
{
RemoveSpawnObjects();
ResetAllFlags();
}
_TraceEnd(8);
}
public bool ClearSpawnedThisTick
{
set
{
if (m_SpawnObjects == null || value == false) return;
for (int i = 0; i < m_SpawnObjects.Count; i++)
{
SpawnObject sobj = m_SpawnObjects[i];
if (sobj != null)
{
sobj.SpawnedThisTick = false;
}
}
}
}
// select and spawn something
// return false if it cannot spawn, e.g. there is nothing to spawn or it is a triggerable spawner and has not been triggered
public bool Spawn(bool smartspawn, byte loops)
{
if (m_SpawnObjects != null && m_SpawnObjects.Count > 0 && (m_proximityActivated || CanFreeSpawn) && TODInRange)
{
m_HoldSequence = false;
// if the spawner is full then dont bother
if (IsFull)
{
ResetProximityActivated();
return (true);
}
// Pick a spawn object to spawn
int SpawnIndex = 0;
// see if sequential spawning has been selected
if (m_SequentialSpawning >= 0)
{
// if so then use its value to get the index of the first available spawn entry in the next subgroup to be spawned
// note, if the current sequence finds a zero group then the spawn will be picked at random from it
SpawnIndex = GetCurrentAvailableSequentialSpawnIndex(m_SequentialSpawning);
}
else
{
// if sequential spawning is not set then select the next spawn at random
SpawnIndex = RandomAvailableSpawnIndex();
}
// no spawns are available so no point in continuing
if (SpawnIndex < 0)
{
ResetProximityActivated();
return (true);
}
SpawnObject sobj = m_SpawnObjects[SpawnIndex];
int sgroup = sobj.SubGroup;
// if this is part of a non-zero group, then spawn all of the group members as well
if (sgroup != 0)
{
SpawnSubGroup(sgroup, smartspawn, loops);
/*
for( int j = 0; j < m_SpawnObjects.Count; j++)
{
SpawnObject so = (SpawnObject)m_SpawnObjects[j];
if(so.SubGroup == sgroup)
{
// get the SpawnsPerTick count and spawn up to that number
bool success = Spawn( j, smartspawn, so.SpawnsPerTick );
if(success && !smartspawn)
RefreshNextSpawnTime(so);
}
}
*/
}
else
{
// Found a valid spawn object so spawn it and see if it successful
if (Spawn(SpawnIndex, smartspawn, sobj.SpawnsPerTick, loops))
{
if (!smartspawn)
RefreshNextSpawnTime(sobj);
}
}
ResetProximityActivated();
return (true);
}
ResetProximityActivated();
return (false);
}
// spawn an individual entry by index up to count times
public bool Spawn(int index, bool smartspawn, int count, int packrange, Point3D packcoord, bool ignoreloopprotection, byte loops)
{
if (m_SpawnObjects == null || index >= m_SpawnObjects.Count) return false;
bool didspawn = false;
SpawnObject so = m_SpawnObjects[index];
if (so == null) return false;
Defrag(false);
// make sure you dont go over the individual entry maxcount
int somax = so.MaxCount;
int socnt = so.SpawnedObjects.Count;
int nspawn = so.SpawnsPerTick;
int scnt = SafeCurrentCount;
for (int k = 0; (k < nspawn) && (k + socnt < somax) && (k + scnt < MaxCount); k++)
{
if (packrange >= 0 && so.SubGroup > 0 && packcoord == Point3D.Zero)
{
packcoord = GetPackCoord(so.SubGroup);
}
if (Spawn(index, smartspawn, packrange, packcoord, ignoreloopprotection, loops))
{
// if any of the attempts were successful then flag it as having spawned
didspawn = true;
}
}
return didspawn;
}
// spawn an individual entry by index up to count times
public bool Spawn(int index, bool smartspawn, int count, byte loops)
{
return Spawn(index, smartspawn, count, false, loops);
}
// spawn an individual entry by index up to count times
public bool Spawn(int index, bool smartspawn, int count, bool ignoreloopprotection, byte loops)
{
return Spawn(index, smartspawn, count, -1, Point3D.Zero, ignoreloopprotection, loops);
}
// spawn an individual entry by spawn object
public void Spawn(string SpawnObjectTypeName, bool smartspawn, int packrange, Point3D packcoord, byte loops)
{
if (m_SpawnObjects == null) return;
for (int i = 0; i < m_SpawnObjects.Count; i++)
{
if (m_SpawnObjects[i].TypeName.ToUpper() == SpawnObjectTypeName.ToUpper())
{
if(Spawn(i, smartspawn, packrange, packcoord, loops))
{
RefreshNextSpawnTime(m_SpawnObjects[i]);
}
break;
}
else
{
}
}
}
// spawn an individual entry by index
public void Spawn(string SpawnObjectTypeName, bool smartspawn, byte loops)
{
Spawn(SpawnObjectTypeName, smartspawn, -1, Point3D.Zero, loops);
}
// spawn an individual entry by index
public bool Spawn(int index, bool smartspawn, int packrange, Point3D packcoord, byte loops)
{
return Spawn(index, smartspawn, packrange, packcoord, false, loops);
}
// spawn an individual entry by index
public bool Spawn(int index, bool smartspawn, int packrange, Point3D packcoord, bool ignoreloopprotection, byte loops)
{
Map map = this.Map;
// Make sure everything is ok to spawn an object
if ((map == null) ||
(map == Map.Internal) ||
(m_SpawnObjects == null) ||
(m_SpawnObjects.Count == 0) ||
(index < 0) ||
(index >= m_SpawnObjects.Count)
)
return false;
// Remove any spawns that don't belong to the spawner any more.
Defrag(false);
// Get the spawn object at the required index
SpawnObject TheSpawn = m_SpawnObjects[index];
// Check if the object retrieved is a valid SpawnObject
if (TheSpawn != null)
{
// dont allow an entry to be spawned more than once per tick
// this protects against runaway recursive looping
if (TheSpawn.SpawnedThisTick && !ignoreloopprotection) return false;
// check the nextspawn time to see if it is available
if (TheSpawn.NextSpawn > DateTime.UtcNow)
return false;
int CurrentCreatureMax = TheSpawn.MaxCount;
int CurrentCreatureCount = TheSpawn.SpawnedObjects.Count;
// Check that the current object to be spawned has not reached its maximum allowed
// and make sure that the maximum spawner count has not been exceeded as well
if ((CurrentCreatureCount >= CurrentCreatureMax) ||
(TotalSpawnedObjects >= m_Count))
{
return false;
}
// check for string substitions
string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(this, this, m_mob_who_triggered, TheSpawn.TypeName);
// random positioning is the default
List<SpawnPositionInfo> spawnpositioning = null;
// require valid surfaces by default
bool requiresurface = true;
// parse the # function specification for the entry
while (substitutedtypeName.StartsWith("#"))
{
string[] args = BaseXmlSpawner.ParseSemicolonArgs(substitutedtypeName, 2);
if (args.Length > 0)
{
if (spawnpositioning == null)
{
spawnpositioning = new List<SpawnPositionInfo>();
}
// parse any comma args
string[] keyvalueargs = BaseXmlSpawner.ParseCommaArgs(args[0], 10);
if (keyvalueargs.Length > 0)
{
switch (keyvalueargs[0])
{
case "#NOITEMID":
spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.NoItemID, m_mob_who_triggered, keyvalueargs));
break;
case "#ITEMID":
spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.ItemID, m_mob_who_triggered, keyvalueargs));
break;
case "#NOTILES":
spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.NoTiles, m_mob_who_triggered, keyvalueargs));
break;
case "#TILES":
spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Tiles, m_mob_who_triggered, keyvalueargs));
break;
case "#WET":
spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Wet, m_mob_who_triggered, keyvalueargs));
break;
case "#XFILL":
spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.RowFill, m_mob_who_triggered, keyvalueargs));
break;
case "#YFILL":
spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.ColFill, m_mob_who_triggered, keyvalueargs));
break;
case "#EDGE":
spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Perimeter, m_mob_who_triggered, keyvalueargs));
break;
case "#PLAYER":
spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Player, m_mob_who_triggered, keyvalueargs));
break;
case "#WAYPOINT":
spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Waypoint, m_mob_who_triggered, keyvalueargs));
break;
case "#RELXY":
spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.RelXY, m_mob_who_triggered, keyvalueargs));
break;
case "#DXY":
spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.DeltaLocation, m_mob_who_triggered, keyvalueargs));
break;
case "#XY":
spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Location, m_mob_who_triggered, keyvalueargs));
break;
case "#CONDITION":
// test the specified condition string
// syntax is #CONDITION,proptest
// reparse with only one arg after the comma, this allows property tests that use commas as well
string[] ckeyvalueargs = BaseXmlSpawner.ParseCommaArgs(args[0], 2);
if (ckeyvalueargs.Length > 1)
{
// dont spawn if it fails the test
if (!BaseXmlSpawner.CheckPropertyString(this, this, ckeyvalueargs[1], m_mob_who_triggered, out this.status_str)) return false;
}
else
{
this.status_str = "invalid #CONDITION specification: " + args[0];
}
break;
default:
this.status_str = "invalid # specification: " + args[0];
break;
}
}
}
// get the rest of the spawn entry
if (args.Length > 1)
{
substitutedtypeName = args[1].Trim();
}
else
{
substitutedtypeName = String.Empty;
}
}
if (substitutedtypeName.StartsWith("*"))
{
requiresurface = false;
substitutedtypeName = substitutedtypeName.TrimStart('*');
}
TheSpawn.RequireSurface = requiresurface;
string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName);
if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName))
{
string status_str = null;
bool completedtypespawn = BaseXmlSpawner.SpawnTypeKeyword(this, TheSpawn, typeName, substitutedtypeName, requiresurface, spawnpositioning,
m_mob_who_triggered, this.Location, this.Map, new XmlGumpCallback(SpawnerGumpCallback), out status_str, loops);
if (status_str != null)
{
this.status_str = status_str;
}
if (completedtypespawn)
{
// successfully spawned the keyword
// note that returning true means that Spawn will assume that it worked and will not try to respawn something else
// added the duration timer that begins on spawning
DoTimer2(m_Duration);
InvalidateProperties();
return true;
}
else
{
return false;
}
}
else
{
// its a regular type descriptor so find out what it is
Type type = SpawnerType.GetType(typeName);
// dont try to spawn invalid types, or Mobile type spawns in containers
if (type != null && !(this.Parent != null && (type == typeof(Mobile) || type.IsSubclassOf(typeof(Mobile)))))
{
string[] arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/");
object o = CreateObject(type, arglist[0]);
if (o == null)
{
this.status_str = "invalid type specification: " + arglist[0];
return true;
}
try
{
if (o is Mobile)
{
// if this is in any container such as a pack the xyz values are invalid as map coords so dont spawn the mob
if (this.Parent is Container)
{
((Mobile)o).Delete();
return true;
}
Mobile m = (Mobile)o;
// add the mobile to the spawned list
TheSpawn.SpawnedObjects.Add(m);
m.Spawner = this;
Point3D loc;
/*
if( ( m is BaseVendor ) &&
( this.Map.CanFit( this.Location, SpawnFitSize, true, false ) == true ) )
{
loc = this.Location;
}
else
{
loc = GetSpawnPosition(requiresurface);
}
*/
loc = GetSpawnPosition(requiresurface, packrange, packcoord, spawnpositioning, m);
if (!smartspawn)
{
m.OnBeforeSpawn(loc, map);
}
m.MoveToWorld(loc, map);
if (m is BaseCreature)
{
BaseCreature c = (BaseCreature)m;
c.RangeHome = m_HomeRange;
c.CurrentWayPoint = m_WayPoint;
if (m_Team > 0)
c.Team = m_Team;
// Check if this spawner uses absolute (from spawnER location)
// or relative (from spawnED location) as the mobiles home point
if (m_HomeRangeIsRelative == true)
c.Home = m.Location; // Mobiles spawned location is the home point
else
c.Home = this.Location; // Spawners location is the home point
}
// if the object has an OnSpawned method, then invoke it
if (!smartspawn)
{
m.OnAfterSpawn();
}
// apply the parsed arguments from the typestring using setcommand
// be sure to do this after setting map and location so that errors dont place the mob on the internal map
string status_str;
BaseXmlSpawner.ApplyObjectStringProperties(this, substitutedtypeName, m, m_mob_who_triggered, this, out status_str);
// if the object has an OnAfterSpawnAndModify method, then invoke it
//BaseXmlSpawner.InvokeOnAfterSpawnAndModify(o);
if (status_str != null)
{
this.status_str = status_str;
}
InvalidateProperties();
// added the duration timer that begins on spawning
DoTimer2(m_Duration);
return true;
}
else if (o is Item)
{
Item item = (Item)o;
string status_str;
BaseXmlSpawner.AddSpawnItem(this, TheSpawn, item, this.Location, map, m_mob_who_triggered, requiresurface, spawnpositioning, substitutedtypeName, smartspawn, out status_str);
if (status_str != null)
{
this.status_str = status_str;
}
InvalidateProperties();
// added the duration timer that begins on spawning
DoTimer2(m_Duration);
return true;
}
}
catch (Exception ex) { Console.WriteLine("When spawning {0}, {1}", o, ex); }
}
else
{
this.status_str = "invalid type specification: " + typeName;
return true;
}
}
}
return false;
}
public bool SpawnSubGroup(int sgroup, byte loops)
{
return SpawnSubGroup(sgroup, false, loops);
}
public bool SpawnSubGroup(int sgroup, bool smartspawn, byte loops)
{
return SpawnSubGroup(sgroup, false, false, loops);
}
public bool SpawnSubGroup(int sgroup, bool smartspawn, bool ignoreloopprotection, byte loops)
{
if (m_SpawnObjects == null) return false;
if (sgroup >= 0)
{
bool didspawn = false;
Point3D packcoord = Point3D.Zero;
for (int j = 0; j < m_SpawnObjects.Count; j++)
{
SpawnObject so = m_SpawnObjects[j];
if (so != null && so.SubGroup == sgroup)
{
// find the first subgroup spawn to determine the packspawning reference coordinates
if (so.PackRange >= 0 && packcoord == Point3D.Zero)
{
packcoord = GetPackCoord(sgroup);
}
// get the SpawnsPerTick count and spawn up to that number
bool success = Spawn(j, smartspawn, so.SpawnsPerTick, so.PackRange, packcoord, ignoreloopprotection, loops);
if (success) didspawn = true;
if (success && !smartspawn)
RefreshNextSpawnTime(so);
}
}
// success if any of the subgroup spawned
if (didspawn)
{
return (true);
}
}
return (false);
}
#endregion
#region Spawn support methods
public Point3D GetPackCoord(int sgroup)
{
Point3D packcoord = Point3D.Zero;
for (int j = 0; j < m_SpawnObjects.Count; j++)
{
SpawnObject so = m_SpawnObjects[j];
if (so != null && so.SubGroup == sgroup && so.SpawnedObjects.Count > 0 && so.PackRange >= 0)
{
// if pack spawning is enabled for this subgroup, then get the
// the origin for pack spawning using the first existing pack spawn
// in the subgroup
for (int i = 0; i < so.SpawnedObjects.Count; ++i)
{
object o = so.SpawnedObjects[i];
if (o is Item)
{
return ((Item)o).Location;
}
else
if (o is Mobile)
{
return ((Mobile)o).Location;
}
}
}
}
return Point3D.Zero;
}
//used by the reset button in the gump
public void ResetAllFlags()
{
m_proximityActivated = false;
m_ExternalTrigger = false;
m_durActivated = false;
m_refractActivated = false;
m_mob_who_triggered = null;
m_skill_that_triggered = XmlSpawnerSkillCheck.RegisteredSkill.Invalid;
m_killcount = 0;
m_GumpState = null;
FreeRun = false;
}
public bool BringHome
{
set { if (value) BringToHome(); }
}
public void BringToHome()
{
if (m_SpawnObjects == null) return;
Defrag(false);
foreach (SpawnObject so in m_SpawnObjects)
{
for (int i = 0; i < so.SpawnedObjects.Count; ++i)
{
object o = so.SpawnedObjects[i];
if (o is Mobile)
{
Mobile m = (Mobile)o;
m.Map = Map;
m.Location = new Point3D(Location);
}
else if (o is Item)
{
Item item = (Item)o;
item.MoveToWorld(Location, Map);
}
}
}
}
public bool CheckRegionAssignment
{
get { return false; }
set
{
if (value == true)
{
// see if a region definition needs updating
if (m_Region == null && m_RegionName != null && RegionName != string.Empty)
{
RegionName = RegionName;
if (SpawnRegion != null)
{
// clear the status if successful
status_str = null;
}
}
}
}
}
public void Start()
{
if (m_Running == false)
{
if (m_SpawnObjects != null && m_SpawnObjects.Count > 0)
{
m_Running = true;
DoTimer();
}
}
}
public void Stop()
{
if (m_Running == true)
{
// turn off all timers
if (m_Timer != null)
m_Timer.Stop();
if (m_DurTimer != null)
m_DurTimer.Stop();
if (m_RefractoryTimer != null)
m_RefractoryTimer.Stop();
m_Running = false;
m_proximityActivated = false;
m_ExternalTrigger = false;
m_mob_who_triggered = null;
m_skill_that_triggered = XmlSpawnerSkillCheck.RegisteredSkill.Invalid;
}
}
public void Reset()
{
Stop();
// reset the protection against runaway looping
ClearSpawnedThisTick = true;
RemoveSpawnObjects();
ClearTags(true);
ResetAllFlags();
status_str = "";
m_killcount = 0;
OnHold = false;
mostRecentSpawnPosition = Point3D.Zero;
spawnPositionWayTable = null;
// dont advance before the next spawn
HoldSequence = true;
IsInactivated = false;
ResetSequential();
}
public bool Respawn()
{
inrespawn = true;
IsInactivated = false;
// reset the protection against runaway looping
ClearSpawnedThisTick = true;
// Delete all currently spawned objects
RemoveSpawnObjects();
// added the explicit start. Previously it relied on the automatic start that occurred when the spawnobject list was updated.
Start();
ResetNextSpawnTimes();
// Respawn all objects up to the spawners current maximum allowed
// note that by default, for proximity sensing, the spawner will only trigger once, but for respawns allow them all
bool keepProximityActivated = m_proximityActivated;
bool triedtospawn = false;
// attempt to spawn up to the MaxCount of the spawner
for (int x = 0; x < m_Count; x++)
{
triedtospawn = Spawn(false, 0);
if (x < m_Count - 1 || OnHold) m_proximityActivated = keepProximityActivated;
}
if (!FreeRun)
{
m_mob_who_triggered = null;
m_skill_that_triggered = XmlSpawnerSkillCheck.RegisteredSkill.Invalid;
}
ClearTags(true);
inrespawn = false;
return triedtospawn;
}
// used to optimize smartspawning use of hasholdsmartspawning
public void SmartRespawn()
{
inrespawn = true;
IsInactivated = false;
// reset the protection against runaway looping
ClearSpawnedThisTick = true;
// Delete all currently spawned objects
SmartRemoveSpawnObjects();
// added the explicit start. Previously it relied on the automatic start that occurred when the spawnobject list was updated.
Start();
ResetNextSpawnTimes();
// Respawn all objects up to the spawners current maximum allowed
// note that by default, for proximity sensing, the spawner will only trigger once, but for respawns allow them all
bool keepProximityActivated = m_proximityActivated;
// attempt to spawn up to the MaxCount of the spawner
for (int x = 0; x < m_Count; x++)
{
Spawn(true, 0);
if (x < m_Count - 1 || OnHold) m_proximityActivated = keepProximityActivated;
}
if (!FreeRun)
{
m_mob_who_triggered = null;
m_skill_that_triggered = XmlSpawnerSkillCheck.RegisteredSkill.Invalid;
}
ClearTags(true);
inrespawn = false;
}
public void SortSpawns()
{
if (m_SpawnObjects == null) return;
// establish the entry order
int count = 0;
foreach (SpawnObject so in m_SpawnObjects)
{
so.EntryOrder = count++;
}
m_SpawnObjects.Sort(new SubgroupSorter());
}
private class SubgroupSorter : IComparer<SpawnObject>
{
public int Compare(SpawnObject a, SpawnObject b)
{
if (a.SubGroup == b.SubGroup)
{
// use the entry order as the secondary sort factor
return a.EntryOrder - b.EntryOrder;
}
else
return a.SubGroup - b.SubGroup;
}
}
public static SpawnObject GetSpawnObject(XmlSpawner spawner, int sgroup)
{
if (spawner == null || spawner.m_SpawnObjects == null) return (null);
for (int i = 0; i < spawner.m_SpawnObjects.Count; i++)
{
// find the first entry with matching subgroup id
if (spawner.m_SpawnObjects[i].SubGroup == sgroup)
{
return spawner.m_SpawnObjects[i];
}
}
return null;
}
public static object GetSpawned(XmlSpawner spawner, int sgroup)
{
if (spawner == null || spawner.m_SpawnObjects == null) return (null);
for (int i = 0; i < spawner.m_SpawnObjects.Count; i++)
{
// find the first entry with matching subgroup id
if (spawner.m_SpawnObjects[i].SubGroup == sgroup)
{
// find the first spawned object in the entry
if (spawner.m_SpawnObjects[i].SpawnedObjects.Count > 0)
{
return spawner.m_SpawnObjects[i].SpawnedObjects[0];
}
}
}
return null;
}
public static List<object> GetSpawnedList(XmlSpawner spawner, int sgroup)
{
List<object> newlist = new List<object>();
if (spawner == null || spawner.m_SpawnObjects == null) return (null);
for (int i = 0; i < spawner.m_SpawnObjects.Count; i++)
{
// find the first entry with matching subgroup id
if (spawner.m_SpawnObjects[i].SubGroup == sgroup)
{
// find the first spawned object in the entry
if (spawner.m_SpawnObjects[i].SpawnedObjects.Count > 0)
{
for (int j = 0; j < spawner.m_SpawnObjects[i].SpawnedObjects.Count; j++)
newlist.Add(spawner.m_SpawnObjects[i].SpawnedObjects[j]);
}
}
}
return newlist;
}
public bool HasSubGroups()
{
if (m_SpawnObjects == null) return (false);
for (int j = 0; j < m_SpawnObjects.Count; j++)
{
if (m_SpawnObjects[j].SubGroup > 0) return true;
}
return false;
}
private void ResetProximityActivated()
{
// dont reset triggering if free run mode has been selected
if (!FreeRun)
{
m_proximityActivated = false;
}
}
private void RefreshNextSpawnTimes()
{
if (m_SpawnObjects != null && m_SpawnObjects.Count > 0)
{
for (int i = 0; i < m_SpawnObjects.Count; i++)
{
SpawnObject so = m_SpawnObjects[i];
RefreshNextSpawnTime(so);
}
}
}
public bool HasIndividualSpawnTimes()
{
if (m_SpawnObjects != null && m_SpawnObjects.Count > 0)
{
for (int i = 0; i < m_SpawnObjects.Count; i++)
{
SpawnObject so = m_SpawnObjects[i];
if (so.MinDelay != -1 || so.MaxDelay != -1) return true;
}
}
return false;
}
private void ResetNextSpawnTimes()
{
if (m_SpawnObjects != null && m_SpawnObjects.Count > 0)
{
for (int i = 0; i < m_SpawnObjects.Count; i++)
{
SpawnObject so = m_SpawnObjects[i];
so.NextSpawn = DateTime.UtcNow;
}
}
}
public void RefreshNextSpawnTime(SpawnObject so)
{
if (so == null) return;
int mind = (int)(so.MinDelay * 60);
int maxd = (int)(so.MaxDelay * 60);
if (mind < 0 || maxd < 0)
{
so.NextSpawn = DateTime.UtcNow;
}
else
{
TimeSpan delay = TimeSpan.FromSeconds(Utility.RandomMinMax(mind, maxd));
so.NextSpawn = DateTime.UtcNow + delay;
}
}
public static bool IsValidMapLocation(int X, int Y, Map map)
{
if (map == null || map == Map.Internal) return false;
// check the location relative to the current map to make sure it is valid
if (X < 0 || X > map.Width || Y < 0 || Y > map.Height)
{
return false;
}
return true;
}
public static bool IsValidMapLocation(Point3D location, Map map)
{
if (map == null || map == Map.Internal) return false;
// check the location relative to the current map to make sure it is valid
if (location.X < 0 || location.X > map.Width || location.Y < 0 || location.Y > map.Height)
{
return false;
}
return true;
}
public static bool IsValidMapLocation(Point2D location, Map map)
{
if (map == null || map == Map.Internal) return false;
// check the location relative to the current map to make sure it is valid
if (location.X < 0 || location.X > map.Width || location.Y < 0 || location.Y > map.Height)
{
return false;
}
return true;
}
private static WayPoint GetWaypoint(string waypointstr)
{
WayPoint waypoint = null;
// try parsing the waypoint name to determine the waypoint. object syntax is "SERIAL,sernumber" or "waypointname"
if (waypointstr != null && waypointstr.Length > 0)
{
string[] wayargs = BaseXmlSpawner.ParseString(waypointstr, 2, ",");
if (wayargs != null && wayargs.Length > 0)
{
// is this a SERIAL specification?
if (wayargs[0] == "SERIAL")
{
// look it up by serial
if (wayargs.Length > 1)
{
int sernum = -1;
try { sernum = (int)Convert.ToUInt64(wayargs[1].Substring(2), 16); }
catch { }
if (sernum > -1)
{
IEntity e = World.FindEntity(sernum);
if (e is WayPoint)
waypoint = e as WayPoint;
}
}
else
{
// improper serial format
}
}
else
{
// just look it up by name
Item wayitem = BaseXmlSpawner.FindItemByName(null, wayargs[0], "WayPoint");
if (wayitem is WayPoint)
{
waypoint = wayitem as WayPoint;
}
}
}
}
return waypoint;
}
private static bool HasTileSurface(Map map, int X, int Y, int Z)
{
if (map == null) return false;
StaticTile[] tiles = map.Tiles.GetStaticTiles(X, Y, true);
//List<Server.Tile> tiles = map.GetTilesAt(new Point2D(X, Y), true, true, true);
if (tiles == null) return false;
// go through the tiles and see if any are at the Z location
foreach (object o in tiles)
{
if (o is StaticTile)
{
StaticTile i = (StaticTile)o;
if ((i.Z + i.Height) == Z)
{
return true;
}
}
}
return false;
}
private bool CheckHoldSmartSpawning(object o)
{
if (o == null) return false;
// try looking this up in the lookup table
if (holdSmartSpawningHash == null)
{
holdSmartSpawningHash = new Dictionary<Type, PropertyInfo>();
}
PropertyInfo prop = null;
if (!holdSmartSpawningHash.TryGetValue(o.GetType(), out prop))
{
prop = o.GetType().GetProperty("HoldSmartSpawning");
// check to make sure the HoldSmartSpawning property for this object has the right type
if (prop != null && (!prop.CanRead || prop.PropertyType != typeof(bool)))
{
prop = null;
}
holdSmartSpawningHash[o.GetType()]=prop;
}
//else
//{
// look it up in the hash table
//prop = holdSmartSpawningHash[o.GetType()];
//}
if (prop != null)
{
try
{
return (bool)(prop.GetValue(o, null));
}
catch { }
}
return false;
}
public bool HasHoldSmartSpawning
{
get
{
// go through the spawn lists
foreach (SpawnObject so in m_SpawnObjects)
{
for (int x = 0; x < so.SpawnedObjects.Count; x++)
{
object o = so.SpawnedObjects[x];
if (CheckHoldSmartSpawning(o))
{
return true;
}
}
}
return false;
}
}
// if a non-null mob argument is passed, then check the canswim and cantwalk props to determine valid placement
public bool CanFit(int x, int y, int z, int height, bool checkBlocksFit, bool checkMobiles, bool requireSurface, Mobile mob)
{
Map map = this.Map;
if (DebugThis)
{
Console.WriteLine("CanFit mob {0}, map={1}", mob, map);
}
if (map == null || map == Map.Internal)
return false;
if (x < 0 || y < 0 || x >= map.Width || y >= map.Height)
return false;
bool hasSurface = false;
bool checkmob = false;
bool canswim = false;
bool cantwalk = false;
if (mob != null)
{
checkmob = true;
canswim = mob.CanSwim;
cantwalk = mob.CantWalk;
}
if (DebugThis)
{
Console.WriteLine("fitting mob {0} checkmob={1} swim={2} walk={3}", mob, checkmob, canswim, cantwalk);
}
LandTile lt = map.Tiles.GetLandTile(x, y);
int lowZ = 0, avgZ = 0, topZ = 0;
bool surface, impassable;
bool wet = false;
map.GetAverageZ(x, y, ref lowZ, ref avgZ, ref topZ);
TileFlag landFlags = TileData.LandTable[lt.ID & TileData.MaxLandValue].Flags;
if (DebugThis)
{
Console.WriteLine("landtile at {0},{1},{2} lowZ={3} avgZ={4} topZ={5}", x, y, z, lowZ, avgZ, topZ);
}
impassable = (landFlags & TileFlag.Impassable) != 0;
if (checkmob)
{
wet = (landFlags & TileFlag.Wet) != 0;
// dont allow wateronly creatures on land
if (cantwalk && !wet)
impassable = true;
// allow water creatures on water
if (canswim && wet)
{
impassable = false;
}
}
if (impassable && avgZ > z && (z + height) > lowZ)
return false;
else if (!impassable && z == avgZ && !lt.Ignored)
hasSurface = true;
if (DebugThis)
{
Console.WriteLine("landtile at {0},{1},{2} wet={3} impassable={4} hassurface={5}", x, y, z, wet, impassable, hasSurface);
}
StaticTile[] staticTiles = map.Tiles.GetStaticTiles(x, y, true);
for (int i = 0; i < staticTiles.Length; ++i)
{
ItemData id = TileData.ItemTable[staticTiles[i].ID & TileData.MaxItemValue];
surface = id.Surface;
impassable = id.Impassable;
if (checkmob)
{
wet = (id.Flags & TileFlag.Wet) != 0;
// dont allow wateronly creatures on land
if (cantwalk && !wet)
impassable = true;
// allow water creatures on water
if (canswim && wet)
{
surface = true;
impassable = false;
}
}
if ((surface || impassable) && (staticTiles[i].Z + id.CalcHeight) > z && (z + height) > staticTiles[i].Z)
return false;
else if (surface && !impassable && z == (staticTiles[i].Z + id.CalcHeight))
hasSurface = true;
}
if (DebugThis)
{
Console.WriteLine("statics hassurface={0}", hasSurface);
}
Sector sector = map.GetSector(x, y);
List<Item> items = sector.Items;
List<Mobile> mobs = sector.Mobiles;
for (int i = 0; i < items.Count; ++i)
{
Item item = items[i];
if (item.ItemID < 0x4000 && item.AtWorldPoint(x, y))
{
ItemData id = item.ItemData;
surface = id.Surface;
impassable = id.Impassable;
if (checkmob)
{
wet = (id.Flags & TileFlag.Wet) != 0;
// dont allow wateronly creatures on land
if (cantwalk && !wet)
impassable = true;
// allow water creatures on water
if (canswim && wet)
{
surface = true;
impassable = false;
}
}
if ((surface || impassable || (checkBlocksFit && item.BlocksFit)) && (item.Z + id.CalcHeight) > z && (z + height) > item.Z)
return false;
else if (surface && !impassable && !item.Movable && z == (item.Z + id.CalcHeight))
hasSurface = true;
}
}
if (DebugThis)
{
Console.WriteLine("items hassurface={0}", hasSurface);
}
if (checkMobiles)
{
for (int i = 0; i < mobs.Count; ++i)
{
Mobile m = mobs[i];
if (m.Location.X == x && m.Location.Y == y && (m.AccessLevel == AccessLevel.Player || !m.Hidden))
if ((m.Z + 16) > z && (z + height) > m.Z)
return false;
}
}
if (DebugThis)
{
Console.WriteLine("return requiresurface={0} hassurface={1}", requireSurface, hasSurface);
}
return !requireSurface || hasSurface;
}
public bool CanSpawnMobile(int x, int y, int z, Mobile mob)
{
if (DebugThis)
{
Console.WriteLine("CanSpawnMobile mob {0}", mob);
}
if (!Region.Find(new Point3D(x, y, z), this.Map).AllowSpawn())
return false;
return Map.CanFit(x, y, z, 16, false, true, true, mob);
}
public bool HasRegionPoints(Region r)
{
if (r != null && r.Area.Length > 0) return true;
else
return false;
}
public Rectangle2D SpawnerBounds
{
get
{
return new Rectangle2D(m_X, m_Y, m_Width + 1, m_Height + 1);
}
}
private void FindTileLocations(ref List<Point3D> locations, Map map, int startx, int starty, int width, int height, List<int> includetilelist, List<int> excludetilelist, TileFlag tileflag, bool checkitems, int spawnerZ)
{
if (width < 0 || height < 0 || map == null) return;
if (locations == null) locations = new List<Point3D>();
bool includetile;
bool excludetile;
for (int x = startx; x <= startx + width; x++)
{
for (int y = starty; y <= starty + height; y++)
{
bool allok=false;
Point3D p = Point3D.Zero;
// go through all of the tiles at the location and find those that are in the allowed tiles list
LandTile ltile = map.Tiles.GetLandTile(x, y);
TileFlag lflags = TileData.LandTable[ltile.ID & TileData.MaxLandValue].Flags;
// check the land tile
if (includetilelist != null && includetilelist.Count > 0)
{
includetile = includetilelist.Contains(ltile.ID & TileData.MaxLandValue);
}
else
{
includetile = true;
}
// non-excluded tiles must also be passable
if (excludetilelist != null && excludetilelist.Count > 0)
{
// also require the tile to be passable
excludetile = ((lflags & TileFlag.Impassable) != 0) || excludetilelist.Contains(ltile.ID & TileData.MaxLandValue);
}
else
{
excludetile = false;
}
if (includetile && !excludetile && ((lflags & tileflag) == tileflag))
{
//Console.WriteLine("found landtile {0}/{1} at {2},{3},{4}", ltile.ID, ltile.ID & 0x3fff, x, y, ltile.Z + ltile.Height);
p=new Point3D(x, y, ltile.Z + ltile.Height);
allok=true;
//locations.Add(new Point3D(x, y, ltile.Z + ltile.Height));
//continue;
}
StaticTile[] statictiles = map.Tiles.GetStaticTiles(x, y, true);
// check the static tiles
for (int i = 0; i < statictiles.Length; ++i)
{
StaticTile stile = statictiles[i];
TileFlag sflags = TileData.ItemTable[stile.ID & TileData.MaxItemValue].Flags;
if (includetilelist != null && includetilelist.Count > 0)
{
includetile = includetilelist.Contains(stile.ID & TileData.MaxItemValue);
}
else
{
includetile = true;
}
// non-excluded tiles must also be passable
if (excludetilelist != null && excludetilelist.Count > 0)
{
excludetile = ((sflags & TileFlag.Impassable) != 0) || excludetilelist.Contains(stile.ID & TileData.MaxItemValue);
}
else
{
excludetile = false;
}
if (includetile && !excludetile && ((sflags & tileflag) == tileflag))
{
//Console.WriteLine("found statictile {0}/{1} at {2},{3},{4}", stile.ID, stile.ID & 0x3fff, x, y, stile.Z + stile.Height);
if(p==Point3D.Zero)
p=new Point3D(x, y, stile.Z + stile.Height);
else if(!allok && (p.Z - spawnerZ) > Math.Abs(stile.Z - spawnerZ))
p=new Point3D(x, y, stile.Z + stile.Height);
else if(Math.Abs(ltile.Z - spawnerZ) > Math.Abs(stile.Z - spawnerZ)) //maggiore distanza rispetto allo statico dallo spawner
p=new Point3D(x, y, stile.Z + stile.Height);
allok=true;
//locations.Add(new Point3D(x, y, stile.Z + stile.Height));
//break;
}
}
if(checkitems)
{
IPooledEnumerable itemslist = map.GetItemsInRange(new Point3D(x, y, 0), 0);
// check the itemsid
foreach(Item i in itemslist)
{
if(i.ItemData.Impassable)
excludetile=true;
TileFlag iflags = TileData.ItemTable[i.ItemID & TileData.MaxItemValue].Flags;
if (includetilelist != null && includetilelist.Count > 0)
{
includetile = includetilelist.Contains(i.ItemID & TileData.MaxItemValue);
}
else
{
includetile = true;
}
if (excludetilelist != null && excludetilelist.Count > 0)
{
excludetile = excludetilelist.Contains(i.ItemID & TileData.MaxItemValue);
}
else
{
excludetile = false;
}
if (includetile && !excludetile && ((iflags & tileflag) == tileflag))
{
//prende precedenza su tutto il resto!
p=new Point3D(x, y, i.Z + i.ItemData.Height);
allok=true;
//locations.Add(new Point3D(x, y, i.Z + i.ItemData.Height));
//break;
}
}
itemslist.Free();
}
if(allok && !excludetile)
locations.Add(p);
}
}
}
private void FindRegionTileLocations(ref List<Point3D> locations, Region r, List<int> includetilelist, List<int> excludetilelist, TileFlag tileflag, bool checkitems, int spawnerZ)
{
if (r == null || r.Area == null) return;
int count = r.Area.Length;
if (locations == null) locations = new List<Point3D>();
// calculate fields of all rectangles (for probability calculating)
for (int n = 0; n < count; n++)
{
Rectangle3D ra = r.Area[n];
int sx = ra.Start.X;
int sy = ra.Start.Y;
int w = ra.Width;
int h = ra.Height;
// find all of the valid tile locations in the area
FindTileLocations(ref locations, r.Map, sx, sy, w, h, includetilelist, excludetilelist, tileflag, checkitems, spawnerZ);
}
}
// 2004.02.08 :: Omega Red
public Point2D GetRandomRegionPoint(Region r)
{
int count = r.Area.Length;
int[] FieldArray = new int[count];
int total = 0;
// calculate fields of all rectangles (for probability calculating)
for (int i = 0; i < count; i++)
{
Rectangle3D ra = r.Area[i];
total += (FieldArray[i] = (ra.Width * ra.Height));
}
int sum = 0;
int rnd = 0;
if (total > 0)
rnd = Utility.Random(total);
int x = 0;
int y = 0;
for (int i = 0; i < count; i++)
{
sum += FieldArray[i];
if (sum > rnd)
{
Rectangle3D r3d = r.Area[i];
if (r3d.Width >= 0)
x = r3d.Start.X + Utility.Random(r3d.Width);
if (r3d.Height >= 0)
y = r3d.Start.Y + Utility.Random(r3d.Height);
break;
}
}
return new Point2D(x, y);
}
// used for getting non-mobile spawn positions
public Point3D GetSpawnPosition(bool requiresurface)
{
// no pack spawning
return GetSpawnPosition(requiresurface, -1, Point3D.Zero, null, null);
}
// used for getting mobile spawn positions
public Point3D GetSpawnPosition(bool requiresurface, Mobile mob)
{
// no pack spawning
return GetSpawnPosition(requiresurface, -1, Point3D.Zero, null, mob);
}
// used for getting non-mobile spawn positions
public Point3D GetSpawnPosition(bool requiresurface, int packrange, Point3D packcoord, List<SpawnPositionInfo> spawnpositioning)
{
return GetSpawnPosition(requiresurface, packrange, packcoord, spawnpositioning, null);
}
public Point3D GetSpawnPosition(bool requiresurface, int packrange, Point3D packcoord, List<SpawnPositionInfo> spawnpositioning, Mobile mob)
{
Map map = Map;
if (map == null)
return Location;
// random positioning by default
SpawnPositionType positioning = SpawnPositionType.Random;
Mobile trigmob = null;
string[] positionargs = null;
List<int> includetilelist = null;
List<int> excludetilelist = null;
bool checkitems = false;
// restrictions on tile flags
TileFlag tileflag = TileFlag.None;
List<Point3D> locations = null;
int fillinc = 1;
int positionrange = 0;
string prefix = null;
List<Item> WayList = null;
int xinc = 0;
int yinc = 0;
int zinc = 0;
if (spawnpositioning != null)
{
foreach (SpawnPositionInfo s in spawnpositioning)
{
if (s == null) continue;
trigmob = s.trigMob;
positionargs = s.positionArgs;
// parse the possible args to the spawn position control keywords
switch (s.positionType)
{
case SpawnPositionType.Wet:
// syntax Wet
// find all of the wet tiles
tileflag |= TileFlag.Wet;
requiresurface = false;
break;
case SpawnPositionType.ItemID:
checkitems=true;
goto case SpawnPositionType.Tiles;
case SpawnPositionType.NoItemID:
checkitems=true;
goto case SpawnPositionType.NoTiles;
case SpawnPositionType.Tiles:
{
// syntax Tiles,start[,end]
// get the tiles in the range
requiresurface = false;
int start = -1;
int end = -1;
if (positionargs != null && positionargs.Length > 1)
{
try
{
start = int.Parse(positionargs[1]);
}
catch { }
}
if (positionargs != null && positionargs.Length > 2)
{
try
{
end = int.Parse(positionargs[2]);
}
catch { }
}
if (includetilelist == null)
{
includetilelist = new List<int>();
}
// add the tiles to the list
if (start > -1 && end < 0)
{
includetilelist.Add(start);
}
else
if (start > -1 && end > -1)
{
for (int j = start; j <= end; j++)
{
includetilelist.Add(j);
}
}
break;
}
case SpawnPositionType.NoTiles:
{
// syntax Tiles,start[,end]
// get the tiles in the range
requiresurface = false;
int start = -1;
int end = -1;
if (positionargs != null && positionargs.Length > 1)
{
try
{
start = int.Parse(positionargs[1]);
}
catch { }
}
if (positionargs != null && positionargs.Length > 2)
{
try
{
end = int.Parse(positionargs[2]);
}
catch { }
}
if (excludetilelist == null)
{
excludetilelist = new List<int>();
}
// add the tiles to the list
if (start > -1 && end < 0)
{
excludetilelist.Add(start);
}
else
if (start > -1 && end > -1)
{
for (int j = start; j <= end; j++)
{
excludetilelist.Add(j);
}
}
break;
}
case SpawnPositionType.RowFill:
case SpawnPositionType.ColFill:
case SpawnPositionType.Perimeter:
// syntax XFILL[,inc]
// syntax YFILL[,inc]
// syntax EDGE[,inc]
positioning = s.positionType;
if (positionargs != null && positionargs.Length > 1)
{
try
{
fillinc = int.Parse(positionargs[1]);
}
catch { }
}
break;
case SpawnPositionType.RelXY:
case SpawnPositionType.DeltaLocation:
case SpawnPositionType.Location:
// syntax RELXY,xinc,yinc[,zinc]
// syntax XY,x,y[,z]
// syntax DXY,dx,dy[,dz]
positioning = s.positionType;
if (positionargs != null && positionargs.Length > 2)
{
try
{
xinc = int.Parse(positionargs[1]);
yinc = int.Parse(positionargs[2]);
}
catch { }
}
if (positionargs != null && positionargs.Length > 3)
{
try
{
zinc = int.Parse(positionargs[3]);
}
catch { }
}
break;
case SpawnPositionType.Waypoint:
// syntax WAYPOINT,prefix[,range]
positioning = s.positionType;
if (positionargs != null && positionargs.Length > 1)
{
prefix = positionargs[1];
}
if (positionargs != null && positionargs.Length > 2)
{
try
{
positionrange = int.Parse(positionargs[2]);
}
catch { }
}
// find a list of items that match the waypoint prefix
if (prefix != null)
{
// see if there is an existing hashtable for the waypoint lists
if (spawnPositionWayTable == null)
{
spawnPositionWayTable = new Dictionary<string, List<Item>>();
}
// try to find the waypoint list in the local table
//WayList = spawnPositionWayTable[prefix];
// no existing list so create a new one
if (!spawnPositionWayTable.TryGetValue(prefix, out WayList) || WayList == null)
{
WayList = new List<Item>();
foreach (Item i in World.Items.Values)
{
if (i is WayPoint && !string.IsNullOrEmpty(i.Name) && i.Map == Map && i.Name == prefix)
{
// add it to the list of items
WayList.Add(i);
}
}
// add the new list to the local table
spawnPositionWayTable[prefix] = WayList;
}
}
break;
case SpawnPositionType.Player:
// syntax PLAYER[,range]
positioning = s.positionType;
if (positionargs != null && positionargs.Length > 1)
{
try
{
positionrange = int.Parse(positionargs[1]);
}
catch { }
}
break;
}
}
}
// precalculate tile locations if they have been specified
if (includetilelist != null || excludetilelist != null || tileflag != TileFlag.None)
{
if (m_Region != null && HasRegionPoints(m_Region))
{
FindRegionTileLocations(ref locations, m_Region, includetilelist, excludetilelist, tileflag, checkitems, this.Z);
}
else if (positioning == SpawnPositionType.Random)
{
FindTileLocations(ref locations, this.Map, m_X, m_Y, m_Width, m_Height, includetilelist, excludetilelist, tileflag, checkitems, this.Z);
}
}
// Try 10 times to find a Spawnable location.
// trace profiling indicates that this is a major bottleneck
for (int i = 0; i < 10; i++)
{
int x = this.X;
int y = this.Y;
int z = Z;
int defaultZ = this.Z;
if (packrange >= 0 && packcoord != Point3D.Zero)
{
defaultZ = packcoord.Z;
}
if (packrange >= 0 && packcoord != Point3D.Zero)
{
// find a random coord relative to the packcoord
x = packcoord.X - packrange + Utility.Random(packrange * 2 + 1);
y = packcoord.Y - packrange + Utility.Random(packrange * 2 + 1);
}
else
if (m_Region != null && HasRegionPoints(m_Region)) // 2004.02.08 :: Omega Red
{
// if region spawning is selected then use that to find an x,y loc instead of the spawn box
if (includetilelist != null || excludetilelist != null || tileflag != TileFlag.None)
{
// use the precalculated tile locations
if (locations != null && locations.Count > 0)
{
Point3D p = locations[Utility.Random(locations.Count)];
x = p.X;
y = p.Y;
defaultZ = p.Z;
}
}
else
{
Point2D p = GetRandomRegionPoint(m_Region);
x = p.X;
y = p.Y;
}
}
else
{
switch (positioning)
{
case SpawnPositionType.Random:
if (includetilelist != null || excludetilelist != null || tileflag != TileFlag.None)
{
if (locations != null && locations.Count > 0)
{
Point3D p = locations[Utility.Random(locations.Count)];
x = p.X;
y = p.Y;
defaultZ = p.Z;
}
}
else
{
if (m_Width > 0)
x = m_X + Utility.Random(m_Width + 1);
if (m_Height > 0)
y = m_Y + Utility.Random(m_Height + 1);
}
break;
case SpawnPositionType.RelXY:
x = mostRecentSpawnPosition.X + xinc;
y = mostRecentSpawnPosition.Y + yinc;
defaultZ = mostRecentSpawnPosition.Z + zinc;
break;
case SpawnPositionType.DeltaLocation:
x = this.X + xinc;
y = this.Y + yinc;
defaultZ = this.Z + zinc;
break;
case SpawnPositionType.Location:
x = xinc;
y = yinc;
defaultZ = zinc;
break;
case SpawnPositionType.RowFill:
x = mostRecentSpawnPosition.X + fillinc;
y = mostRecentSpawnPosition.Y;
if (x < m_X)
{
x = m_X;
}
if (y < m_Y)
{
y = m_Y;
}
if (x > m_X + m_Width)
{
x = m_X + (x - m_X - m_Width - 1);
y++;
}
if (y > m_Y + m_Height)
{
y = m_Y;
}
break;
case SpawnPositionType.ColFill:
x = mostRecentSpawnPosition.X;
y = mostRecentSpawnPosition.Y + fillinc;
if (x < m_X)
{
x = m_X;
}
if (y < m_Y)
{
y = m_Y;
}
if (y > m_Y + m_Height)
{
y = m_Y + (y - m_Y - m_Height - 1);
x++;
}
if (x > m_X + m_Width)
{
x = m_X;
}
break;
case SpawnPositionType.Perimeter:
x = mostRecentSpawnPosition.X;
y = mostRecentSpawnPosition.Y;
// if the point is not on the perimeter, reset it to the corner
if (x != m_X && x != m_X + m_Width && y != m_Y && y != m_Y + m_Height)
{
x = m_X;
y = m_Y;
}
if (y == m_Y && x < m_X + m_Width) x += fillinc;
else
if (y == m_Y + m_Height && x > m_X) x -= fillinc;
else
if (x == m_X && y > m_Y) y -= fillinc;
else
if (x == m_X + m_Width && y < m_Y + m_Height) y += fillinc;
if (x > m_X + m_Width)
{
x = m_X + m_Width;
}
if (y > m_Y + m_Height)
{
y = m_Y + m_Height;
}
if (x < m_X)
{
x = m_X;
}
if (y < m_Y)
{
y = m_Y;
}
break;
case SpawnPositionType.Player:
if (trigmob != null)
{
x = trigmob.Location.X;
y = trigmob.Location.Y;
if (positionrange > 0)
{
x += Utility.Random(positionrange * 2 + 1) - positionrange;
y += Utility.Random(positionrange * 2 + 1) - positionrange;
}
}
break;
case SpawnPositionType.Waypoint:
// pick an item randomly from the waylist
if (WayList != null && WayList.Count > 0)
{
int index = Utility.Random(WayList.Count);
Item waypoint = WayList[index];
if (waypoint != null)
{
x = waypoint.Location.X;
y = waypoint.Location.Y;
defaultZ = waypoint.Location.Z;
if (positionrange > 0)
{
x += Utility.Random(positionrange * 2 + 1) - positionrange;
y += Utility.Random(positionrange * 2 + 1) - positionrange;
}
}
}
break;
}
mostRecentSpawnPosition = new Point3D(x, y, defaultZ);
}
// skip invalid points
if (x < 0 || y < 0 || (x == 0 && y == 0)) continue;
// try to find a valid spawn location using the z coord of the spawner
// relax the normal surface requirement for mobiles if the flag is set
bool fit = false;
if (requiresurface)
{
fit = CanSpawnMobile(x, y, defaultZ, mob);
}
else
{
fit = Map.CanFit(x, y, defaultZ, SpawnFitSize, true, false, false);
}
// if that fails then try to find a valid z coord
if (fit)
{
return new Point3D(x, y, defaultZ);
}
else
{
z = Map.GetAverageZ(x, y);
if (requiresurface)
{
fit = CanSpawnMobile(x, y, z, mob);
}
else
{
fit = Map.CanFit(x, y, z, SpawnFitSize, true, false, false);
}
if (fit)
{
return new Point3D(x, y, z);
}
}
}
if (packrange >= 0 && packcoord != Point3D.Zero)
{
return packcoord;
}
else
{
return this.Location;
}
}
public int GetCreatureMax(int index)
{
Defrag(false);
if (m_SpawnObjects == null) return 0;
return m_SpawnObjects[index].MaxCount;
}
private void DeleteFromList(List<object> list)
{
if (list == null) return;
foreach (object o in list)
{
if (o is Item)
((Item)o).Delete();
else if (o is Mobile)
((Mobile)o).Delete();
}
}
private void DeleteFromList(List<Item> listi, List<Mobile> listm)
{
if (listi != null)
{
var i = listi.Count;
while (--i >= 0)
{
if (i < listi.Count && listi[i] != null)
{
try
{
listi[i].Delete();
}
catch
{ }
}
}
listi.Clear();
}
if(listm != null)
{
var i = listm.Count;
while (--i >= 0)
{
if (i < listm.Count && listm[i] != null)
{
try
{
listm[i].Delete();
}
catch
{ }
}
}
listm.Clear();
}
}
public void RemoveSpawnObjects()
{
if (m_SpawnObjects == null) return;
Defrag(false);
ClearTags(true);
List<object> deletelist = new List<object>();
foreach (SpawnObject so in m_SpawnObjects)
{
for (int i = 0; i < so.SpawnedObjects.Count; ++i)
{
object o = so.SpawnedObjects[i];
if (o is Item || o is Mobile) deletelist.Add(o);
}
}
DeleteFromList(deletelist);
// Defrag again
Defrag(false);
}
public void RemoveSpawnObjects(SpawnObject so)
{
if (so == null) return;
Defrag(false);
List<object> deletelist = new List<object>();
for (int i = 0; i < so.SpawnedObjects.Count; ++i)
{
object o = so.SpawnedObjects[i];
if (o is Item || o is Mobile) deletelist.Add(o);
}
DeleteFromList(deletelist);
// Defrag again
Defrag(false);
}
public void ClearSubgroup(int subgroup)
{
if (m_SpawnObjects == null) return;
Defrag(false);
ClearTags(true);
List<object> deletelist = new List<object>();
foreach (SpawnObject so in m_SpawnObjects)
{
if (so.SubGroup != subgroup || !so.ClearOnAdvance) continue;
for (int i = 0; i < so.SpawnedObjects.Count; ++i)
{
object o = so.SpawnedObjects[i];
if (o is Item || o is Mobile) deletelist.Add(o);
}
}
DeleteFromList(deletelist);
// Defrag again
Defrag(false);
}
// used to optimize smart spawning by removing all objects except those that have hold smartspawning
public void SmartRemoveSpawnObjects()
{
if (m_SpawnObjects == null) return;
Defrag(false);
ClearTags(true);
List<object> deletelist = new List<object>();
foreach (SpawnObject so in m_SpawnObjects)
{
for (int i = 0; i < so.SpawnedObjects.Count; ++i)
{
object o = so.SpawnedObjects[i];
// new optimization for smart spawning to remove all objects except those with hold smartspawning enabled
if (CheckHoldSmartSpawning(o))
{
continue;
}
if (o is Item || o is Mobile) deletelist.Add(o);
}
}
DeleteFromList(deletelist);
// Defrag again
Defrag(false);
}
public void AddSpawnObject(string SpawnObjectName)
{
if (m_SpawnObjects == null) return;
Defrag(false);
// Find the spawn object and increment its count by one
foreach (SpawnObject so in m_SpawnObjects)
{
if (so.TypeName.ToUpper() == SpawnObjectName.ToUpper())
{
// Add one to the total count
m_Count++;
// Increment the max count for the current creature
so.ActualMaxCount++;
//only spawn them immediately if the spawner is running
if (Running)
Spawn(SpawnObjectName, false, 0);
}
}
InvalidateProperties();
}
public void DeleteSpawnObject(Mobile from, string SpawnObjectName)
{
bool WasRunning = m_Running;
try
{
// Stop spawning for a moment
Stop();
// Clean up any spawns marked as deleted
Defrag(false);
// Keep a reference to the spawn object
SpawnObject TheSpawn = null;
// Find the spawn object and increment its count by one
foreach (SpawnObject so in m_SpawnObjects)
{
if (so.TypeName.ToUpper() == SpawnObjectName.ToUpper())
{
// Set the spawn
TheSpawn = so;
break;
}
}
// Was the spawn object found
if (TheSpawn != null)
{
bool delete_this_entry = false;
// Decrement the max count for the current creature
TheSpawn.ActualMaxCount--;
// Make sure the spawn count does not go negative
if (TheSpawn.MaxCount < 0)
{
TheSpawn.MaxCount = 0;
delete_this_entry = true;
}
if (!delete_this_entry)
{
// Subtract one to the total count
m_Count--;
}
// Make sure the count does not go negative
if (m_Count < 0)
{
m_Count = 0;
}
List<object> deletelist = new List<object>();
// Remove any spawns over the count
while (TheSpawn.SpawnedObjects != null && TheSpawn.SpawnedObjects.Count > 0 && TheSpawn.SpawnedObjects.Count > TheSpawn.MaxCount)
{
object o = TheSpawn.SpawnedObjects[0];
// Delete the object
if (o is Item || o is Mobile) deletelist.Add(o);
TheSpawn.SpawnedObjects.Remove(o);
}
DeleteFromList(deletelist);
// Check if the spawn object should be removed
//if( TheSpawn.MaxCount < 1 )
if (delete_this_entry)
{
m_SpawnObjects.Remove(TheSpawn);
if (from != null)
CommandLogging.WriteLine(from, "{0} {1} removed from XmlSpawner {2} '{3}' [{4}, {5}] ({6}) : {7}", from.AccessLevel, CommandLogging.Format(from), Serial, Name, GetWorldLocation().X, GetWorldLocation().Y, Map, SpawnObjectName);
}
}
InvalidateProperties();
}
finally
{
if (WasRunning)
Start();
}
}
public void RemoveSpawnObject(SpawnObject so)
{
if (m_SpawnObjects.Contains(so))
{
m_SpawnObjects.Remove(so);
}
}
#endregion
#region Object Creation
public static object CreateObject(Type type, string itemtypestring)
{
return CreateObject(type, itemtypestring, true);
}
public static object CreateObject(Type type, string itemtypestring, bool requireconstructable)
{
// look for constructor arguments to be passed to it with the syntax type,arg1,arg2,.../
string[] typewordargs = BaseXmlSpawner.ParseObjectArgs(itemtypestring);
return CreateObject(type, typewordargs, requireconstructable, false);
}
public static object CreateObject(Type type, string itemtypestring, bool requireconstructable, bool requireattachable)
{
// look for constructor arguments to be passed to it with the syntax type,arg1,arg2,.../
string[] typewordargs = BaseXmlSpawner.ParseObjectArgs(itemtypestring);
return CreateObject(type, typewordargs, requireconstructable, requireattachable);
}
public static object CreateObject(Type type, string[] typewordargs, bool requireconstructable, bool requireattachable)
{
if (type == null) return null;
object o = null;
int typearglen = 0;
if (typewordargs != null)
typearglen = typewordargs.Length;
// ok, there are args in the typename, so we need to invoke the proper constructor
ConstructorInfo[] ctors = type.GetConstructors();
if (ctors == null) return null;
// go through all the constructors for this type
for (int i = 0; i < ctors.Length; ++i)
{
ConstructorInfo ctor = ctors[i];
if (ctor == null) continue;
// if both requireconstructable and requireattachable are true, then allow either condition
#if(RESTRICTCONSTRUCTABLE)
if (!(requireconstructable && Add.IsConstructable(ctor,requester)) && !(requireattachable && XmlAttach.IsAttachable(ctor, requester)))
continue;
#else
if (!(requireconstructable && IsConstructable(ctor)) && !(requireattachable && XmlAttach.IsAttachable(ctor)))
continue;
#endif
// check the parameter list of the constructor
ParameterInfo[] paramList = ctor.GetParameters();
// and compare with the argument list provided
if (paramList != null && typearglen == paramList.Length)
{
// this is a constructor that takes args and matches the number of args passed in to CreateObject
if (paramList.Length > 0)
{
object[] paramValues = null;
try
{
paramValues = Add.ParseValues(paramList, typewordargs);
}
catch { }
if (paramValues == null)
continue;
// ok, have a match on args, so try to construct it
try
{
o = Activator.CreateInstance(type, paramValues);
}
catch { }
}
else
{
// zero argument constructor
try
{
o = Activator.CreateInstance(type);
}
catch { }
}
// successfully constructed the object, otherwise try another matching constructor
if (o != null) break;
}
}
return o;
}
#endregion
#region Timers
private static void DoGlobalSectorTimer(TimeSpan delay)
{
if (m_GlobalSectorTimer != null)
m_GlobalSectorTimer.Stop();
m_GlobalSectorTimer = new GlobalSectorTimer(delay);
m_GlobalSectorTimer.Start();
}
private class GlobalSectorTimer : Timer
{
public GlobalSectorTimer(TimeSpan delay)
: base(delay, delay)
{
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()
{
// check the sectors
// check all active players
if (NetState.Instances != null)
{
foreach (NetState state in NetState.Instances)
{
Mobile m = state.Mobile;
if (m != null && (m.AccessLevel <= SmartSpawnAccessLevel || !m.Hidden))
{
// activate any spawner in the sector they are in
if (m.Map != null && m.Map != Map.Internal)
{
Sector s = m.Map.GetSector(m.Location);
if (s != null && GlobalSectorTable[m.Map.MapID] != null)
{
List<XmlSpawner> spawnerlist;// = GlobalSectorTable[m.Map.MapID][s];
if (GlobalSectorTable[m.Map.MapID].TryGetValue(s, out spawnerlist) && spawnerlist != null)
{
foreach (XmlSpawner spawner in spawnerlist)
{
if (spawner != null && !spawner.Deleted && spawner.Running && spawner.SmartSpawning && spawner.IsInactivated)
{
spawner.SmartRespawn();
}
}
}
}
}
}
}
}
}
}
public void DoSectorTimer(TimeSpan delay)
{
if (m_SectorTimer != null)
m_SectorTimer.Stop();
m_SectorTimer = new SectorTimer(this, delay);
m_SectorTimer.Start();
}
private class SectorTimer : Timer
{
private XmlSpawner m_Spawner;
public SectorTimer(XmlSpawner spawner, TimeSpan delay)
: base(delay, delay)
{
Priority = TimerPriority.OneSecond;
m_Spawner = spawner;
}
protected override void OnTick()
{
// check the sectors
if (m_Spawner != null && !m_Spawner.Deleted && m_Spawner.Running && m_Spawner.IsInactivated)
{
if (m_Spawner.SmartSpawning)
{
if (m_Spawner.HasActiveSectors)
{
Stop();
m_Spawner.SmartRespawn();
}
}
else
{
Stop();
m_Spawner.IsInactivated = false;
}
}
else
{
Stop();
}
}
}
private class WarnTimer2 : Timer
{
private List<XmlSpawner.WarnTimer2.WarnEntry2> m_List;
private class WarnEntry2
{
public Point3D m_Point;
public Map m_Map;
public string m_Name;
public WarnEntry2(Point3D p, Map map, string name)
{
m_Point = p;
m_Map = map;
m_Name = name;
}
}
public WarnTimer2()
: base(TimeSpan.FromSeconds(1.0))
{
m_List = new List<XmlSpawner.WarnTimer2.WarnEntry2>();
Start();
}
public void Add(Point3D p, Map map, string name)
{
m_List.Add(new WarnEntry2(p, map, name));
}
protected override void OnTick()
{
try
{
Console.WriteLine("Warning: {0} bad spawns detected, logged: 'badspawn.log'", m_List.Count);
using (StreamWriter op = new StreamWriter("badspawn.log", true))
{
op.WriteLine("# Bad spawns : {0}", DateTime.UtcNow);
op.WriteLine("# Format: X Y Z F Name");
op.WriteLine();
foreach (WarnEntry2 e in m_List)
op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}", e.m_Point.X, e.m_Point.Y, e.m_Point.Z, e.m_Map, e.m_Name);
op.WriteLine();
op.WriteLine();
}
}
catch
{ }
}
}
public void DoTimer()
{
if (!m_Running)
return;
int minSeconds = (int)m_MinDelay.TotalSeconds;
int maxSeconds = (int)m_MaxDelay.TotalSeconds;
TimeSpan delay = TimeSpan.FromSeconds(Utility.RandomMinMax(minSeconds, maxSeconds));
DoTimer(delay);
}
public void DoTimer(TimeSpan delay)
{
if (!m_Running)
return;
m_End = DateTime.UtcNow + delay;
if (m_Timer != null)
m_Timer.Stop();
m_Timer = new SpawnerTimer(this, delay);
m_Timer.Start();
}
public void DoTimer2(TimeSpan delay)
{
m_DurEnd = DateTime.UtcNow + delay;
if (m_Duration > TimeSpan.FromMinutes(0) || (m_durActivated == true))
{
if (m_DurTimer != null)
m_DurTimer.Stop();
m_DurTimer = new InternalTimer(this, delay);
m_DurTimer.Start();
m_durActivated = true;
}
}
public void DoTimer3(TimeSpan delay)
{
// if ( !m_proximityActivated )
// return;
m_RefractEnd = DateTime.UtcNow + delay;
m_refractActivated = true;
if (m_RefractoryTimer != null)
m_RefractoryTimer.Stop();
m_RefractoryTimer = new InternalTimer3(this, delay);
m_RefractoryTimer.Start();
}
// added the duration timer that begins on spawning
private class InternalTimer : Timer
{
private XmlSpawner m_spawner;
public InternalTimer(XmlSpawner spawner, TimeSpan delay)
: base(delay)
{
Priority = TimerPriority.OneSecond;
m_spawner = spawner;
}
protected override void OnTick()
{
if (m_spawner != null && !m_spawner.Deleted)
{
m_spawner.RemoveSpawnObjects();
m_spawner.m_durActivated = false;
}
}
}
private class SpawnerTimer : Timer
{
private XmlSpawner m_Spawner;
public SpawnerTimer(XmlSpawner spawner, TimeSpan delay)
: base(delay)
{
// reduce timer priority if spawner is inactivated
if (spawner.IsInactivated)
{
Priority = TimerPriority.FiveSeconds;
}
else
{
Priority = spawner.BasePriority;
}
m_Spawner = spawner;
}
protected override void OnTick()
{
if (m_Spawner != null && !m_Spawner.Deleted)
{
m_Spawner.OnTick();
}
}
}
// added the refractory timer that begins on proximity triggering
private class InternalTimer3 : Timer
{
private XmlSpawner m_spawner;
public InternalTimer3(XmlSpawner spawner, TimeSpan delay)
: base(delay)
{
Priority = TimerPriority.OneSecond;
m_spawner = spawner;
}
protected override void OnTick()
{
if (m_spawner != null && !m_spawner.Deleted)
{
// reenable triggering
m_spawner.m_refractActivated = false;
}
}
}
#endregion
#region Serialization
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)31); // version
// version 31
writer.Write(m_DisableGlobalAutoReset);
// Version 30
writer.Write(m_AllowNPCTriggering);
// Version 29
if (m_SpawnObjects != null)
{
writer.Write(m_SpawnObjects.Count);
for (int i = 0; i < m_SpawnObjects.Count; ++i)
{
// Write the spawns per tick value
writer.Write(m_SpawnObjects[i].SpawnsPerTick);
}
}
else
{
// empty spawner
writer.Write((int)0);
}
// Version 28
if (m_SpawnObjects != null)
{
for (int i = 0; i < m_SpawnObjects.Count; ++i)
{
// Write the pack range value
writer.Write(m_SpawnObjects[i].PackRange);
}
}
// Version 27
if (m_SpawnObjects != null)
{
for (int i = 0; i < m_SpawnObjects.Count; ++i)
{
// Write the disable spawn flag
writer.Write(m_SpawnObjects[i].Disabled);
}
}
// Version 26
writer.Write(m_SpawnOnTrigger);
writer.Write(m_FirstModified);
writer.Write(m_LastModified);
// Version 25
// eliminated the textentrybook serialization (they autodelete on deser now)
// Version 24
if (m_SpawnObjects != null)
{
for (int i = 0; i < m_SpawnObjects.Count; ++i)
{
SpawnObject so = m_SpawnObjects[i];
// Write the restrict kills flag
writer.Write(so.RestrictKillsToSubgroup);
// Write the clear on advance flag
writer.Write(so.ClearOnAdvance);
// Write the mindelay
writer.Write(so.MinDelay);
// Write the maxdelay
writer.Write(so.MaxDelay);
// write the next spawn time for the subgrop
writer.WriteDeltaTime(so.NextSpawn);
}
}
if (m_ShowBoundsItems != null && m_ShowBoundsItems.Count > 0)
{
writer.Write(true);
writer.WriteItemList<Static>(m_ShowBoundsItems);
}
else
{
// empty showbounds item list
writer.Write(false);
}
// Version 23
writer.Write(IsInactivated);
writer.Write(m_SmartSpawning);
// Version 22
writer.Write(m_SkillTrigger);
writer.Write((int)m_skill_that_triggered);
writer.Write(m_FreeRun);
writer.Write(m_mob_who_triggered);
// Version 21
writer.Write(m_DespawnTime);
// Version 20
if (m_SpawnObjects != null)
{
for (int i = 0; i < m_SpawnObjects.Count; ++i)
{
// Write the requiresurface flag
writer.Write(m_SpawnObjects[i].RequireSurface);
}
}
// Version 19
writer.Write(m_ConfigFile);
writer.Write(m_OnHold);
writer.Write(m_HoldSequence);
writer.Write(m_FirstModifiedBy);
writer.Write(m_LastModifiedBy);
// compute the number of tags to save
int tagcount = 0;
for (int i = 0; i < m_KeywordTagList.Count; i++)
{
// only save WAIT type keywords or other keywords that have the save flag set
if ((m_KeywordTagList[i].Flags & BaseXmlSpawner.KeywordFlags.Serialize) != 0)
tagcount++;
}
writer.Write(tagcount);
// and write them out
for (int i = 0; i < m_KeywordTagList.Count; i++)
{
if ((m_KeywordTagList[i].Flags & BaseXmlSpawner.KeywordFlags.Serialize) != 0)
{
m_KeywordTagList[i].Serialize(writer);
}
}
// Version 18
writer.Write(m_AllowGhostTriggering);
// Version 17
// removed in version 25
//writer.Write( m_TextEntryBook);
// Version 16
writer.Write(m_SequentialSpawning);
// write out the remaining time until sequential reset
writer.Write(NextSeqReset);
// Write the spawn object list
if (m_SpawnObjects != null)
{
for (int i = 0; i < m_SpawnObjects.Count; ++i)
{
SpawnObject so = m_SpawnObjects[i];
// Write the subgroup and sequential reset time
writer.Write(so.SubGroup);
writer.Write(so.SequentialResetTime);
writer.Write(so.SequentialResetTo);
writer.Write(so.KillsNeeded);
}
}
writer.Write(m_RegionName); // 2004.02.08 :: Omega Red
// Version 15
writer.Write(m_ExternalTriggering);
writer.Write(m_ExternalTrigger);
// Version 14
writer.Write(m_NoItemTriggerName);
// Version 13
writer.Write(m_GumpState);
// Version 12
int todtype = (int)m_TODMode;
writer.Write(todtype);
// Version 11
writer.Write(m_KillReset);
writer.Write(m_skipped);
writer.Write(m_spawncheck);
// Version 10
writer.Write(m_SetPropertyItem);
// Version 9
writer.Write(m_TriggerProbability);
// Version 8
writer.Write(m_MobPropertyName);
writer.Write(m_MobTriggerName);
writer.Write(m_PlayerPropertyName);
// Version 7
writer.Write(m_SpeechTrigger);
// Version 6
writer.Write(m_ItemTriggerName);
// Version 5
writer.Write(m_ProximityTriggerMessage);
writer.Write(m_ObjectPropertyItem);
writer.Write(m_ObjectPropertyName);
writer.Write(m_killcount);
// Version 4
writer.Write(m_ProximityRange);
writer.Write(m_ProximityTriggerSound);
writer.Write(m_proximityActivated);
writer.Write(m_durActivated);
writer.Write(m_refractActivated);
writer.Write(m_StackAmount);
writer.Write(m_TODStart);
writer.Write(m_TODEnd);
writer.Write(m_MinRefractory);
writer.Write(m_MaxRefractory);
if (m_refractActivated)
writer.Write(m_RefractEnd - DateTime.UtcNow);
if (m_durActivated)
writer.Write(m_DurEnd - DateTime.UtcNow);
// Version 3
writer.Write(m_ShowContainerStatic);
// Version 2
writer.Write(m_Duration);
// Version 1
writer.Write(m_UniqueId);
writer.Write(m_HomeRangeIsRelative);
// Version 0
writer.Write(m_Name);
writer.Write(m_X);
writer.Write(m_Y);
writer.Write(m_Width);
writer.Write(m_Height);
writer.Write(m_WayPoint);
writer.Write(m_Group);
writer.Write(m_MinDelay);
writer.Write(m_MaxDelay);
writer.Write(m_Count);
writer.Write(m_Team);
writer.Write(m_HomeRange);
writer.Write(m_Running);
if (m_Running)
writer.Write(m_End - DateTime.UtcNow);
// Write the spawn object list
int nso = 0;
if (m_SpawnObjects != null) nso = m_SpawnObjects.Count;
writer.Write(nso);
for (int i = 0; i < nso; ++i)
{
SpawnObject so = m_SpawnObjects[i];
// Write the type and maximum count
writer.Write((string)so.TypeName);
writer.Write((int)so.ActualMaxCount);
// Write the spawned object information
writer.Write(so.SpawnedObjects.Count);
for (int x = 0; x < so.SpawnedObjects.Count; ++x)
{
object o = so.SpawnedObjects[x];
if (o is Item)
writer.Write((Item)o);
else if (o is Mobile)
writer.Write((Mobile)o);
else
{
// if this is a keyword tag then add some more info
if (o is BaseXmlSpawner.KeywordTag)
{
writer.Write(-1 * ((BaseXmlSpawner.KeywordTag)o).Serial - 2);
}
else
{
writer.Write(Serial.MinusOne);
}
}
}
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
bool haveproximityrange = false;
bool hasnewobjectinfo = false;
int tmpSpawnListSize = 0;
List<int> tmpSubGroup = null;
List<double> tmpSequentialResetTime = null;
List<int> tmpSequentialResetTo = null;
List<int> tmpKillsNeeded = null;
List<bool> tmpRequireSurface = null;
List<bool> tmpRestrictKillsToSubgroup = null;
List<bool> tmpClearOnAdvance = null;
List<double> tmpMinDelay = null;
List<double> tmpMaxDelay = null;
List<DateTime> tmpNextSpawn = null;
List<bool> tmpDisableSpawn = null;
List<int> tmpPackRange = null;
List<int> tmpSpawnsPer = null;
switch (version)
{
case 31:
{
m_DisableGlobalAutoReset = reader.ReadBool();
goto case 30;
}
case 30:
{
m_AllowNPCTriggering = reader.ReadBool();
goto case 29;
}
case 29:
{
tmpSpawnListSize = reader.ReadInt();
tmpSpawnsPer = new List<int>(tmpSpawnListSize);
for (int i = 0; i < tmpSpawnListSize; ++i)
{
int spawnsper = reader.ReadInt();
tmpSpawnsPer.Add(spawnsper);
}
goto case 28;
}
case 28:
{
if (version < 29)
tmpSpawnListSize = reader.ReadInt();
tmpPackRange = new List<int>(tmpSpawnListSize);
for (int i = 0; i < tmpSpawnListSize; ++i)
{
int packrange = reader.ReadInt();
tmpPackRange.Add(packrange);
}
goto case 27;
}
case 27:
{
if (version < 28)
tmpSpawnListSize = reader.ReadInt();
tmpDisableSpawn = new List<bool>(tmpSpawnListSize);
for (int i = 0; i < tmpSpawnListSize; ++i)
{
bool disablespawn = reader.ReadBool();
tmpDisableSpawn.Add(disablespawn);
}
goto case 26;
}
case 26:
{
m_SpawnOnTrigger = reader.ReadBool();
m_FirstModified = reader.ReadDateTime();
m_LastModified = reader.ReadDateTime();
goto case 25;
}
case 25:
{
goto case 24;
}
case 24:
{
if (version < 27)
tmpSpawnListSize = reader.ReadInt();
tmpRestrictKillsToSubgroup = new List<bool>(tmpSpawnListSize);
tmpClearOnAdvance = new List<bool>(tmpSpawnListSize);
tmpMinDelay = new List<double>(tmpSpawnListSize);
tmpMaxDelay = new List<double>(tmpSpawnListSize);
tmpNextSpawn = new List<DateTime>(tmpSpawnListSize);
for (int i = 0; i < tmpSpawnListSize; ++i)
{
bool restrictkills = reader.ReadBool();
bool clearadvance = reader.ReadBool();
double mind = reader.ReadDouble();
double maxd = reader.ReadDouble();
DateTime nextspawn = reader.ReadDeltaTime();
tmpRestrictKillsToSubgroup.Add(restrictkills);
tmpClearOnAdvance.Add(clearadvance);
tmpMinDelay.Add(mind);
tmpMaxDelay.Add(maxd);
tmpNextSpawn.Add(nextspawn);
}
bool hasitems = reader.ReadBool();
if (hasitems)
{
m_ShowBoundsItems = reader.ReadStrongItemList<Static>();
}
goto case 23;
}
case 23:
{
IsInactivated = reader.ReadBool();
SmartSpawning = reader.ReadBool();
goto case 22;
}
case 22:
{
SkillTrigger = reader.ReadString(); // note this will also register the skill
m_skill_that_triggered = (SkillName)reader.ReadInt();
m_FreeRun = reader.ReadBool();
m_mob_who_triggered = reader.ReadMobile();
goto case 21;
}
case 21:
{
m_DespawnTime = reader.ReadTimeSpan();
goto case 20;
}
case 20:
{
if (version < 24)
tmpSpawnListSize = reader.ReadInt();
tmpRequireSurface = new List<bool>(tmpSpawnListSize);
for (int i = 0; i < tmpSpawnListSize; ++i)
{
bool requiresurface = reader.ReadBool();
tmpRequireSurface.Add(requiresurface);
}
goto case 19;
}
case 19:
{
m_ConfigFile = reader.ReadString();
m_OnHold = reader.ReadBool();
m_HoldSequence = reader.ReadBool();
m_FirstModifiedBy = reader.ReadString();
m_LastModifiedBy = reader.ReadString();
// deserialize the keyword tag list
int tagcount = reader.ReadInt();
m_KeywordTagList = new List<BaseXmlSpawner.KeywordTag>(tagcount);
for (int i = 0; i < tagcount; i++)
{
BaseXmlSpawner.KeywordTag tag = new BaseXmlSpawner.KeywordTag(null, this);
tag.Deserialize(reader);
}
goto case 18;
}
case 18:
{
m_AllowGhostTriggering = reader.ReadBool();
goto case 17;
}
case 17:
{
if (version < 25)
{
// the textentrybooks are deleted on deserialization so no need to track them
reader.ReadItem();
}
goto case 16;
}
case 16:
{
hasnewobjectinfo = true;
m_SequentialSpawning = reader.ReadInt();
TimeSpan seqdelay = reader.ReadTimeSpan();
m_SeqEnd = DateTime.UtcNow + seqdelay;
if (version < 20)
{
tmpSpawnListSize = reader.ReadInt();
}
tmpSubGroup = new List<int>(tmpSpawnListSize);
tmpSequentialResetTime = new List<double>(tmpSpawnListSize);
tmpSequentialResetTo = new List<int>(tmpSpawnListSize);
tmpKillsNeeded = new List<int>(tmpSpawnListSize);
for (int i = 0; i < tmpSpawnListSize; ++i)
{
int subgroup = reader.ReadInt();
double resettime = reader.ReadDouble();
int resetto = reader.ReadInt();
int killsneeded = reader.ReadInt();
tmpSubGroup.Add(subgroup);
tmpSequentialResetTime.Add(resettime);
tmpSequentialResetTo.Add(resetto);
tmpKillsNeeded.Add(killsneeded);
}
m_RegionName = reader.ReadString(); // 2004.02.08 :: Omega Red
goto case 15;
}
case 15:
{
m_ExternalTriggering = reader.ReadBool();
m_ExternalTrigger = reader.ReadBool();
goto case 14;
}
case 14:
{
m_NoItemTriggerName = reader.ReadString();
goto case 13;
}
case 13:
{
m_GumpState = reader.ReadString();
goto case 12;
}
case 12:
{
int todtype = reader.ReadInt();
switch (todtype)
{
case (int)TODModeType.Gametime:
m_TODMode = TODModeType.Gametime;
break;
case (int)TODModeType.Realtime:
m_TODMode = TODModeType.Realtime;
break;
}
goto case 11;
}
case 11:
{
m_KillReset = reader.ReadInt();
m_skipped = reader.ReadBool();
m_spawncheck = reader.ReadInt();
goto case 10;
}
case 10:
{
m_SetPropertyItem = reader.ReadItem();
goto case 9;
}
case 9:
{
m_TriggerProbability = reader.ReadDouble();
goto case 8;
}
case 8:
{
m_MobPropertyName = reader.ReadString();
m_MobTriggerName = reader.ReadString();
m_PlayerPropertyName = reader.ReadString();
goto case 7;
}
case 7:
{
m_SpeechTrigger = reader.ReadString();
goto case 6;
}
case 6:
{
m_ItemTriggerName = reader.ReadString();
goto case 5;
}
case 5:
{
m_ProximityTriggerMessage = reader.ReadString();
m_ObjectPropertyItem = reader.ReadItem();
m_ObjectPropertyName = reader.ReadString();
m_killcount = reader.ReadInt();
goto case 4;
}
case 4:
{
haveproximityrange = true;
m_ProximityRange = reader.ReadInt();
m_ProximityTriggerSound = reader.ReadInt();
m_proximityActivated = reader.ReadBool();
m_durActivated = reader.ReadBool();
m_refractActivated = reader.ReadBool();
m_StackAmount = reader.ReadInt();
m_TODStart = reader.ReadTimeSpan();
m_TODEnd = reader.ReadTimeSpan();
m_MinRefractory = reader.ReadTimeSpan();
m_MaxRefractory = reader.ReadTimeSpan();
if (m_refractActivated == true)
{
TimeSpan delay = reader.ReadTimeSpan();
DoTimer3(delay);
}
if (m_durActivated == true)
{
TimeSpan delay = reader.ReadTimeSpan();
DoTimer2(delay);
}
goto case 3;
}
case 3:
{
m_ShowContainerStatic = reader.ReadItem() as Static;
goto case 2;
}
case 2:
{
m_Duration = reader.ReadTimeSpan();
goto case 1;
}
case 1:
{
m_UniqueId = reader.ReadString();
m_HomeRangeIsRelative = reader.ReadBool();
goto case 0;
}
case 0:
{
m_Name = reader.ReadString();
// backward compatibility with old name storage
if (m_Name != null && m_Name != String.Empty) Name = m_Name;
m_X = reader.ReadInt();
m_Y = reader.ReadInt();
m_Width = reader.ReadInt();
m_Height = reader.ReadInt();
//we HAVE to check if the area is even or if coordinates point to the original spawner, otherwise it's custom area!
if (m_Width == m_Height && (m_Width%2)==0 && (m_X+m_Width/2)==this.X && (m_Y+m_Height/2)==this.Y)
m_SpawnRange = m_Width / 2;
else
m_SpawnRange = -1;
if (!haveproximityrange)
{
m_ProximityRange = -1;
}
m_WayPoint = reader.ReadItem() as WayPoint;
m_Group = reader.ReadBool();
m_MinDelay = reader.ReadTimeSpan();
m_MaxDelay = reader.ReadTimeSpan();
m_Count = reader.ReadInt();
m_Team = reader.ReadInt();
m_HomeRange = reader.ReadInt();
m_Running = reader.ReadBool();
if (m_Running == true)
{
TimeSpan delay = reader.ReadTimeSpan();
DoTimer(delay);
}
// Read in the size of the spawn object list
int SpawnListSize = reader.ReadInt();
m_SpawnObjects = new List<XmlSpawner.SpawnObject>(SpawnListSize);
for (int i = 0; i < SpawnListSize; ++i)
{
string TypeName = reader.ReadString();
int TypeMaxCount = reader.ReadInt();
SpawnObject TheSpawnObject = new SpawnObject(TypeName, TypeMaxCount);
m_SpawnObjects.Add(TheSpawnObject);
string typeName = BaseXmlSpawner.ParseObjectType(TypeName);
// does it have a substitution that might change its validity?
// if so then let it go
/*if(typeName!=null && typeName.StartsWith("#WAYPOINT"))
{
string[] args = BaseXmlSpawner.ParseSemicolonArgs(substitutedtypeName, 2);
string[] keyvalueargs = BaseXmlSpawner.ParseCommaArgs(args[0], 10);
SpawnPositionInfo spawnpositioning = new SpawnPositionInfo(SpawnPositionType.Waypoint, null, keyvalueargs);
if (spawnPositionWayTable == null)
{
spawnPositionWayTable = new Dictionary<string, List<Item>>();
}
// try to find the waypoint list in the local table
//WayList = spawnPositionWayTable[prefix];
List<Item> WayList;
// no existing list so create a new one
if (!spawnPositionWayTable.TryGetValue(prefix, out WayList) || WayList == null)
{
WayList = new List<Item>();
foreach (Item i in World.Items.Values)
{
if (i is WayPoint && i.Name != null && i.Map == Map && i.Name.StartsWith(prefix))
{
// add it to the list of items
WayList.Add(i);
}
}
// add the new list to the local table
spawnPositionWayTable[prefix] = WayList;
}
}*/
if (typeName == null || ((SpawnerType.GetType(typeName) == null) &&
(!BaseXmlSpawner.IsTypeOrItemKeyword(typeName) && typeName.IndexOf('{') == -1 && !typeName.StartsWith("*") && !typeName.StartsWith("#"))))
{
if (m_WarnTimer == null)
m_WarnTimer = new WarnTimer2();
m_WarnTimer.Add(Location, Map, TypeName);
this.status_str = "invalid type: " + typeName;
}
// Read in the number of spawns already
int SpawnedCount = reader.ReadInt();
TheSpawnObject.SpawnedObjects = new List<object>(SpawnedCount);
for (int x = 0; x < SpawnedCount; ++x)
{
int serial = reader.ReadInt();
if (serial < -1)
{
// minusone is reserved for unknown types by default
// minustwo on is used for referencing keyword tags
int tagserial = -1 * (serial + 2);
// get the tag with that serial and add it
BaseXmlSpawner.KeywordTag t = BaseXmlSpawner.GetFromTagList(this, tagserial);
if (t != null)
{
TheSpawnObject.SpawnedObjects.Add(t);
}
}
else
{
IEntity e = World.FindEntity(serial);
if (e != null)
TheSpawnObject.SpawnedObjects.Add(e);
}
}
}
// now have to reintegrate the later version spawnobject information into the earlier version desered objects
if (hasnewobjectinfo && tmpSpawnListSize == SpawnListSize)
{
for (int i = 0; i < SpawnListSize; ++i)
{
SpawnObject so = m_SpawnObjects[i];
so.SubGroup = tmpSubGroup[i];
so.SequentialResetTime = tmpSequentialResetTime[i];
so.SequentialResetTo = tmpSequentialResetTo[i];
so.KillsNeeded = tmpKillsNeeded[i];
if (version > 19)
so.RequireSurface = tmpRequireSurface[i];
bool restrictkills = false;
bool clearadvance = true;
double mind = -1;
double maxd = -1;
DateTime nextspawn = DateTime.MinValue;
if (version > 23)
{
restrictkills = tmpRestrictKillsToSubgroup[i];
clearadvance = tmpClearOnAdvance[i];
mind = tmpMinDelay[i];
maxd = tmpMaxDelay[i];
nextspawn = tmpNextSpawn[i];
}
so.RestrictKillsToSubgroup = restrictkills;
so.ClearOnAdvance = clearadvance;
so.MinDelay = mind;
so.MaxDelay = maxd;
so.NextSpawn = nextspawn;
bool disablespawn = false;
if (version > 26)
{
disablespawn = tmpDisableSpawn[i];
}
so.Disabled = disablespawn;
int packrange = -1;
if (version > 27)
{
packrange = tmpPackRange[i];
}
so.PackRange = packrange;
int spawnsper = 1;
if (version > 28)
{
spawnsper = tmpSpawnsPer[i];
}
so.SpawnsPerTick = spawnsper;
}
}
break;
}
}
if(m_RegionName!=null)
{
Timer.DelayCall(delegate{if(!this.Deleted && m_RegionName!=null)RegionName=m_RegionName;});
}
}
internal string GetSerializedObjectList()
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (SpawnObject so in m_SpawnObjects)
{
if (sb.Length > 0)
sb.Append(':'); // ':' Separates multiple object types
sb.AppendFormat("{0}={1}", so.TypeName, so.ActualMaxCount); // '=' separates object name from maximum amount
}
return sb.ToString();
}
internal string GetSerializedObjectList2()
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (SpawnObject so in m_SpawnObjects)
{
if (sb.Length > 0)
sb.Append(":OBJ="); // Separates multiple object types
sb.AppendFormat("{0}:MX={1}:SB={2}:RT={3}:TO={4}:KL={5}:RK={6}:CA={7}:DN={8}:DX={9}:SP={10}:PR={11}",
so.TypeName, so.ActualMaxCount, so.SubGroup, so.SequentialResetTime, so.SequentialResetTo, so.KillsNeeded,
so.RestrictKillsToSubgroup ? 1 : 0, so.ClearOnAdvance ? 1 : 0, so.MinDelay, so.MaxDelay, so.SpawnsPerTick, so.PackRange);
}
return sb.ToString();
}
#endregion
#region Spawn classes
public class SpawnObject
{
private string m_TypeName;
private int m_MaxCount;
private int m_SubGroup;
private int m_SequentialResetTo;
private int m_KillsNeeded;
private bool m_RestrictKillsToSubgroup = false;
private bool m_ClearOnAdvance = true;
private double m_MinDelay = -1;
private double m_MaxDelay = -1;
private int m_SpawnsPerTick = 1;
private bool m_Disabled = false;
private int m_PackRange = -1;
private bool m_Ignore = false;
// temporary variable used to calculate weighted spawn probabilities
public bool Available;
public List<object> SpawnedObjects;
public string[] PropertyArgs;
public double SequentialResetTime;
public int EntryOrder; // used for sorting
public bool RequireSurface = true;
public DateTime NextSpawn;
public bool SpawnedThisTick;
// these are externally accessible to the SETONSPAWNENTRY keyword
public string TypeName { get { return m_TypeName; } set { m_TypeName = value; } }
public int MaxCount
{
get
{
if (Disabled)
{
return 0;
}
else
{
return m_MaxCount;
}
}
set
{
m_MaxCount = value;
}
}
public int ActualMaxCount { get { return m_MaxCount; } set { m_MaxCount = value; } }
public int SubGroup { get { return m_SubGroup; } set { m_SubGroup = value; } }
public int SpawnsPerTick { get { return m_SpawnsPerTick; } set { m_SpawnsPerTick = value; } }
public int SequentialResetTo { get { return m_SequentialResetTo; } set { m_SequentialResetTo = value; } }
public int KillsNeeded { get { return m_KillsNeeded; } set { m_KillsNeeded = value; } }
public bool RestrictKillsToSubgroup { get { return m_RestrictKillsToSubgroup; } set { m_RestrictKillsToSubgroup = value; } }
public bool ClearOnAdvance { get { return m_ClearOnAdvance; } set { m_ClearOnAdvance = value; } }
public double MinDelay { get { return m_MinDelay; } set { m_MinDelay = value; } }
public double MaxDelay { get { return m_MaxDelay; } set { m_MaxDelay = value; } }
public bool Disabled { get { return m_Disabled; } set { m_Disabled = value; } }
public bool Ignore { get { return m_Ignore; } set { m_Ignore = value; } }
public int PackRange { get { return m_PackRange; } set { m_PackRange = value; } }
// command loggable constructor
public SpawnObject(Mobile from, XmlSpawner spawner, string name, int maxamount)
{
if (from != null && spawner != null)
{
bool found = false;
// go through the current spawner objects and see if this is a new entry
if (spawner.m_SpawnObjects != null)
{
for (int i = 0; i < spawner.m_SpawnObjects.Count; i++)
{
SpawnObject s = spawner.m_SpawnObjects[i];
if (s != null && s.TypeName == name)
{
found = true;
break;
}
}
}
if (!found)
{
CommandLogging.WriteLine(from, "{0} {1} added to XmlSpawner {2} '{3}' [{4}, {5}] ({6}) : {7}", from.AccessLevel, CommandLogging.Format(from), spawner.Serial, spawner.Name, spawner.GetWorldLocation().X, spawner.GetWorldLocation().Y, spawner.Map, name);
}
}
TypeName = name;
MaxCount = maxamount;
SubGroup = 0;
SequentialResetTime = 0;
SequentialResetTo = 0;
KillsNeeded = 0;
RestrictKillsToSubgroup = false;
ClearOnAdvance = true;
SpawnedObjects = new List<object>();
}
public SpawnObject(string name, int maxamount)
{
TypeName = name;
MaxCount = maxamount;
SubGroup = 0;
SequentialResetTime = 0;
SequentialResetTo = 0;
KillsNeeded = 0;
RestrictKillsToSubgroup = false;
ClearOnAdvance = true;
SpawnedObjects = new List<object>();
}
public SpawnObject(string name, int maxamount, int subgroup, double sequentialresettime, int sequentialresetto, int killsneeded,
bool restrictkills, bool clearadvance, double mindelay, double maxdelay, int spawnsper, int packrange)
{
TypeName = name;
MaxCount = maxamount;
SubGroup = subgroup;
SequentialResetTime = sequentialresettime;
SequentialResetTo = sequentialresetto;
KillsNeeded = killsneeded;
RestrictKillsToSubgroup = restrictkills;
ClearOnAdvance = clearadvance;
MinDelay = mindelay;
MaxDelay = maxdelay;
SpawnsPerTick = spawnsper;
PackRange = packrange;
SpawnedObjects = new List<object>();
}
internal static string GetParm(string str, string separator)
{
// find the parm separator in the string
// then look for the termination at the ':' or end of string
// and return the stuff between
string[] arg = BaseXmlSpawner.SplitString(str, separator);
//should be 2 args
if (arg.Length > 1)
{
// look for the end of parm terminator (could also be eol)
string[] parm = arg[1].Split(':');
if (parm.Length > 0)
{
return (parm[0]);
}
}
return (null);
}
internal static SpawnObject[] LoadSpawnObjectsFromString(string ObjectList)
{
// Clear the spawn object list
List<XmlSpawner.SpawnObject> NewSpawnObjects = new List<XmlSpawner.SpawnObject>();
if (ObjectList != null && ObjectList.Length > 0)
{
// Split the string based on the object separator first ':'
string[] SpawnObjectList = ObjectList.Split(':');
// Parse each item in the array
foreach (string s in SpawnObjectList)
{
// Split the single spawn object item by the max count '='
string[] SpawnObjectDetails = s.Split('=');
// Should be two entries
if (SpawnObjectDetails.Length == 2)
{
// Validate the information
// Make sure the spawn object name part has a valid length
if (SpawnObjectDetails[0].Length > 0)
{
// Make sure the max count part has a valid length
if (SpawnObjectDetails[1].Length > 0)
{
int maxCount = 1;
try
{
maxCount = int.Parse(SpawnObjectDetails[1]);
}
catch (System.Exception)
{ // Something went wrong, leave the default amount }
}
// Create the spawn object and store it in the array list
SpawnObject so = new SpawnObject(SpawnObjectDetails[0], maxCount);
NewSpawnObjects.Add(so);
}
}
}
}
}
return NewSpawnObjects.ToArray();
}
internal static SpawnObject[] LoadSpawnObjectsFromString2(string ObjectList)
{
// Clear the spawn object list
List<XmlSpawner.SpawnObject> NewSpawnObjects = new List<XmlSpawner.SpawnObject>();
// spawn object definitions will take the form typestring:MX=int:SB=int:RT=double:TO=int:KL=int
// or typestring:MX=int:SB=int:RT=double:TO=int:KL=int:OBJ=typestring...
if (ObjectList != null && ObjectList.Length > 0)
{
string[] SpawnObjectList = BaseXmlSpawner.SplitString(ObjectList, ":OBJ=");
// Parse each item in the array
foreach (string s in SpawnObjectList)
{
// at this point each spawn string will take the form typestring:MX=int:SB=int:RT=double:TO=int:KL=int
// Split the single spawn object item by the max count to get the typename and the remaining parms
string[] SpawnObjectDetails = BaseXmlSpawner.SplitString(s, ":MX=");
// Should be two entries
if (SpawnObjectDetails.Length == 2)
{
// Validate the information
// Make sure the spawn object name part has a valid length
if (SpawnObjectDetails[0].Length > 0)
{
// Make sure the parm part has a valid length
if (SpawnObjectDetails[1].Length > 0)
{
// now parse out the parms
// MaxCount
string parmstr = GetParm(s, ":MX=");
int maxCount = 1;
try { maxCount = int.Parse(parmstr); }
catch { }
// SubGroup
parmstr = GetParm(s, ":SB=");
int subGroup = 0;
try { subGroup = int.Parse(parmstr); }
catch { }
// SequentialSpawnResetTime
parmstr = GetParm(s, ":RT=");
double resetTime = 0;
try { resetTime = double.Parse(parmstr); }
catch { }
// SequentialSpawnResetTo
parmstr = GetParm(s, ":TO=");
int resetTo = 0;
try { resetTo = int.Parse(parmstr); }
catch { }
// KillsNeeded
parmstr = GetParm(s, ":KL=");
int killsNeeded = 0;
try { killsNeeded = int.Parse(parmstr); }
catch { }
// RestrictKills
parmstr = GetParm(s, ":RK=");
bool restrictKills = false;
if (parmstr != null)
try { restrictKills = (int.Parse(parmstr) == 1); }
catch { }
// ClearOnAdvance
parmstr = GetParm(s, ":CA=");
bool clearAdvance = true;
// if kills needed is zero, then set CA to false by default. This maintains consistency with the
// previous default behavior for old spawn specs that havent specified CA
if (killsNeeded == 0)
clearAdvance = false;
if (parmstr != null)
try { clearAdvance = (int.Parse(parmstr) == 1); }
catch { }
// MinDelay
parmstr = GetParm(s, ":DN=");
double minD = -1;
try { minD = double.Parse(parmstr); }
catch { }
// MaxDelay
parmstr = GetParm(s, ":DX=");
double maxD = -1;
try { maxD = double.Parse(parmstr); }
catch { }
// SpawnsPerTick
parmstr = GetParm(s, ":SP=");
int spawnsPer = 1;
try { spawnsPer = int.Parse(parmstr); }
catch { }
// PackRange
parmstr = GetParm(s, ":PR=");
int packRange = -1;
try { packRange = int.Parse(parmstr); }
catch { }
// Create the spawn object and store it in the array list
SpawnObject so = new SpawnObject(SpawnObjectDetails[0], maxCount, subGroup, resetTime, resetTo, killsNeeded,
restrictKills, clearAdvance, minD, maxD, spawnsPer, packRange);
NewSpawnObjects.Add(so);
}
}
}
}
}
return NewSpawnObjects.ToArray();
}
}
#endregion
}
}