XmlSpawner housekeeping.

This commit is contained in:
Voxpire 2023-10-11 11:59:58 +01:00 committed by Kamron Batman
parent a823299a7c
commit 2c334d1a1f
No known key found for this signature in database
GPG key ID: 7D81DF26D9A5D94A

View file

@ -53,28 +53,40 @@ public class XmlSpawner : Item, ISpawner
}
public const string Version = "5.0"; // RUADUCK's EDIT
public const byte MaxLoops = 10; //maximum number of recursive calls from spawner to itself. this is to prevent stack overflow from xmlspawner scripting
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 XmlSpawnDir { get; set; } = "XmlSpawner"; // default directory for saving/loading .xml files with [xmlload [xmlsave
private const int MaxSmartSectorListSize = 1024; // maximum sector list size for use in smart spawning. This gives a 512x512 tile range.
private static string defwaypointname; // 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
public static AccessLevel DiskAccessLevel { get; set; } = AccessLevel.Administrator; // minimum access level required by commands that can access the disk such as XmlLoad, XmlSave, and the Save function of XmlEdit
#if RESTRICTConstructible
public static AccessLevel ConstructibleAccessLevel = AccessLevel.GameMaster; // only allow spawning of objects that have Constructible access restrictions at this level or lower. Must define RESTRICTConstructible to enable this.
public static AccessLevel ConstructibleAccessLevel { get; set; } = AccessLevel.GameMaster; // only allow spawning of objects that have Constructible access restrictions at this level or lower. Must define RESTRICTConstructible to enable this.
#endif
private static int MaxMoveCheck = 10; // limit number of players that can be checked for triggering in a single OnMovement tick
// 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;
public static AccessLevel SmartSpawnAccessLevel { get; set; } = AccessLevel.Player;
// define the default values used in making spawners
private static TimeSpan defMinDelay = TimeSpan.FromMinutes(5);
@ -85,6 +97,7 @@ public class XmlSpawner : Item, ISpawner
private static TimeSpan defTODEnd = TimeSpan.FromMinutes(0);
private static TimeSpan defDuration = TimeSpan.FromMinutes(0);
private static readonly TimeSpan defDespawnTime = TimeSpan.FromHours(0);
private static bool defIsGroup;
private static int defTeam;
private static int defProximityTriggerSound = defaultTriggerSound;
@ -105,7 +118,7 @@ public class XmlSpawner : Item, ISpawner
// hash table for optimizing HoldSmartSpawning method invocation
private static Dictionary<Type, PropertyInfo> holdSmartSpawningHash;
public static int seccount;
public static int seccount { get; set; }
// sector hashtable for each map
private static readonly Dictionary<Sector, List<XmlSpawner>>[] GlobalSectorTable = new Dictionary<Sector, List<XmlSpawner>>[6];
@ -122,7 +135,7 @@ public class XmlSpawner : Item, ISpawner
private TimeSpan m_MaxDelay;
// added a duration parameter for time-limited spawns
private TimeSpan m_Duration;
public List<SpawnObject> m_SpawnObjects = new(); // List of objects to spawn
private List<SpawnObject> m_SpawnObjects = new(); // List of objects to spawn
private DateTime m_End;
private DateTime m_RefractEnd;
private DateTime m_DurEnd;
@ -143,8 +156,10 @@ public class XmlSpawner : Item, ISpawner
private string m_NoItemTriggerName;
private Item m_ObjectPropertyItem;
private string m_ObjectPropertyName;
public string status_str;
public int m_killcount;
public string status_str { get; set; }
private int m_killcount;
// added proximity range sensor
private int m_ProximityRange;
private bool m_speechTriggerActivated;
@ -159,21 +174,24 @@ public class XmlSpawner : Item, ISpawner
private bool m_HoldSequence;
private List<MovementInfo> m_MovementList;
private MovementTimer m_MovementTimer;
internal List<BaseXmlSpawner.KeywordTag> m_KeywordTagList = new();
public List<XmlSpawner> RecentSpawnerSearchList = null;
public List<Item> RecentItemSearchList = null;
public List<Mobile> RecentMobileSearchList = null;
private List<BaseXmlSpawner.KeywordTag> m_KeywordTagList = new();
public List<XmlSpawner> RecentSpawnerSearchList { get; set; }
public List<Item> RecentItemSearchList { get; set; }
public List<Mobile> RecentMobileSearchList { get; set; }
private SkillName m_skill_that_triggered;
private Map currentmap;
public bool m_IsInactivated;
private bool m_IsInactivated;
private bool m_SmartSpawning;
private SectorTimer m_SectorTimer;
private List<Static> m_ShowBoundsItems = new();
public List<BaseXmlSpawner.TypeInfo> PropertyInfoList = null; // used to optimize property info lookup used by set and get property methods.
public List<BaseXmlSpawner.TypeInfo> PropertyInfoList { get; set; } // used to optimize property info lookup used by set and get property methods.
private Dictionary<string, List<Item>> spawnPositionWayTable; // used to optimize #waypoint lookup
@ -193,7 +211,7 @@ public class XmlSpawner : Item, ISpawner
// private double m_SkillTriggerMax;
// private int m_SkillTriggerSuccess;
public bool DebugThis { get; set; } = false;
public bool DebugThis { get; set; }
public int MovingPlayerCount { get; set; }
@ -237,13 +255,13 @@ public class XmlSpawner : Item, ISpawner
}
}
public TimeSpan RealTOD => Core.Now.TimeOfDay;
public static TimeSpan RealTOD => Core.Now.TimeOfDay;
public int RealDay => Core.Now.Day;
public static int RealDay => Core.Now.Day;
public int RealMonth => Core.Now.Month;
public static int RealMonth => Core.Now.Month;
public DayOfWeek RealDayOfWeek => Core.Now.DayOfWeek;
public static DayOfWeek RealDayOfWeek => Core.Now.DayOfWeek;
public MoonPhase MoonPhase => Clock.GetMoonPhase(Map, Location.X, Location.Y);
@ -267,7 +285,7 @@ public class XmlSpawner : Item, ISpawner
public bool SingleSector { get; private set; }
public bool InActivationRange(Sector s1, Sector s2)
public static bool InActivationRange(Sector s1, Sector s2)
{
// check to see if the sectors are within +- 2 of one another
if (s1 == null || s2 == null)
@ -388,14 +406,9 @@ public class XmlSpawner : Item, ISpawner
// is this container held?
if (Parent != null)
{
if (RootParent is Mobile)
if (RootParent is IPoint3D e)
{
loc = ((Mobile)RootParent).Location;
}
else
if (RootParent is Item)
{
loc = ((Item)RootParent).Location;
loc = new Point3D(e);
}
}
@ -496,7 +509,7 @@ public class XmlSpawner : Item, ISpawner
SingleSector = false;
}
_TraceStart(2);
TraceStart(2);
// go through the sectorlist and see if any of the sectors are active
foreach (var s in sectorList)
@ -512,16 +525,16 @@ public class XmlSpawner : Item, ISpawner
return true;
}
}
_TraceEnd(2);
TraceEnd(2);
}
seccount++;
}
_TraceEnd(2);
TraceEnd(2);
return false;
}
}
public int SecCount => seccount;
public static int SecCount => seccount;
public bool IsInactivated
{
@ -792,27 +805,6 @@ public class XmlSpawner : Item, ISpawner
}
}
public bool isEmpty()
{
if (m_SpawnObjects == null)
{
return true;
}
foreach (var 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
@ -1534,7 +1526,29 @@ public class XmlSpawner : Item, ISpawner
}
[CommandProperty(AccessLevel.GameMaster)]
public bool IsEmpty => isEmpty();
public bool IsEmpty
{
get
{
if (m_SpawnObjects == null)
{
return true;
}
foreach (var so in m_SpawnObjects)
{
if (so.SpawnedObjects != null && so.SpawnedObjects.Count > 0)
{
if (so.SpawnedObjects[0] is Mobile)
{
return false;
}
}
}
return true;
}
}
public Guid Guid { get; }
public bool UnlinkOnTaming => true;
@ -1738,7 +1752,8 @@ public class XmlSpawner : Item, ISpawner
}
}
private static bool IgnoreLocationChange;
private bool IgnoreLocationChange;
public override void OnLocationChange(Point3D oldLocation)
{
if (IgnoreLocationChange)
@ -1774,7 +1789,7 @@ public class XmlSpawner : Item, ISpawner
}
}
public bool SomeOneHasGumpOpen
public static bool SomeOneHasGumpOpen
{
get
{
@ -2291,7 +2306,7 @@ public class XmlSpawner : Item, ISpawner
}
// try loading the new spawn specifications first
var Spawns = new SpawnObject[0];
var Spawns = Array.Empty<SpawnObject>();
var havenew = true;
valid_entry = true;
try { Spawns = SpawnObject.LoadSpawnObjectsFromString2((string)dr["Objects2"]); }
@ -2343,49 +2358,55 @@ public class XmlSpawner : Item, ISpawner
#if TRACE
private readonly string setname1 = _traceName[1] = "XmlFind";
private readonly string setname2 = _traceName[2] = "HasSector";
private readonly string setname4 = _traceName[4] = "AttachSpeech";
private readonly string setname5 = _traceName[5] = "HasHold";
private readonly string setname8 = _traceName[8] = "OnTick";
private readonly string setname9 = _traceName[9] = "Defrag";
private readonly string setname10 = _traceName[10] = "Respawn";
private readonly string setname11 = _traceName[11] = "SetProp";
private readonly string setname12 = _traceName[12] = "AttachMovement";
private readonly string setname13 = _traceName[13] = "ActiveSector";
private readonly string setname15 = _traceName[15] = "DistroTick";
private readonly string setname16 = _traceName[16] = "GetScaledFaction";
private readonly string setname17 = _traceName[17] = "FactionOnKill";
private readonly string setname18 = _traceName[18] = "CheckAcquire";
public static readonly string[] _traceName =
{
string.Empty,
"XmlFind",
"HasSector",
string.Empty,
"AttachSpeech",
"HasHold",
string.Empty,
string.Empty,
"OnTick",
"Defrag",
"Respawn",
"SetProp",
"AttachMovement",
"ActiveSector",
string.Empty,
"DistroTick",
"GetScaledFaction",
"FactionOnKill",
"CheckAcquire",
string.Empty,
};
private static readonly DateTime[] _traceStart = new DateTime[_traceName.Length];
private static readonly TimeSpan[] _traceTotal = new TimeSpan[_traceName.Length];
private static readonly int[] _traceCount = new int[_traceName.Length];
private const int MaxTraces = 20;
private static readonly 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 = Core.Now;
private static double _startProcessTime;
public static void _TraceStart(int index)
public static void TraceStart(int index)
{
if (index < MaxTraces)
if (index < _traceStart.Length)
{
_traceStart[index] = Core.Now;
//_traceStart[index] = Process.GetCurrentProcess().UserProcessorTime;
}
}
public static void _TraceEnd(int index)
public static void TraceEnd(int index)
{
if (index < MaxTraces)
if (index < _traceStart.Length)
{
_traceTotal[index] = _traceTotal[index].Add(Core.Now - _traceStart[index]);
//XmlSpawner._traceTotal[index] = XmlSpawner._traceTotal[index].Add(Process.GetCurrentProcess().UserProcessorTime - _traceStart[index]);
_traceTotal[index] += Core.Now - _traceStart[index];
_traceCount[index]++;
}
}
#else
public static void _TraceStart(int index) { }
public static void _TraceEnd(int index) { }
public static void TraceStart(int index) { }
public static void TraceEnd(int index) { }
#endif
private bool ValidPlayerTrig(Mobile m)
@ -2515,15 +2536,14 @@ public class XmlSpawner : Item, ISpawner
}
}
}
public bool HandlesOnSkillUse => m_Running && SkillTrigger != null && 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, Location, m_ProximityRange))
{
return;
@ -2544,6 +2564,7 @@ public class XmlSpawner : Item, ISpawner
// }
}
}
public override bool HandlesOnSpeech => m_Running && !string.IsNullOrEmpty(SpeechTrigger);
public override void OnSpeech(SpeechEventArgs e)
@ -2586,8 +2607,7 @@ public class XmlSpawner : Item, ISpawner
foreach (var moveinfo in m_MovementList)
{
var mtrig = moveinfo.trigMob;
if (mtrig == m)
if (moveinfo.trigMob == m)
{
add = false;
break;
@ -2597,7 +2617,6 @@ public class XmlSpawner : Item, ISpawner
// wasnt on the list so add it
if (add)
{
// is the list at max throttling length?
if (m_MovementList.Count > MaxMoveCheck)
{
@ -2639,9 +2658,11 @@ public class XmlSpawner : Item, ISpawner
{
var count = 0;
var maxspeed = 0;
foreach (var moveinfo in m_Spawner.m_MovementList)
{
var m = moveinfo.trigMob;
if (m == null)
{
continue;
@ -2649,12 +2670,14 @@ public class XmlSpawner : Item, ISpawner
// additional throttling in here by limiting number of mobs that can be checked in a single ontick
count++;
if (count > MaxMoveCheck)
{
break;
}
var speed = (int)GetDistance(m.Location, moveinfo.trigLocation);
if (speed > maxspeed)
{
maxspeed = speed;
@ -2667,6 +2690,7 @@ public class XmlSpawner : Item, ISpawner
m_Spawner.FastestPlayerSpeed = maxspeed;
}
m_Spawner.m_MovementList.Clear();
}
}
@ -2699,6 +2723,7 @@ public class XmlSpawner : Item, ISpawner
m_speechTriggerActivated = false;
}
}
base.OnMovement(m, oldLocation);
}
@ -3169,17 +3194,14 @@ public class XmlSpawner : Item, ISpawner
[Description("Lists the keyword taglist for a spawner")]
public static void ShowTagList_OnCommand(CommandEventArgs e)
{
e.Mobile.Target = new TagListTarget(e);
e.Mobile.Target = new TagListTarget();
}
private class TagListTarget : Target
{
private readonly CommandEventArgs m_e;
public TagListTarget(CommandEventArgs e)
public TagListTarget()
: base(30, false, TargetFlags.None)
{
m_e = e;
}
protected override void OnTarget(Mobile from, object targeted)
@ -3225,14 +3247,9 @@ public class XmlSpawner : Item, ISpawner
}
}
if (targeted is Mobile mobile)
if (targeted is ISpawnable s)
{
spawner = mobile.Spawner as XmlSpawner;
}
else
if (targeted is Item item)
{
spawner = item.Spawner as XmlSpawner;
spawner = s.Spawner as XmlSpawner;
}
if (spawner == null)
@ -3740,27 +3757,27 @@ public class XmlSpawner : Item, ISpawner
[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)
{
var ToShow = new List<Item>();
var ToShow = new List<XmlSpawner>();
foreach (var item in World.Items.Values)
{
if (item is XmlSpawner)
if (item is XmlSpawner xmlItem)
{
//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)
xmlItem.Visible = false; // set the spawn item visibility
xmlItem.Movable = false; // Make the spawn item movable
xmlItem.Hue = 88; // Bright blue colour so its easy to spot
xmlItem.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)
if (xmlItem.Parent != null && xmlItem.RootParent is Container)
{
ToShow.Add(item);
ToShow.Add(xmlItem);
}
}
}
// place the statics
foreach (XmlSpawner xml_item in ToShow)
foreach (var 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
@ -3788,7 +3805,7 @@ public class XmlSpawner : Item, ISpawner
[Description("Makes all XmlSpawner objects invisible and unmovable returns the object id to the default.")]
public static void HideSpawnPoints_OnCommand(CommandEventArgs e)
{
var ToDelete = new List<Item>();
var ToDelete = new List<XmlSpawner>();
foreach (var item in World.Items.Values)
{
if (item is XmlSpawner xmlItem)
@ -3806,7 +3823,7 @@ public class XmlSpawner : Item, ISpawner
}
}
}
foreach (XmlSpawner xml_item in ToDelete)
foreach (var xml_item in ToDelete)
{
if (xml_item.m_ShowContainerStatic != null && !xml_item.m_ShowContainerStatic.Deleted)
{
@ -3959,18 +3976,28 @@ public class XmlSpawner : Item, ISpawner
maxpercent = 100 * maxcount / totalcount;
}
e.Mobile.SendMessage($"Smartspawning access level is {SmartSpawnAccessLevel}");
e.Mobile.SendMessage($"--------------------------------");
e.Mobile.SendMessage($"{count} XmlSpawners");
e.Mobile.SendMessage($"{smartcount} are configured for SmartSpawning\n");
e.Mobile.SendMessage($"{inactivecount} are currently inactivated");
e.Mobile.SendMessage($"{totalSectorsMonitored} sectors being monitored\n");
e.Mobile.SendMessage($"Maximum possible spawn count is {totalcount}");
e.Mobile.SendMessage($"Maximum possible spawn reduction is {maxcount}\n");
e.Mobile.SendMessage($"Current spawn count is {currentcount}");
e.Mobile.SendMessage($"Current spawn reduction is {savings}");
e.Mobile.SendMessage($"Maximum possible savings is {maxpercent}%");
e.Mobile.SendMessage($"Current savings is {percent}%");
var notice = new Gumps.NoticeGump
(
1060637,
30720,
$"Smartspawning access level is {SmartSpawnAccessLevel}\n"
+ $"--------------------------------\n"
+ $"{count:N0} XmlSpawners\n"
+ $"{smartcount:N0} are configured for SmartSpawning\n"
+ $"{inactivecount:N0} are currently inactivated\n"
+ $"{totalSectorsMonitored:N0} sectors being monitored\n"
+ $"Maximum possible spawn count is {totalcount:N0}\n"
+ $"Maximum possible spawn reduction is {maxcount:N0}\n"
+ $"Current spawn count is {currentcount:N0}\n"
+ $"Current spawn reduction is {savings:N0}\n"
+ $"Maximum possible savings is {maxpercent}%\n"
+ $"Current savings is {percent}%\n",
0xFFC000,
420,
280
);
e.Mobile.SendGump(notice);
}
[Usage("OptimalSmartSpawning [max spawn/homerange diff]")]
@ -4051,7 +4078,7 @@ public class XmlSpawner : Item, ISpawner
// 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("#"))
type == null && !BaseXmlSpawner.IsTypeOrItemKeyword(typestr) && !typestr.Contains('{') && !typestr.StartsWith("*") && !typestr.StartsWith("#"))
{
skipit = true;
break;
@ -4067,8 +4094,8 @@ public class XmlSpawner : Item, ISpawner
}
}
e.Mobile.SendMessage($"Configured {count} XmlSpawners for SmartSpawning using maxdiff of {maxdiff}");
e.Mobile.SendMessage($"Estimated item/mob reduction is {maxcount}");
e.Mobile.SendMessage($"Configured {count:N0} XmlSpawners for SmartSpawning using maxdiff of {maxdiff:N0}");
e.Mobile.SendMessage($"Estimated item/mob reduction is {maxcount:N0}");
}
[Usage("XmlSpawnerWipe [SpawnerPrefixFilter]")]
@ -4433,7 +4460,7 @@ public class XmlSpawner : Item, ISpawner
linenumber++;
// is this the new format?
string[] args;
if (line.IndexOf('|') >= 0)
if (line.Contains('|'))
{
args = line.Trim().Split('|');
newformat = true;
@ -5100,13 +5127,13 @@ public class XmlSpawner : Item, ISpawner
{
try
{
ImportSpawner(spawner, e.Mobile);
ImportSpawner(spawner);
successes++;
}
catch (Exception ex) { e.Mobile.SendMessage(33, $"{ex.Message} {spawner.InnerText}"); failures++; }
}
}
e.Mobile.SendMessage($"{successes} spawners loaded successfully from {filePath}, {failures} failures.");
e.Mobile.SendMessage($"{successes:N0} spawners loaded successfully from {filePath}, {failures:N0} failures.");
}
else
{
@ -5129,7 +5156,7 @@ public class XmlSpawner : Item, ISpawner
return node.InnerText;
}
private static void ImportSpawner(XmlElement node, Mobile from)
private static void ImportSpawner(XmlElement node)
{
var count = int.Parse(GetText(node["count"], "1"));
var homeRange = int.Parse(GetText(node["homerange"], "4"));
@ -5238,7 +5265,7 @@ public class XmlSpawner : Item, ISpawner
}
catch (Exception ex) { e.Mobile.SendMessage(33, $"{ex.Message} {spawner.InnerText}"); failures++; }
}
e.Mobile.SendMessage($"{successes} megaspawners loaded successfully from {filePath}, {failures} failures.");
e.Mobile.SendMessage($"{successes:N0} megaspawners loaded successfully from {filePath}, {failures:N0} failures.");
}
else
{
@ -5985,7 +6012,7 @@ public class XmlSpawner : Item, ISpawner
try { SpawnIsRunning = bool.Parse((string)dr["IsRunning"]); }
catch { questionable_spawner = true; }
// try loading the new spawn specifications first
var Spawns = new SpawnObject[0];
var Spawns = Array.Empty<SpawnObject>();
var havenew = true;
try { Spawns = SpawnObject.LoadSpawnObjectsFromString2((string)dr["Objects2"]); }
catch { havenew = false; }
@ -6137,7 +6164,7 @@ public class XmlSpawner : Item, ISpawner
else
{
// disable the X_Y adjustments in OnLocationChange
IgnoreLocationChange = true;
TheSpawn.IgnoreLocationChange = true;
TheSpawn.MoveToWorld(new Point3D(SpawnCentreX, SpawnCentreY, NewZ), SpawnMap);
}
@ -7038,7 +7065,7 @@ public class XmlSpawner : Item, ISpawner
}
catch { }
// Indicate how many spawners were written
from?.SendMessage($"{TotalCount} spawner(s) were saved to file {dirname} [Trammel={TrammelCount}, Felucca={FeluccaCount}, Ilshenar={IlshenarCount}, Malas={MalasCount}, Tokuno={TokunoCount}, Other={OtherCount}].");
from?.SendMessage($"{TotalCount} spawner(s) were saved to file {dirname} [Trammel={TrammelCount:N0}, Felucca={FeluccaCount:N0}, Ilshenar={IlshenarCount:N0}, Malas={MalasCount:N0}, Tokuno={TokunoCount:N0}, Other={OtherCount:N0}].");
return true;
}
@ -7097,11 +7124,11 @@ public class XmlSpawner : Item, ISpawner
if (WipeAll)
{
e.Mobile.SendMessage($"Removed {Count} XmlSpawner objects from the world.");
e.Mobile.SendMessage($"Removed {Count:N0} XmlSpawner objects from the world.");
}
else
{
e.Mobile.SendMessage($"Removed {Count} XmlSpawner objects from {e.Mobile.Map}.");
e.Mobile.SendMessage($"Removed {Count:N0} XmlSpawner objects from {e.Mobile.Map}.");
}
}
else
@ -7182,11 +7209,11 @@ public class XmlSpawner : Item, ISpawner
if (RespawnAll)
{
e.Mobile.SendMessage($"Respawned {Count} XmlSpawner objects from the world.");
e.Mobile.SendMessage($"Respawned {Count:N0} XmlSpawner objects from the world.");
}
else
{
e.Mobile.SendMessage($"Respawned {Count} XmlSpawner objects from {e.Mobile.Map}.");
e.Mobile.SendMessage($"Respawned {Count:N0} XmlSpawner objects from {e.Mobile.Map}.");
}
}
else
@ -7266,7 +7293,7 @@ public class XmlSpawner : Item, ISpawner
Console.WriteLine("Adjusted Process Time = {0:####.####} secs", processtime / 1000);
Console.WriteLine("Processor Time = {0} ({1:p3} avg sys load)", currentprocess.UserProcessorTime, sysload);
for (var i = 0; i < MaxTraces; i++)
for (var i = 0; i < _traceCount.Length; i++)
{
if (_traceCount[i] > 0)
{
@ -7284,10 +7311,9 @@ public class XmlSpawner : Item, ISpawner
public static void XmlResetTrace_OnCommand(CommandEventArgs e)
{
if (e.Arguments.Length >= 0)
{
for (var i = 0; i < MaxTraces; i++)
for (var i = 0; i < _traceCount.Length; i++)
{
_traceCount[i] = 0;
_traceTotal[i] = TimeSpan.Zero;
@ -7311,7 +7337,7 @@ public class XmlSpawner : Item, ISpawner
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,
defProximityRange, defProximityTriggerSound, defAmount, defTeam, defHomeRange, defRelativeHome, Array.Empty<SpawnObject>(), 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);
}
@ -8245,7 +8271,7 @@ public class XmlSpawner : Item, ISpawner
public void OnTick()
{
_TraceStart(8);
TraceStart(8);
// start up the timer again for the next Ontick
DoTimer();
@ -8301,7 +8327,7 @@ public class XmlSpawner : Item, ISpawner
// dont process spawn ticks while inactivated if smart spawning is enabled
if (SmartSpawning && IsInactivated)
{
_TraceEnd(8);
TraceEnd(8);
return;
}
@ -8440,8 +8466,8 @@ public class XmlSpawner : Item, ISpawner
ResetAllFlags();
}
_TraceEnd(8);
TraceEnd(8);
}
public bool ClearSpawnedThisTick
@ -8756,8 +8782,9 @@ public class XmlSpawner : Item, ISpawner
if (ckeyvalueargs.Length > 1)
{
// dont spawn if it fails the test
if (!BaseXmlSpawner.CheckPropertyString(this, this, ckeyvalueargs[1], out status_str))
if (!BaseXmlSpawner.CheckPropertyString(this, this, ckeyvalueargs[1], out var status))
{
status_str = status;
return false;
}
}
@ -9091,13 +9118,10 @@ public class XmlSpawner : Item, ISpawner
public void Start()
{
if (m_Running == false)
if (!m_Running && m_SpawnObjects?.Count > 0)
{
if (m_SpawnObjects != null && m_SpawnObjects.Count > 0)
{
m_Running = true;
DoTimer();
}
m_Running = true;
DoTimer();
}
}
@ -9467,7 +9491,6 @@ public class XmlSpawner : Item, ISpawner
// is this a SERIAL specification?
if (wayargs[0] == "SERIAL")
{
// look it up by serial
if (wayargs.Length > 1)
{
@ -9591,6 +9614,7 @@ public class XmlSpawner : Item, ISpawner
{
Console.WriteLine("CanFit mob {0}, map={1}", mob, map);
}
if (map == null || map == Map.Internal)
{
return false;
@ -9612,10 +9636,12 @@ public class XmlSpawner : Item, ISpawner
canswim = mob.CanSwim;
cantwalk = mob.CantWalk;
}
if (DebugThis)
{
Console.WriteLine("fitting mob {0} checkmob={1} swim={2} walk={3}", mob, checkmob, canswim, cantwalk);
}
var lt = map.Tiles.GetLandTile(x, y);
bool surface;
@ -9960,7 +9986,7 @@ public class XmlSpawner : Item, ISpawner
}
}
public Point2D GetRandomRegionPoint(Region r)
public static Point2D GetRandomRegionPoint(Region r)
{
var count = r.Area.Length;
@ -10594,67 +10620,35 @@ public class XmlSpawner : Item, ISpawner
return m_SpawnObjects[index].MaxCount;
}
private void DeleteFromList(List<object> list)
private static void DeleteFromList<T>(List<T> list) where T : IEntity
{
if (list == null)
{
return;
}
foreach (var o in list)
var i = list.Count;
while (--i >= 0)
{
if (o is Item item)
if (i < list.Count)
{
item.Delete();
}
else if (o is Mobile mobile)
{
mobile.Delete();
try
{
list[i]?.Delete();
}
catch
{ }
}
}
list.Clear();
}
private void DeleteFromList(List<Item> listi, List<Mobile> listm)
private static 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();
}
DeleteFromList(listi);
DeleteFromList(listm);
}
public void RemoveSpawnObjects()
@ -10667,16 +10661,16 @@ public class XmlSpawner : Item, ISpawner
Defrag(false);
ClearTags(true);
var deletelist = new List<object>();
var deletelist = new List<IEntity>();
foreach (var so in m_SpawnObjects)
{
for (var i = 0; i < so.SpawnedObjects.Count; ++i)
{
var o = so.SpawnedObjects[i];
if (o is Item or Mobile)
if (o is IEntity e)
{
deletelist.Add(o);
deletelist.Add(e);
}
}
}
@ -10696,15 +10690,15 @@ public class XmlSpawner : Item, ISpawner
Defrag(false);
var deletelist = new List<object>();
var deletelist = new List<IEntity>();
for (var i = 0; i < so.SpawnedObjects.Count; ++i)
{
var o = so.SpawnedObjects[i];
if (o is Item or Mobile)
if (o is IEntity e)
{
deletelist.Add(o);
deletelist.Add(e);
}
}
@ -10724,7 +10718,7 @@ public class XmlSpawner : Item, ISpawner
Defrag(false);
ClearTags(true);
var deletelist = new List<object>();
var deletelist = new List<IEntity>();
foreach (var so in m_SpawnObjects)
{
if (so.SubGroup != subgroup || !so.ClearOnAdvance)
@ -10736,9 +10730,9 @@ public class XmlSpawner : Item, ISpawner
{
var o = so.SpawnedObjects[i];
if (o is Item or Mobile)
if (o is IEntity e)
{
deletelist.Add(o);
deletelist.Add(e);
}
}
}
@ -10760,7 +10754,7 @@ public class XmlSpawner : Item, ISpawner
Defrag(false);
ClearTags(true);
var deletelist = new List<object>();
var deletelist = new List<IEntity>();
foreach (var so in m_SpawnObjects)
{
for (var i = 0; i < so.SpawnedObjects.Count; ++i)
@ -10773,9 +10767,9 @@ public class XmlSpawner : Item, ISpawner
continue;
}
if (o is Item or Mobile)
if (o is IEntity e)
{
deletelist.Add(o);
deletelist.Add(e);
}
}
}
@ -10798,7 +10792,7 @@ public class XmlSpawner : Item, ISpawner
// Find the spawn object and increment its count by one
foreach (var so in m_SpawnObjects)
{
if (so.TypeName.ToUpper() == SpawnObjectName.ToUpper())
if (InsensitiveStringHelpers.Equals(so.TypeName, SpawnObjectName))
{
// Add one to the total count
m_Count++;
@ -10871,7 +10865,7 @@ public class XmlSpawner : Item, ISpawner
}
var deletelist = new List<object>();
var deletelist = new List<IEntity>();
// Remove any spawns over the count
while (TheSpawn.SpawnedObjects != null && TheSpawn.SpawnedObjects.Count > 0 && TheSpawn.SpawnedObjects.Count > TheSpawn.MaxCount)
@ -10879,9 +10873,9 @@ public class XmlSpawner : Item, ISpawner
var o = TheSpawn.SpawnedObjects[0];
// Delete the object
if (o is Item or Mobile)
if (o is IEntity e)
{
deletelist.Add(o);
deletelist.Add(e);
}
_ = TheSpawn.SpawnedObjects.Remove(o);
@ -11948,7 +11942,7 @@ public class XmlSpawner : Item, ISpawner
var typeName = BaseXmlSpawner.ParseObjectType(TypeName);
if (typeName == null || AssemblyHandler.FindTypeByName(typeName) == null &&
!BaseXmlSpawner.IsTypeOrItemKeyword(typeName) && typeName.IndexOf('{') == -1 && !typeName.StartsWith("*") && !typeName.StartsWith("#"))
!BaseXmlSpawner.IsTypeOrItemKeyword(typeName) && !typeName.Contains('{') && !typeName.StartsWith("*") && !typeName.StartsWith("#"))
{
m_WarnTimer ??= new WarnTimer2();