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

11414 lines
318 KiB
C#

using System;
using System.Data;
using System.IO;
using System.Collections.Generic;
using Server;
using Server.Items;
using Server.Network;
using Server.Gumps;
using Server.Targeting;
using System.Reflection;
using Server.Commands;
using Server.Commands.Generic;
using CPA = Server.CommandPropertyAttribute;
using System.Xml;
using Server.Spells;
using System.Text;
using System.Globalization;
using Server.Accounting;
using Server.Engines.XmlSpawner2;
namespace Server.Mobiles
{
public delegate void XmlGumpCallback(Mobile from, object invoker, string response);
public class BaseXmlSpawner
{
#region Initialization
private static List<BaseXmlSpawner.ProtectedProperty> ProtectedPropertiesList = new List<BaseXmlSpawner.ProtectedProperty>();
private class ProtectedProperty
{
public Type ObjectType;
public string Name;
public ProtectedProperty(Type type, string name)
{
ObjectType = type;
Name = name;
}
}
public static bool IsProtected(Type type, string property)
{
if (type == null || property == null) return false;
// search through the protected list for a matching entry
foreach (ProtectedProperty p in ProtectedPropertiesList)
{
if ((p.ObjectType == type || type.IsSubclassOf(p.ObjectType)) && (property.ToLower() == p.Name.ToLower()))
{
return true;
}
}
return false;
}
public static void Initialize()
{
// register restricted properties that cannot be set by the spawner
ProtectedPropertiesList.Add(new ProtectedProperty(typeof(Mobile), "accesslevel"));
ProtectedPropertiesList.Add(new ProtectedProperty(typeof(Item), "stafflevel"));
//fill the list
//InitializeHash();
}
#endregion
#region Type support
[Flags]
public enum KeywordFlags
{
HoldSpawn = 0x01,
HoldSequence = 0x02,
Serialize = 0x04,
Defrag = 0x08,
}
public class TypeInfo
{
public List<PropertyInfo> plist = new List<PropertyInfo>(); // hold propertyinfo list
public Type t;
}
// -------------------------------------------------------------
// Modified from Beta-36 Properties.cs code
// -------------------------------------------------------------
private static Type typeofTimeSpan = typeof(TimeSpan);
private static Type typeofParsable = typeof(ParsableAttribute);
private static Type typeofCustomEnum = typeof(CustomEnumAttribute);
private static bool IsParsable(Type t)
{
return (t == typeofTimeSpan || t.IsDefined(typeofParsable, false));
}
private static Type[] m_ParseTypes = new Type[] { typeof(string) };
private static object[] m_ParseParams = new object[1];
private static object Parse(object o, Type t, string value)
{
MethodInfo method = t.GetMethod("Parse", m_ParseTypes);
m_ParseParams[0] = value;
return method.Invoke(o, m_ParseParams);
}
private static Type[] m_NumericTypes = new Type[]
{
typeof( Byte ), typeof( SByte ),
typeof( Int16 ), typeof( UInt16 ),
typeof( Int32 ), typeof( UInt32 ),
typeof( Int64 ), typeof( UInt64 ), typeof( Server.Serial )
};
public static bool IsNumeric(Type t)
{
return (Array.IndexOf(m_NumericTypes, t) >= 0);
}
private static Type typeofType = typeof(Type);
private static bool IsType(Type t)
{
return (t == typeofType);
}
private static Type typeofChar = typeof(Char);
private static bool IsChar(Type t)
{
return (t == typeofChar);
}
private static Type typeofString = typeof(String);
private static bool IsString(Type t)
{
return (t == typeofString);
}
private static bool IsEnum(Type t)
{
return t.IsEnum;
}
private static bool IsCustomEnum(Type t)
{
return t.IsDefined(typeofCustomEnum, false);
}
// -------------------------------------------------------------
// End modified Beta-36 Properties.cs code
// -------------------------------------------------------------
public static string ParsedType(Type type)
{
if (type == null) return null;
string s = type.ToString();
if (s == null) return null;
string[] args = s.Split(Type.Delimiter);
if (args != null && args.Length > 0)
{
return args[args.Length - 1];
}
else
{
return null;
}
}
public static bool CheckType(object o, string typename)
{
if (typename == null || o == null) return false;
// test the type
Type objecttype = o.GetType();
Type targettype = null;
targettype = SpawnerType.GetType(typename);
if (objecttype != null && targettype != null && (objecttype.Equals(targettype) || objecttype.IsSubclassOf(targettype)))
{
return true;
}
return false;
}
private enum typeKeyword
{
SET,
SETVAR,
SETONTRIGMOB,
SETONCARRIED,
SETONSPAWN,
SETONSPAWNENTRY,
SETONNEARBY,
SETONPETS,
SETONMOB,
SETONTHIS,
SETONPARENT,
SETACCOUNTTAG,
FOREACH,
GIVE,
TAKEGIVE,
TAKE,
GUMP,
TAKEBYTYPE,
BROWSER,
SENDMSG,
SENDASCIIMSG,
MUSIC,
RESURRECT,
POISON,
DAMAGE,
EFFECT,
MEFFECT,
SOUND,
WAITUNTIL,
WHILE,
IF,
GOTO,
CAST,
BCAST,
BSOUND,
COMMAND,
SPAWN,
DESPAWN
}
private enum typemodKeyword
{
MUSIC,
POISON,
DAMAGE,
EFFECT,
BOLTEFFECT,
MEFFECT,
PEFFECT,
SOUND,
SAY,
SPEECH,
ANIMATE,
OFFSET,
ADD,
MSG,
ASCIIMSG,
SENDMSG,
SENDASCIIMSG,
BCAST,
EQUIP,
UNEQUIP,
DELETE,
KILL,
ATTACH,
FACETO,
SETVALUE,
FLASH,
PRIVMSG
}
private enum itemKeyword
{
ARMOR,
WEAPON,
JARMOR,
JWEAPON,
SHIELD,
SARMOR,
LOOT,
JEWELRY,
POTION,
SCROLL,
NECROSCROLL,
LOOTPACK,
TAKEN,
GIVEN,
ITEM,
MULTIADDON,
RANDOMITEM
}
private enum valueKeyword
{
GET,
GETVAR,
GETONMOB,
GETONCARRIED,
GETONTRIGMOB,
GETONNEARBY,
GETONSPAWN,
GETONPARENT,
GETONTHIS,
GETONTAKEN,
GETONGIVEN,
GETFROMFILE,
GETACCOUNTTAG,
AMOUNTCARRIED,
RND,
RNDBOOL,
RNDLIST,
RNDSTRLIST,
TRIGSKILL,
PLAYERSINRANGE,
MY,
RANDNAME
}
private enum valuemodKeyword
{
GET,
GETONMOB,
GETVAR,
GETONCARRIED,
GETONTRIGMOB,
GETONNEARBY,
GETONSPAWN,
GETONPARENT,
GETONTHIS,
GETONTAKEN,
GETONGIVEN,
GETFROMFILE,
GETACCOUNTTAG,
AMOUNTCARRIED,
RND,
RNDBOOL,
RNDLIST,
RNDSTRLIST,
MUL,
INC,
MOB,
TRIGMOB,
MY,
TRIGSKILL,
PLAYERSINRANGE,
RANDNAME
}
#endregion
#region Static variable declarations
// name of mobile used to issue commands via the COMMAND keyword. The accesslevel of the mobile will determine
// the accesslevel of commands that can be issued.
// if this is null, then COMMANDS can only be issued when triggered by players of the appropriate accesslevel
private static string CommandMobileName = null;
private static Dictionary<string, BaseXmlSpawner.typeKeyword> typeKeywordHash = new Dictionary<string, BaseXmlSpawner.typeKeyword>();
private static Dictionary<string, BaseXmlSpawner.typemodKeyword> typemodKeywordHash = new Dictionary<string, BaseXmlSpawner.typemodKeyword>();
private static Dictionary<string, BaseXmlSpawner.valueKeyword> valueKeywordHash = new Dictionary<string, BaseXmlSpawner.valueKeyword>();
private static Dictionary<string, BaseXmlSpawner.valuemodKeyword> valuemodKeywordHash = new Dictionary<string, BaseXmlSpawner.valuemodKeyword>();
private static Dictionary<string, BaseXmlSpawner.itemKeyword> itemKeywordHash = new Dictionary<string, BaseXmlSpawner.itemKeyword>();
private static char[] slashdelim = new char[1] { '/' };
private static char[] commadelim = new char[1] { ',' };
private static char[] spacedelim = new char[1] { ' ' };
private static char[] semicolondelim = new char[1] { ';' };
private static char[] literalend = new char[1] { '§' };
#endregion
#region Keywords
public static bool IsValueKeyword(string str)
{
if (string.IsNullOrEmpty(str) || !char.IsUpper(str[0])) return false;
//if (valueKeywordHash == null) InitializeHash();
return valueKeywordHash.ContainsKey(str);
}
public static bool IsValuemodKeyword(string str)
{
if (string.IsNullOrEmpty(str) || !char.IsUpper(str[0])) return false;
//if (valuemodKeywordHash == null) InitializeHash();
return valuemodKeywordHash.ContainsKey(str);
}
public static bool IsSpecialItemKeyword(string typeName)
{
if (string.IsNullOrEmpty(typeName) || !char.IsUpper(typeName[0])) return false;
//if (itemKeywordHash == null) InitializeHash();
return itemKeywordHash.ContainsKey(typeName);
}
public static bool IsTypeKeyword(string typeName)
{
if (string.IsNullOrEmpty(typeName) || !char.IsUpper(typeName[0])) return false;
//if (typeKeywordHash == null) InitializeHash();
return (typeKeywordHash.ContainsKey(typeName));
}
public static bool IsTypemodKeyword(string typeName)
{
if (string.IsNullOrEmpty(typeName) || !char.IsUpper(typeName[0])) return false;
//if (typemodKeywordHash == null) InitializeHash();
return (typemodKeywordHash.ContainsKey(typeName));
}
public static bool IsTypeOrItemKeyword(string typeName)
{
if (string.IsNullOrEmpty(typeName) || !Char.IsUpper(typeName[0])) return false;
//if (typeKeywordHash == null || itemKeywordHash == null) InitializeHash();
return (typeKeywordHash.ContainsKey(typeName) || itemKeywordHash.ContainsKey(typeName));
}
private static void AddTypeKeyword(string name)
{
typeKeywordHash.Add(name, (typeKeyword)Enum.Parse(typeof(typeKeyword), name));
}
private static void AddTypemodKeyword(string name)
{
typemodKeywordHash.Add(name, (typemodKeyword)Enum.Parse(typeof(typemodKeyword), name));
}
private static void AddValueKeyword(string name)
{
valueKeywordHash.Add(name, (valueKeyword)Enum.Parse(typeof(valueKeyword), name));
}
private static void AddValuemodKeyword(string name)
{
valuemodKeywordHash.Add(name, (valuemodKeyword)Enum.Parse(typeof(valuemodKeyword), name));
}
private static void AddItemKeyword(string name)
{
itemKeywordHash.Add(name, (itemKeyword)Enum.Parse(typeof(itemKeyword), name));
}
public static void RemoveKeyword(string name)
{
if (name == null) return;
name = name.Trim().ToUpper();
//if (IsTypeKeyword(name))
//{
typeKeywordHash.Remove(name);
//}
//if (IsTypemodKeyword(name))
//{
typemodKeywordHash.Remove(name);
//}
//if (IsValueKeyword(name))
//{
valueKeywordHash.Remove(name);
//}
//if (IsValuemodKeyword(name))
//{
valuemodKeywordHash.Remove(name);
//}
//if (IsSpecialItemKeyword(name))
//{
itemKeywordHash.Remove(name);
//}
}
public static void Configure()
{
// set up the keyword hash tables
// already set at startup time
/*typeKeywordHash = new Hashtable();
typemodKeywordHash = new Hashtable();
itemKeywordHash = new Hashtable();
valueKeywordHash = new Hashtable();
valuemodKeywordHash = new Hashtable();*/
// Type keywords
// spawned as primary objects
AddTypeKeyword("SET");
AddTypeKeyword("SETVAR");
AddTypeKeyword("SETONTRIGMOB");
AddTypeKeyword("SETONCARRIED");
AddTypeKeyword("SETONNEARBY");
AddTypeKeyword("SETONPETS");
AddTypeKeyword("SETONSPAWN");
AddTypeKeyword("SETONSPAWNENTRY");
AddTypeKeyword("SETONMOB");
AddTypeKeyword("SETONTHIS");
AddTypeKeyword("SETONPARENT");
AddTypeKeyword("SETACCOUNTTAG");
AddTypeKeyword("FOREACH");
AddTypeKeyword("GIVE");
AddTypeKeyword("TAKEGIVE");
AddTypeKeyword("TAKE");
AddTypeKeyword("GUMP");
AddTypeKeyword("TAKEBYTYPE");
AddTypeKeyword("BROWSER");
AddTypeKeyword("SENDMSG");
AddTypeKeyword("SENDASCIIMSG");
AddTypeKeyword("RESURRECT");
AddTypeKeyword("POISON");
AddTypeKeyword("DAMAGE");
AddTypeKeyword("SOUND");
AddTypeKeyword("EFFECT");
AddTypeKeyword("MEFFECT");
AddTypeKeyword("MUSIC");
AddTypeKeyword("WAITUNTIL");
AddTypeKeyword("WHILE");
AddTypeKeyword("IF");
AddTypeKeyword("GOTO");
AddTypeKeyword("CAST");
AddTypeKeyword("BCAST");
AddTypeKeyword("BSOUND");
AddTypeKeyword("COMMAND");
AddTypeKeyword("SPAWN");
AddTypeKeyword("DESPAWN");
// Typemod keywords
// used in place of properties as modifiers of the primary object type
AddTypemodKeyword("MUSIC");
AddTypemodKeyword("SOUND");
AddTypemodKeyword("POISON");
AddTypemodKeyword("DAMAGE");
AddTypemodKeyword("EFFECT");
AddTypemodKeyword("BOLTEFFECT");
AddTypemodKeyword("MEFFECT");
AddTypemodKeyword("PEFFECT");
AddTypemodKeyword("SAY");
AddTypemodKeyword("SPEECH");
AddTypemodKeyword("ANIMATE");
AddTypemodKeyword("OFFSET");
AddTypemodKeyword("MSG");
AddTypemodKeyword("ASCIIMSG");
AddTypemodKeyword("SENDMSG");
AddTypemodKeyword("SENDASCIIMSG");
AddTypemodKeyword("BCAST");
AddTypemodKeyword("ADD");
AddTypemodKeyword("EQUIP");
AddTypemodKeyword("UNEQUIP");
AddTypemodKeyword("DELETE");
AddTypemodKeyword("KILL");
AddTypemodKeyword("ATTACH");
AddTypemodKeyword("FACETO");
AddTypemodKeyword("SETVALUE");
AddTypemodKeyword("FLASH");
AddTypemodKeyword("PRIVMSG");
// Value keywords
// used in property tests
AddValueKeyword("RND");
AddValueKeyword("RNDBOOL");
AddValueKeyword("RNDLIST");
AddValueKeyword("RNDSTRLIST");
AddValueKeyword("MY");
AddValueKeyword("GET");
AddValueKeyword("GETVAR");
AddValueKeyword("GETONMOB");
AddValueKeyword("GETONCARRIED");
AddValueKeyword("AMOUNTCARRIED");
AddValueKeyword("GETONTRIGMOB");
AddValueKeyword("GETONNEARBY");
AddValueKeyword("GETONSPAWN");
AddValueKeyword("GETONPARENT");
AddValueKeyword("GETONTHIS");
AddValueKeyword("GETONTAKEN");
AddValueKeyword("GETONGIVEN");
AddValueKeyword("GETFROMFILE");
AddValueKeyword("GETACCOUNTTAG");
AddValueKeyword("RANDNAME");
AddValueKeyword("TRIGSKILL");
AddValueKeyword("PLAYERSINRANGE");
// Valuemod keywords
// used as values in property assignments
AddValuemodKeyword("RND");
AddValuemodKeyword("RNDBOOL");
AddValuemodKeyword("RNDLIST");
AddValuemodKeyword("RNDSTRLIST");
AddValuemodKeyword("MY");
AddValuemodKeyword("GET");
AddValuemodKeyword("GETVAR");
AddValuemodKeyword("GETONMOB");
AddValuemodKeyword("GETONCARRIED");
AddValuemodKeyword("AMOUNTCARRIED");
AddValuemodKeyword("GETONTRIGMOB");
AddValuemodKeyword("GETONNEARBY");
AddValuemodKeyword("GETONSPAWN");
AddValuemodKeyword("GETONPARENT");
AddValuemodKeyword("GETONTHIS");
AddValuemodKeyword("GETONTAKEN");
AddValuemodKeyword("GETONGIVEN");
AddValuemodKeyword("GETFROMFILE");
AddValuemodKeyword("GETACCOUNTTAG");
AddValuemodKeyword("MUL");
AddValuemodKeyword("INC");
AddValuemodKeyword("MOB");
AddValuemodKeyword("TRIGMOB");
AddValuemodKeyword("RANDNAME");
AddValuemodKeyword("TRIGSKILL");
AddValuemodKeyword("PLAYERSINRANGE");
// Item keywords
// these can be spawned like type keywords, or added to containers like items
AddItemKeyword("ARMOR");
AddItemKeyword("WEAPON");
AddItemKeyword("JARMOR");
AddItemKeyword("LOOT");
AddItemKeyword("JWEAPON");
AddItemKeyword("SARMOR");
AddItemKeyword("SHIELD");
AddItemKeyword("JEWELRY");
AddItemKeyword("POTION");
AddItemKeyword("SCROLL");
AddItemKeyword("NECROSCROLL");
AddItemKeyword("LOOTPACK");
AddItemKeyword("TAKEN");
AddItemKeyword("GIVEN");
AddItemKeyword("ITEM");
AddItemKeyword("MULTIADDON");
AddItemKeyword("RANDOMITEM");
}
#endregion
#region KeywordTag
public class KeywordTag
{
public KeywordFlags Flags;
public int Type;
private Timer m_Timer;
public DateTime m_End;
public DateTime m_TimeoutEnd;
public TimeSpan m_Delay;
public TimeSpan m_Timeout;
private XmlSpawner m_Spawner;
public string m_Condition;
public int m_Goto;
public bool Deleted = false;
public int Serial = -1;
public Mobile m_TrigMob;
public string Typename;
public KeywordTag(string typename, XmlSpawner spawner)
: this(typename, spawner, -1)
{
}
public KeywordTag(string typename, XmlSpawner spawner, int type)
: this(typename, spawner, type, TimeSpan.Zero, TimeSpan.Zero, null, -1)
{
}
public KeywordTag(string typename, XmlSpawner spawner, TimeSpan delay, string condition, int gotogroup)
: this(typename, spawner, 0, delay, TimeSpan.Zero, condition, gotogroup)
{
}
public KeywordTag(string typename, XmlSpawner spawner, TimeSpan delay, TimeSpan timeout, string condition, int gotogroup)
: this(typename, spawner, 0, delay, timeout, condition, gotogroup)
{
}
public KeywordTag(string typename, XmlSpawner spawner, int type, TimeSpan delay, TimeSpan timeout, string condition, int gotogroup)
{
Type = type;
m_Delay = delay;
m_Timeout = timeout;
m_TimeoutEnd = DateTime.UtcNow + timeout;
m_Spawner = spawner;
m_Condition = condition;
m_Goto = gotogroup;
Typename = typename;
// add the tag to the list
if (spawner != null && !spawner.Deleted)
{
m_TrigMob = spawner.TriggerMob;
if (spawner.m_KeywordTagList == null)
{
spawner.m_KeywordTagList = new List<BaseXmlSpawner.KeywordTag>();
}
// calculate the serial index of the new tag by adding one to the last one if there is one, otherwise just reset to 0
if (spawner.m_KeywordTagList.Count > 0)
Serial = spawner.m_KeywordTagList[spawner.m_KeywordTagList.Count - 1].Serial + 1;
else
Serial = 0;
spawner.m_KeywordTagList.Add(this);
switch (type)
{
case 0: // WAIT timer type
// start up the timer
DoTimer(delay, m_Delay, condition, gotogroup);
// and put spawning on hold until it is done
//spawner.OnHold = true;
Flags |= KeywordFlags.HoldSpawn;
Flags |= KeywordFlags.Serialize;
break;
case 1: // GUMP type
break;
case 2: // GOTO type
Flags |= KeywordFlags.HoldSequence;
Flags |= KeywordFlags.Serialize;
break;
default:
// dont do anything for other types
Flags |= KeywordFlags.Defrag;
break;
}
}
}
public void Delete()
{
// release any hold on spawning that might have been in place
//if(m_Spawner != null && !m_Spawner.Deleted && Type == 0)
//{
//m_Spawner.OnHold = false;
//m_Spawner.HoldSequence = false;
//}
// and stop all timers
if (m_Timer != null && Type == 0)
{
m_Timer.Stop();
}
this.Deleted = true;
// and remove it from the list
RemoveFromTagList(m_Spawner, this);
}
private void DoTimer(TimeSpan delay, TimeSpan repeatdelay, string condition, int gotogroup)
{
m_End = DateTime.UtcNow + delay;
if (m_Timer != null)
m_Timer.Stop();
m_Timer = new KeywordTimer(m_Spawner, this, delay, repeatdelay, condition, gotogroup);
m_Timer.Start();
}
public void Serialize(GenericWriter writer)
{
writer.Write((int)1); // version
// Version 1
writer.Write((int)Flags);
// Version 0
writer.Write(m_Spawner);
writer.Write(Type);
writer.Write(Serial);
if (Type == 0)
{
// save any timer information
writer.Write(m_End - DateTime.UtcNow);
writer.Write(m_Delay);
writer.Write(m_Condition);
writer.Write(m_Goto);
writer.Write(m_TimeoutEnd - DateTime.UtcNow);
writer.Write(m_Timeout);
writer.Write(m_TrigMob);
}
}
public void Deserialize(GenericReader reader)
{
int version = reader.ReadInt();
switch (version)
{
case 1:
Flags = (KeywordFlags)reader.ReadInt();
goto case 0;
case 0:
m_Spawner = (XmlSpawner)reader.ReadItem();
Type = reader.ReadInt();
Serial = reader.ReadInt();
if (Type == 0)
{
// get any timer info
TimeSpan delay = reader.ReadTimeSpan();
m_Delay = reader.ReadTimeSpan();
m_Condition = reader.ReadString();
m_Goto = reader.ReadInt();
TimeSpan timeoutdelay = reader.ReadTimeSpan();
m_TimeoutEnd = DateTime.UtcNow + timeoutdelay;
m_Timeout = reader.ReadTimeSpan();
m_TrigMob = reader.ReadMobile();
this.DoTimer(delay, m_Delay, m_Condition, m_Goto);
}
break;
}
}
// added the timer that begins on spawning tmp keywords
private class KeywordTimer : Timer
{
private KeywordTag m_Tag;
private XmlSpawner m_Spawner;
private string m_Condition;
private int m_Goto;
private TimeSpan m_Repeatdelay;
public KeywordTimer(XmlSpawner spawner, KeywordTag tag, TimeSpan delay, TimeSpan repeatdelay, string condition, int gotogroup)
: base(delay)
{
Priority = TimerPriority.OneSecond;
m_Tag = tag;
m_Spawner = spawner;
m_Condition = condition;
m_Goto = gotogroup;
m_Repeatdelay = repeatdelay;
}
protected override void OnTick()
{
// if a condition is available then test it
if (m_Condition != null && m_Condition.Length > 0 && m_Spawner != null && m_Spawner.Running)
{
// if the test is valid then terminate the timer
string status_str;
Mobile trigmob = null;
if (m_Spawner != null && !m_Spawner.Deleted)
{
trigmob = m_Spawner.TriggerMob;
}
if (TestItemProperty(m_Spawner, m_Spawner, m_Condition, trigmob, out status_str))
{
// release the hold on spawning
//m_Spawner.OnHold = false;
// spawn the designated subgroup if specified
if (m_Goto >= 0 && m_Spawner != null && !m_Spawner.Deleted)
{
// set the trigmob to the mob that originally triggered the wait keyword
if (m_Tag != null)
m_Spawner.TriggerMob = m_Tag.m_TrigMob;
// spawn the subgroup
m_Spawner.SpawnSubGroup(m_Goto, 0);
// advance sequential spawning to that group
//m_Spawner.SequentialSpawn = m_Goto;
}
// get rid of the temporary tag
if (m_Tag != null && !m_Tag.Deleted)
{
m_Tag.Delete();
}
}
else
{
// otherwise restart it and keep on holding
if (m_Tag != null && !m_Tag.Deleted)
{
//if(m_Tag.m_Timeout > TimeSpan.Zero)
// check the timeout if applicable
if (m_Tag.m_Timeout > TimeSpan.Zero && m_Tag.m_TimeoutEnd < DateTime.UtcNow)
{
// release the hold on spawning and delete the tag
m_Tag.Delete();
//m_Spawner.OnHold = false;
}
else
{
m_Tag.DoTimer(m_Repeatdelay, m_Repeatdelay, m_Condition, m_Goto);
}
}
}
}
else
{
// and terminate the timer
if (m_Tag != null && !m_Tag.Deleted)
{
m_Tag.Delete();
}
// release the hold on spawning
//m_Spawner.OnHold = false;
}
}
}
}
public static string TagInfo(KeywordTag tag)
{
if (tag != null)
return (String.Format("{0} : type={1} cond={2} go={3} del={4} end={5}", tag.Typename, tag.Type, tag.m_Condition, tag.m_Goto, tag.m_Delay, tag.m_End));
else
return null;
}
public static void RemoveFromTagList(XmlSpawner spawner, KeywordTag tag)
{
for (int i = 0; i < spawner.m_KeywordTagList.Count; i++)
{
if (tag == spawner.m_KeywordTagList[i])
{
spawner.m_KeywordTagList.RemoveAt(i);
break;
}
}
}
public static KeywordTag GetFromTagList(XmlSpawner spawner, int serial)
{
for (int i = 0; i < spawner.m_KeywordTagList.Count; i++)
{
if (serial == spawner.m_KeywordTagList[i].Serial)
{
return spawner.m_KeywordTagList[i];
}
}
return (null);
}
#endregion
#region Property parsing methods
// -------------------------------------------------------------
// Begin modified code from Beta-36 Properties.cs
// Added support for nested attribute and array access
// -------------------------------------------------------------
private static string InternalGetValue(object o, PropertyInfo p, int index)
{
Type type = p.PropertyType;
object value = null;
if (type.IsPrimitive)
{
value = p.GetValue(o, null);
}
else if ((type.GetInterface("IList") != null) && index >= 0)
{
try
{
object arrayvalue = p.GetValue(o, null);
value = ((IList<object>)arrayvalue)[index];
}
catch { }
}
else
{
value = p.GetValue(o, null);
}
string toString;
if (value == null)
toString = "(-null-)";
else if (IsNumeric(type))
toString = String.Format("{0} (0x{0:X})", value);
else if (IsChar(type))
toString = String.Format("'{0}' ({1} [0x{1:X}])", value, (int)value);
else if (IsString(type))
toString = String.Format("\"{0}\"", value);
else
toString = value.ToString();
return String.Format("{0} = {1}", p.Name, toString);
}
public static bool IsItem(Type type)
{
return (type != null && (type == typeof(Item) || type.IsSubclassOf(typeof(Item))));
}
public static bool IsMobile(Type type)
{
return (type != null && (type == typeof(Mobile) || type.IsSubclassOf(typeof(Mobile))));
}
public static string ConstructFromString(PropertyInfo p, Type type, object obj, string value, ref object constructed)
{
object toSet;
if (value == "(-null-)" && !type.IsValueType)
value = null;
if (IsEnum(type))
{
try
{
toSet = Enum.Parse(type, value, true);
}
catch
{
return "That is not a valid enumeration member.";
}
}
else if (IsCustomEnum(type))
{
try
{
MethodInfo info = p.PropertyType.GetMethod("Parse", new Type[] { typeof(string) });
if (info != null)
toSet = info.Invoke(null, new object[] { value });
else if (p.PropertyType == typeof(Enum) || p.PropertyType.IsSubclassOf(typeof(Enum)))
toSet = Enum.Parse(p.PropertyType, value, false);
else
toSet = null;
if (toSet == null)
return "That is not a valid custom enumeration member.";
}
catch
{
return "That is not a valid custom enumeration member.";
}
}
else if (IsType(type))
{
try
{
toSet = ScriptCompiler.FindTypeByName(value);
if (toSet == null)
return "No type with that name was found.";
}
catch
{
return "No type with that name was found.";
}
}
else if (IsParsable(type))
{
try
{
toSet = Parse(obj, type, value);
}
catch
{
return "That is not properly formatted.";
}
}
else if (value == null)
{
toSet = null;
}
else if (value.StartsWith("0x") && IsNumeric(type))
{
try
{
toSet = Convert.ChangeType(Convert.ToUInt64(value.Substring(2), 16), type);
}
catch
{
return "That is not properly formatted. not convertible.";
}
}
else if (value.StartsWith("0x") && (IsItem(type) || IsMobile(type)))
{
try
{
// parse out the mobile or item name from the value string
int ispace = value.IndexOf(' ');
string valstr = value.Substring(2);
if (ispace > 0)
{
valstr = value.Substring(2, ispace - 2);
}
toSet = World.FindEntity(Convert.ToInt32(valstr, 16));
// now check to make sure the object returned is consistent with the type
if (!((toSet is Mobile && IsMobile(type)) || (toSet is Item && IsItem(type))))
{
return "Item/Mobile type mismatch. cannot assign.";
}
}
catch
{
return "That is not properly formatted. not convertible.";
}
}
else if ((type.GetInterface("IList") != null))
{
try
{
object arrayvalue = p.GetValue(obj, null);
object po = ((IList<object>)arrayvalue)[0];
Type atype = po.GetType();
toSet = Parse(obj, atype, value);
}
catch
{
return "That is not properly formatted.";
}
}
else
{
try
{
toSet = Convert.ChangeType(value, type);
}
catch
{
return "That is not properly formatted.";
}
}
constructed = toSet;
return null;
}
public static string InternalSetValue(Mobile from, object o, PropertyInfo p, string value, bool shouldLog, int index)
{
object toSet = null;
Type ptype = p.PropertyType;
string result = ConstructFromString(p, p.PropertyType, o, value, ref toSet);
if (result != null)
return result;
try
{
if (shouldLog)
CommandLogging.LogChangeProperty(from, o, p.Name, value);
if (ptype.IsPrimitive)
{
p.SetValue(o, toSet, null);
}
else if ((ptype.GetInterface("IList") != null) && index >= 0)
{
try
{
object arrayvalue = p.GetValue(o, null);
((IList<object>)arrayvalue)[index] = toSet;
}
catch { }
}
else
{
p.SetValue(o, toSet, null);
}
return "Property has been set.";
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return "An exception was caught, the property may not be set.";
}
}
// set property values with support for nested attributes
public static string SetPropertyValue(XmlSpawner spawner, object o, string name, string value)
{
if (o == null)
{
return "Null object";
}
Type ptype = null;
object po = null;
Type type = o.GetType();
PropertyInfo[] props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public);
// parse the strings of the form property.attribute into two parts
// first get the property
string[] arglist = ParseString(name, 2, ".");
string propname = arglist[0];
string[] keywordargs = ParseString(propname, 4, ",");
// check for special keywords
if (keywordargs[0] == "ATTACHMENT")
{
if (keywordargs.Length < 4)
{
return "Invalid ATTACHMENT format";
}
// syntax is ATTACHMENT,type,name,propname
string apropname = keywordargs[3];
string aname = keywordargs[2];
Type attachtype = SpawnerType.GetType(keywordargs[1]);
// allow empty string specifications to be used to indicate a null string which will match any name
if (aname == "") aname = null;
List<XmlAttachment> attachments = XmlAttach.FindAttachments(o, attachtype, aname);
if (attachments != null && attachments.Count > 0)
{
// change the object, object type, and propname to refer to the attachment
o = attachments[0];
propname = apropname;
if (o == null)
{
return "Null object";
}
type = o.GetType();
props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public);
}
else
return "Attachment not found";
}
else if (keywordargs[0] == "SKILL")
{
if (keywordargs.Length < 2)
{
return "Invalid SKILL format";
}
SkillName skillname;
#if Framework_4_0
if(Enum.TryParse(keywordargs[1], true, out skillname))
#else
if(TryParse(keywordargs[1], true, out skillname))
#endif
{
if(o is Mobile)
{
Skill skill = ((Mobile)o).Skills[skillname];
double d;
if(double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out d))
{
skill.Base = d;
return "Property has been set.";
}
else
return "Invalid double number";
}
else
return "Object is not mobile";
}
else
return "Invalid SKILL reference.";
}
else if (keywordargs[0] == "STEALABLE")
{
if (o is Item)
{
bool b;
if(bool.TryParse(value, out b))
{
ItemFlags.SetStealable((Item)o, b);
return "Property has been set.";
}
else
return "Invalid Stealable assignment.";
}
else
return "Object is not an item";
}
// do a bit of parsing to handle array references
string[] arraystring = propname.Split('[');
int index = 0;
if (arraystring.Length > 1)
{
// parse the property name from the indexing
propname = arraystring[0];
// then parse to get the index value
string[] arrayvalue = arraystring[1].Split(']');
if (arrayvalue.Length > 0)
{
int.TryParse(arraystring[0], out index);
}
}
if (arglist.Length == 2)
{
PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname);
if (plookup != null)
{
//if ( !plookup.CanWrite )
//return "Property is read only.";
if (BaseXmlSpawner.IsProtected(type, propname))
return "Property is protected.";
ptype = plookup.PropertyType;
po = plookup.GetValue(o, null);
// now set the nested attribute using the new property list
return (SetPropertyValue(spawner, po, arglist[1], value));
}
else
{
// is a nested property with attributes so first get the property
foreach (PropertyInfo p in props)
{
if (Insensitive.Equals(p.Name, propname))
{
//CPA pattr = Properties.GetCPA( p );
//if ( pattr == null )
//return "Property not found.";
//if ( !p.CanWrite )
//return "Property is read only.";
if (BaseXmlSpawner.IsProtected(type, propname))
return "Property is protected.";
ptype = p.PropertyType;
po = p.GetValue(o, null);
// now set the nested attribute using the new property list
return (SetPropertyValue(spawner, po, arglist[1], value));
}
}
}
}
else
{
// its just a simple single property
PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname);
if (plookup != null)
{
if (!plookup.CanWrite)
return "Property is read only.";
if (BaseXmlSpawner.IsProtected(type, propname))
return "Property is protected.";
string returnvalue = InternalSetValue(null, o, plookup, value, false, index);
return returnvalue;
}
else
{
// note, looping through all of the props turns out to be a significant performance bottleneck
// good place for optimization
foreach (PropertyInfo p in props)
{
if (Insensitive.Equals(p.Name, propname))
{
if (!p.CanWrite)
return "Property is read only.";
if (BaseXmlSpawner.IsProtected(type, propname))
return "Property is protected.";
string returnvalue = InternalSetValue(null, o, p, value, false, index);
return returnvalue;
}
}
}
}
return "Property not found.";
}
public static string SetPropertyObject(XmlSpawner spawner, object o, string name, object value)
{
if (o == null)
{
return "Null object";
}
Type ptype = null;
object po = null;
Type type = o.GetType();
PropertyInfo[] props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public);
// parse the strings of the form property.attribute into two parts
// first get the property
string[] arglist = ParseString(name, 2, ".");
if (arglist.Length == 2)
{
// is a nested property with attributes so first get the property
// use the lookup table for optimization if possible
PropertyInfo plookup = LookupPropertyInfo(spawner, type, arglist[0]);
if (plookup != null)
{
//if ( !plookup.CanWrite )
//return "Property is read only.";
if (BaseXmlSpawner.IsProtected(type, arglist[0]))
return "Property is protected.";
ptype = plookup.PropertyType;
po = plookup.GetValue(o, null);
// now set the nested attribute using the new property list
return (SetPropertyObject(spawner, po, arglist[1], value));
}
else
{
foreach (PropertyInfo p in props)
{
if (Insensitive.Equals(p.Name, arglist[0]))
{
//if ( !p.CanWrite )
//return "Property is read only.";
if (BaseXmlSpawner.IsProtected(type, arglist[0]))
return "Property is protected.";
ptype = p.PropertyType;
po = p.GetValue(o, null);
// now set the nested attribute using the new property list
return (SetPropertyObject(spawner, po, arglist[1], value));
}
}
}
}
else
{
// its just a simple single property
// use the lookup table for optimization if possible
PropertyInfo plookup = LookupPropertyInfo(spawner, type, name);
if (plookup != null)
{
if (!plookup.CanWrite)
return "Property is read only.";
if (BaseXmlSpawner.IsProtected(type, name))
return "Property is protected.";
if (plookup.PropertyType == typeof(Server.Mobile))
{
plookup.SetValue(o, value, null);
return "Property has been set.";
}
else
{
return "Property is not of type Mobile.";
}
}
else
{
foreach (PropertyInfo p in props)
{
if (Insensitive.Equals(p.Name, name))
{
if (!p.CanWrite)
return "Property is read only.";
if (BaseXmlSpawner.IsProtected(type, name))
return "Property is protected.";
if (p.PropertyType == typeof(Server.Mobile))
{
p.SetValue(o, value, null);
return "Property has been set.";
}
else
{
return "Property is not of type Mobile.";
}
}
}
}
}
return "Property not found.";
}
public static string GetBasicPropertyValue(object o, string propname, out Type ptype)
{
ptype = null;
if (o == null || propname == null) return null;
Type type = o.GetType();
PropertyInfo[] props = type.GetProperties();
foreach (PropertyInfo p in props)
{
if (Insensitive.Equals(p.Name, propname))
{
if (!p.CanRead)
return null;
ptype = p.PropertyType;
string value = InternalGetValue(o, p, -1);
return ParseGetValue(value, ptype);
}
}
return null;
}
public static string GetPropertyValue(XmlSpawner spawner, object o, string name, out Type ptype)
{
ptype = null;
if (o == null || name == null) return null;
Type type = o.GetType();
object po = null;
PropertyInfo[] props = null;
try
{
props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public);
}
catch
{
Console.WriteLine("GetProperties error with type {0}", type);
return null;
}
// parse the strings of the form property.attribute into two parts
// first get the property
string[] arglist = ParseString(name, 2, ".");
string propname = arglist[0];
// parse up to 4 comma separated args for special keyword properties
string[] keywordargs = ParseString(propname, 4, ",");
// check for special keywords
if (keywordargs[0] == "ATTACHMENT")
{
// syntax is ATTACHMENT,type,name,property
if (keywordargs.Length < 4)
{
return "Invalid ATTACHMENT format";
}
string apropname = keywordargs[3];
string aname = keywordargs[2];
Type attachtype = SpawnerType.GetType(keywordargs[1]);
// allow empty string specifications to be used to indicate a null string which will match any name
if (aname == "") aname = null;
List<XmlAttachment> attachments = XmlAttach.FindAttachments(o, attachtype, aname);
if (attachments != null && attachments.Count > 0)
{
string getvalue = GetPropertyValue(spawner, attachments[0], apropname, out ptype);
return getvalue;
}
else
return "Attachment not found";
}
else
if (keywordargs[0] == "SKILL")
{
// syntax is SKILL,skillname
if (keywordargs.Length < 2)
{
return "Invalid SKILL format";
}
SkillName skillname;
#if Framework_4_0
if(Enum.TryParse(keywordargs[1], true, out skillname))
#else
if(TryParse(keywordargs[1], true, out skillname))
#endif
{
if (o is Mobile)
{
Skill skill = ((Mobile)o).Skills[skillname];
ptype = skill.Value.GetType();
return String.Format("{0} = {1}", skillname, skill.Value);
}
else
return "Object is not mobile";
}
else
{ return "Skill not found."; }
}
else
if (keywordargs[0] == "SERIAL")
{
bool found = true;
try
{
if (o is Mobile)
{
ptype = ((Mobile)o).Serial.GetType();
return String.Format("Serial = {0}", ((Mobile)o).Serial);
}
else
if (o is Item)
{
ptype = ((Item)o).Serial.GetType();
return String.Format("Serial = {0}", ((Item)o).Serial);
}
else
return "Object is not item/mobile";
}
catch { found = false; }
if (!found)
return "Serial not found.";
}
else
if (keywordargs[0] == "TYPE")
{
ptype = typeof(Type);
return String.Format("Type = {0}", o.GetType().Name);
}
else
if (keywordargs[0] == "STEALABLE")
{
bool found = true;
try
{
if (o is Item)
{
ptype = typeof(bool);
return String.Format("Stealable = {0}", ItemFlags.GetStealable((Item)o));
}
else
return "Object is not an item";
}
catch { found = false; }
if (!found)
return "Stealable flag not found.";
}
// do a bit of parsing to handle array references
string[] arraystring = arglist[0].Split('[');
int index = -1;
if (arraystring.Length > 1)
{
// parse the property name from the indexing
propname = arraystring[0];
// then parse to get the index value
string[] arrayvalue = arraystring[1].Split(']');
if (arrayvalue.Length > 0)
{
if(!int.TryParse(arrayvalue[0], out index))
index=-1;
}
}
if (arglist.Length == 2)
{
// use the lookup table for optimization if possible
PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname);
if (plookup != null)
{
if (!plookup.CanRead)
return "Property is write only.";
//if ( BaseXmlSpawner.IsProtected(type, propname) )
//return "Property is protected.";
ptype = plookup.PropertyType;
if (ptype.IsPrimitive)
{
po = plookup.GetValue(o, null);
}
else if ((ptype.GetInterface("IList") != null) && index >= 0)
{
try
{
object arrayvalue = plookup.GetValue(o, null);
po = ((IList<object>)arrayvalue)[index];
}
catch { }
}
else
{
po = plookup.GetValue(o, null);
}
// now set the nested attribute using the new property list
return (GetPropertyValue(spawner, po, arglist[1], out ptype));
}
else
{
// is a nested property with attributes so first get the property
foreach (PropertyInfo p in props)
{
//if ( Insensitive.Equals( p.Name, arglist[0] ) )
if (Insensitive.Equals(p.Name, propname))
{
if (!p.CanRead)
return "Property is write only.";
//if ( BaseXmlSpawner.IsProtected(type, propname) )
//return "Property is protected.";
ptype = p.PropertyType;
if (ptype.IsPrimitive)
{
po = p.GetValue(o, null);
}
else if ((ptype.GetInterface("IList") != null) && index >= 0)
{
try
{
object arrayvalue = p.GetValue(o, null);
po = ((IList<object>)arrayvalue)[index];
}
catch { }
}
else
{
po = p.GetValue(o, null);
}
// now set the nested attribute using the new property list
return (GetPropertyValue(spawner, po, arglist[1], out ptype));
}
}
}
}
else
{
// use the lookup table for optimization if possible
PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname);
if (plookup != null)
{
if (!plookup.CanRead)
return "Property is write only.";
ptype = plookup.PropertyType;
return InternalGetValue(o, plookup, index);
}
else
{
// its just a simple single property
foreach (PropertyInfo p in props)
{
//if ( Insensitive.Equals( p.Name, name ) )
if (Insensitive.Equals(p.Name, propname))
{
if (!p.CanRead)
return "Property is write only.";
ptype = p.PropertyType;
return InternalGetValue(o, p, index);
}
}
}
}
return "Property not found.";
}
// -------------------------------------------------------------
// End modified Beta-36 Properties.cs code
// -------------------------------------------------------------
public static string ApplyToProperty(XmlSpawner spawner, object getobject, object setobject, string getpropertystring, string setpropertystring)
{
Type ptype;
string getvalue = GetPropertyValue(spawner, getobject, getpropertystring, out ptype);
if (getvalue == null)
{
return "Null object or property";
}
if (ptype == null)
{
return getvalue;
}
string value2 = ParseGetValue(getvalue, ptype);
if (value2 != null)
{
// set the property value using returned get value as the the value
string result = SetPropertyValue(spawner, setobject, setpropertystring, value2);
// see if it was successful
if (result != "Property has been set.")
{
return setpropertystring + " : " + result;
}
}
return null;
}
// added in arg parsing to handle object property setting
public static bool ApplyObjectStringProperties(XmlSpawner spawner, string str, object o, Mobile trigmob, object refobject, out string status_str)
{
status_str = null;
if (str == null || str.Length <= 0 || o == null) return false;
// object strings will be of the form "object/modifier" where the modifier string is of the form "propname/value/propname/value/..."
// some keywords do not have value arguments so the modifier could take the form "propname/propname/value/..."
// this is handled by parsing into both forms
// make sure the string is properly terminated to assure proper parsing of any final keywords
bool terminated = false;
str = str.Trim();
if (str[str.Length - 1] != '/')
{
str += "/";
terminated = true;
}
string[] arglist;
arglist = ParseSlashArgs(str, 2);
string remainder = null;
// place the modifier section of the string in remainder
if (arglist.Length > 1)
remainder = arglist[1];
bool no_error = true;
// process the modifier string if there is anything
while (arglist.Length > 1)
{
// place into arglist the parsed modifier up to this point
// arglist[0] will contain the propname
// arglist[1] will contain the value
// arglist[2] will contain the reset of the modifier
arglist = ParseSlashArgs(remainder, 3);
// singlearglist will contain the propname and the remainder
// for those keywords that do not have value args
string[] singlearglist = ParseSlashArgs(remainder, 2);
if (arglist.Length > 1)
{
// handle value keywords that may take comma args
// itemarglist[1] will contain arg2/arg3/arg4>/arg5
// additemstr should have the full list of args <arg2/arg3/arg4>/arg5 if they are there. In the case of /arg1/ADD/arg2
// it will just have arg2
string[] groupedarglist = ParseString(arglist[1], 2, "[");
// take that argument list that should like like arg2/ag3/arg4>/arg5
// need to find the matching ">"
string[] groupargs = null;
string groupargstring = null;
if (groupedarglist.Length > 1)
{
groupargs = ParseToMatchingParen(groupedarglist[1], '[', ']');
// and get the first part of the string without the > so itemargs[0] should be arg2/ag3/arg4
groupargstring = groupargs[0];
}
// need to handle comma args that may be grouped with the () such as the (ATTACHMENT,args) arg
//string[] value_keywordargs = ParseString(groupedarglist[0],10,",");
string[] value_keywordargs = groupedarglist[0].Trim().Split(',');
if (groupargstring != null && groupargstring.Length > 0)
{
if (value_keywordargs != null && value_keywordargs.Length > 0)
value_keywordargs[value_keywordargs.Length - 1] = groupargstring;
}
// handle propname keywords that may take comma args
//string[] keywordargs = ParseString(arglist[0],10,",");
string[] keywordargs = arglist[0].Trim().Split(',');
// this quick optimization can determine whether this is a regular prop/value assignment
// since most prop modification strings will use regular propnames and not keywords, it makes sense to check for that first
if (value_keywordargs[0].Length > 0 && !Char.IsUpper(value_keywordargs[0][0]) &&
arglist[0].Length > 0 && !Char.IsUpper(arglist[0][0]))
{
// all of this code is also included in the keyword candidate tests
// this is because regular props can also be entered with uppercase so the lowercase test is not definitive
// restricted properties
//if(arglist[0].ToLower() == "accesslevel")
//{
// status_str = "accesslevel is a protected property";
// if(arglist.Length < 3) break;
// remainder = arglist[2];
//}
//else
{
// check for the literal char
if (singlearglist[1] != null && singlearglist[1].Length > 0 && singlearglist[1][0] == '@')
{
//support for literal terminator
singlearglist = ParseLiteralTerminator(singlearglist[1]);
string lstr = singlearglist[0];
if (terminated && lstr[lstr.Length - 1] == '/')
lstr = lstr.Remove(lstr.Length - 1, 1);
string result = SetPropertyValue(spawner, o, arglist[0], lstr.Remove(0, 1));
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
if(singlearglist.Length>1 && singlearglist[1] != null)
{
// if(singlearglist[1].Length>0 && singlearglist[1][0]=='/')
// singlearglist[1].Remove(0, 1);
remainder = singlearglist[1];
}
else
{
remainder=null;
break;
}
}
else
{
string result = SetPropertyValue(spawner, o, arglist[0], arglist[1]);
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
}
}
else
{
if (IsValuemodKeyword(value_keywordargs[0]))
{
valuemodKeyword kw = valuemodKeywordHash[value_keywordargs[0]];
if (kw == valuemodKeyword.RND)
{
// generate a random number and use it as the property value. Use the format /RND,min,max/
if (value_keywordargs.Length > 2)
{
// get a random number
string randvalue = "0";
int min, max;
if(int.TryParse(value_keywordargs[1], out min) && int.TryParse(value_keywordargs[2], out max))
{
randvalue=String.Format("{0}", Utility.RandomMinMax(min, max));
}
else
{
status_str = "Invalid RND args : " + arglist[1]; no_error = false;
}
// set the property value using the random number as the value
string result = SetPropertyValue(spawner, o, arglist[0], randvalue);
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
}
else
{
status_str = "Invalid RND args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.RNDBOOL)
{
// generate a random bool and use it as the property value. Use the format /RNDBOOL/
string randvalue = Utility.RandomBool().ToString();
// set the property value using the random number as the value
string result = SetPropertyValue(spawner, o, arglist[0], randvalue);
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.RNDLIST || kw == valuemodKeyword.RNDSTRLIST)
{
// generate a random number and use it as the property value. Use the format /RNDLIST,val1,val2,.../
if (value_keywordargs.Length > 1)
{
// compute a random index into the arglist
int randindex = Utility.Random(1, value_keywordargs.Length - 1);
// assign the list entry as the value
string randvalue = value_keywordargs[randindex];
// set the property value
string result = SetPropertyValue(spawner, o, arglist[0], randvalue);
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
}
else
{
status_str = "Invalid " + arglist[0] + " args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.MY)
{
// syntax is MY,property
// note this will be an arg to some property
if (value_keywordargs.Length > 1)
{
string resultstr = ApplyToProperty(spawner, o, o, value_keywordargs[1], arglist[0]);
if (resultstr != null)
{
status_str = "MY error: " + resultstr;
no_error = false;
}
}
else
{
status_str = "Invalid MY args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.GET)
{
// syntax is GET,[itemname -OR- SETITEM][,itemtype],property
// or GET,itemname[,itemtype],<ATTACHMENT,type,name,property>
// note this will be an arg to some property
if (value_keywordargs.Length > 2)
{
string propname = value_keywordargs[2];
string typestr = null;
if (value_keywordargs.Length > 3)
{
propname = value_keywordargs[3];
typestr = value_keywordargs[2];
}
// get the current property value
//Type ptype;
// get target item
// is the itemname a serialno?
object testitem = null;
if (value_keywordargs[1].StartsWith("0x"))
{
int serial;
if(!int.TryParse(value_keywordargs[1].Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out serial))
serial=-1;
if (serial >= 0)
testitem = World.FindEntity(serial);
}
else if(value_keywordargs[1]=="SETITEM" && spawner!=null && !spawner.Deleted && spawner.SetItem!=null)
{
testitem = spawner.SetItem;
}
else
{
testitem = FindItemByName(spawner, value_keywordargs[1], typestr);
}
string resultstr = ApplyToProperty(spawner, testitem, o, propname, arglist[0]);
if (resultstr != null)
{
status_str = "GET error: " + resultstr;
no_error = false;
}
}
else if(spawner!=null && value_keywordargs.Length > 0)
{
string propname = value_keywordargs[0];
string resultstr = ApplyToProperty(spawner, spawner.SetItem, o, propname, arglist[0]);
if (resultstr != null)
{
status_str = "GET error: " + resultstr;
no_error = false;
}
}
else
{
status_str = "Invalid GET args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.GETVAR)
{
// syntax is GETVAR,varname
if (value_keywordargs.Length > 1)
{
string varname = value_keywordargs[1];
// look for the xmllocalvariable attachment with the given name
XmlLocalVariable var = (XmlLocalVariable)XmlAttach.FindAttachment(refobject, typeof(XmlLocalVariable), varname);
if (var != null)
{
string result = SetPropertyValue(spawner, o, arglist[0], var.Data);
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
}
else
{
status_str = arglist[0] + " : No such var";
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else
{
status_str = "Invalid GETVAR args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.GETONMOB)
{
// syntax is GETONMOB,mobname[,mobtype],property
// or GETONMOB,mobname[,mobtype],<ATTACHMENT,type,name,property>
// note this will be an arg to some property
if (value_keywordargs.Length > 2)
{
//if(trigmob != null && !trigmob.Deleted){
// get the current property value
//Type ptype;
// get target item
string propname = value_keywordargs[2];
string typestr = null;
if (value_keywordargs.Length > 3)
{
propname = value_keywordargs[3];
typestr = value_keywordargs[2];
}
Mobile testmobile = FindMobileByName(spawner, value_keywordargs[1], typestr);
string resultstr = ApplyToProperty(spawner, testmobile, o, propname, arglist[0]);
if (resultstr != null)
{
status_str = "GETONMOB error: " + resultstr;
no_error = false;
}
}
else
{
status_str = "Invalid GETONMOB args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.GETONCARRIED)
{
// syntax is GETONCARRIED,itemname[,itemtype][,equippedonly],property
// or GETONCARRIED,itemname[,itemtype][,equippedonly],<ATTACHMENT,type,name,property>
// note this will be an arg to some property
if (value_keywordargs.Length > 2)
{
bool equippedonly = false;
if (trigmob != null && !trigmob.Deleted)
{
string itemname = value_keywordargs[1];
string propname = value_keywordargs[2];
string typestr = null;
if (value_keywordargs.Length > 3)
{
propname = value_keywordargs[3];
typestr = value_keywordargs[2];
}
if (value_keywordargs.Length > 4)
{
propname = value_keywordargs[4];
if (value_keywordargs[3].ToLower() == "equippedonly")
{
equippedonly = true;
}
else
{
if(!bool.TryParse(value_keywordargs[3], out equippedonly))
{
status_str = "GETONCARRIED error parsing equippedonly";
no_error = false;
}
}
}
// get the current property value
//Type ptype;
// get target item
Item testitem = SearchMobileForItem(trigmob, ParseObjectType(itemname), typestr, false, equippedonly);
string resultstr = ApplyToProperty(spawner, testitem, o, propname, arglist[0]);
if (resultstr != null)
{
status_str = "GETONCARRIED error: " + resultstr;
no_error = false;
}
}
else
{
no_error = false;
}
}
else
{
status_str = "Invalid GETONCARRIED args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.GETONTRIGMOB)
{
// syntax is GETONTRIGMOB,property
// or GETONTRIGMOB,<ATTACHMENT,type,name,property>
// note this will be an arg to some property
if (value_keywordargs.Length > 1)
{
if (trigmob != null && !trigmob.Deleted)
{
string resultstr = ApplyToProperty(spawner, trigmob, o, value_keywordargs[1], arglist[0]);
if (resultstr != null)
{
status_str = "GETONTRIGMOB error: " + resultstr;
no_error = false;
}
}
else
{
no_error = false;
}
}
else
{
status_str = "Invalid GETONTRIGMOB args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.GETONNEARBY)
{
// syntax is GETONNEARBY,range,name[,type][,searchcontainers],property
// or GETONNEARBY,range,name[,type][,searchcontainers],[ATTACHMENT,type,name,property]
// note this will be an arg to some property
if (value_keywordargs.Length > 3)
{
string targetname = value_keywordargs[2];
string propname = value_keywordargs[3];
string typestr = null;
bool searchcontainers = false;
int range;
if(!int.TryParse(value_keywordargs[1], out range))
range=-1;
if (range < 0)
{
status_str = "invalid range in GETONNEARBY";
no_error = false;
}
if (value_keywordargs.Length > 4)
{
typestr = value_keywordargs[3];
propname = value_keywordargs[4];
}
if (value_keywordargs.Length > 5)
{
if(!bool.TryParse(value_keywordargs[3], out searchcontainers))
{
status_str = "invalid searchcontainer bool in GETONNEARBY";
no_error = false;
}
typestr = value_keywordargs[4];
propname = value_keywordargs[5];
}
Type targettype = null;
if (typestr != null)
{
targettype = SpawnerType.GetType(typestr);
}
if (no_error)
{
// get all of the nearby objects
object relativeto = spawner;
if (o is XmlAttachment)
{
relativeto = ((XmlAttachment)o).AttachedTo;
}
List<object> nearbylist = GetNearbyObjects(relativeto, targetname, targettype, typestr, range, searchcontainers, null);
string resultstr = null;
// apply the properties from the first valid thing on the list
foreach (object nearbyobj in nearbylist)
{
resultstr = ApplyToProperty(spawner, nearbyobj, o, propname, arglist[0]);
if (resultstr == null)
break;
}
if (resultstr != null)
{
status_str = "GETONNEARBY error: " + resultstr;
no_error = false;
}
}
}
else
{
status_str = "Invalid GETONNEARBY args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.GETONPARENT)
{
// syntax is GETONPARENT,property
// or GETONPARENT,<ATTACHMENT,type,name,property>
// note this will be an arg to some property
if (value_keywordargs.Length > 1)
{
object parent = null;
if (refobject is Item)
{
parent = ((Item)refobject).Parent;
}
else
if (refobject is XmlAttachment)
{
parent = ((XmlAttachment)refobject).AttachedTo;
}
if (parent != null)
{
string resultstr = ApplyToProperty(spawner, parent, o, value_keywordargs[1], arglist[0]);
if (resultstr != null)
{
status_str = "GETONPARENT error: " + resultstr;
no_error = false;
}
}
else
{
no_error = false;
}
}
else
{
status_str = "Invalid GETONPARENT args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.GETONTHIS)
{
// syntax is GETONTHIS,property
// or GETONTHIS,<ATTACHMENT,type,name,property>
// note this will be an arg to some property
if (value_keywordargs.Length > 1)
{
if (refobject != null)
{
string resultstr = ApplyToProperty(spawner, refobject, o, value_keywordargs[1], arglist[0]);
if (resultstr != null)
{
status_str = "GETONTHIS error: " + resultstr;
no_error = false;
}
}
else
{
no_error = false;
}
}
else
{
status_str = "Invalid GETONTHIS args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.GETONTAKEN)
{
// syntax is GETONTAKEN,property
// or GETONTAKEN,<ATTACHMENT,type,name,property>
// note this will be an arg to some property
if (value_keywordargs.Length > 1)
{
// find the taken object
Item taken = GetTaken(refobject);
if (taken != null)
{
string resultstr = ApplyToProperty(spawner, taken, o, value_keywordargs[1], arglist[0]);
if (resultstr != null)
{
status_str = "GETONTAKEN error: " + resultstr;
no_error = false;
}
}
else
{
no_error = false;
}
}
else
{
status_str = "Invalid GETONTAKEN args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.GETONGIVEN)
{
// syntax is GETONGIVEN,property
// or GETONGIVEN,<ATTACHMENT,type,name,property>
// note this will be an arg to some property
if (value_keywordargs.Length > 1)
{
// find the taken object
Item taken = GetGiven(refobject);
if (taken != null)
{
string resultstr = ApplyToProperty(spawner, taken, o, value_keywordargs[1], arglist[0]);
if (resultstr != null)
{
status_str = "GETONGIVEN error: " + resultstr;
no_error = false;
}
}
else
{
no_error = false;
}
}
else
{
status_str = "Invalid GETONGIVEN args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.GETONSPAWN)
{
// syntax is GETONSPAWN[,spawername],subgroup,property
// or GETONSPAWN[,spawername],subgroup,<ATTACHMENT,type,name,property>
// note this will be an arg to some property
if (value_keywordargs.Length > 2)
{
string subgroupstr = value_keywordargs[1];
string propstr = value_keywordargs[2];
string spawnerstr = null;
if (value_keywordargs.Length > 3)
{
spawnerstr = value_keywordargs[1];
subgroupstr = value_keywordargs[2];
propstr = value_keywordargs[3];
}
// get the current property value
//Type ptype;
// get target object
int subgroup;
if(!int.TryParse(subgroupstr, out subgroup))
subgroup = -1;
if (subgroup == -1)
{
status_str = "Invalid subgroup in GETONSPAWN";
no_error = false;
}
else
{
if (spawnerstr != null)
{
spawner = FindSpawnerByName(spawner, spawnerstr);
if (spawner == null)
{
status_str = "Invalid spawnername in GETONSPAWN";
no_error = false;
}
}
object targetobj = XmlSpawner.GetSpawned(spawner, subgroup);
if (targetobj != null)
{
string resultstr = ApplyToProperty(spawner, targetobj, o, propstr, arglist[0]);
if (resultstr != null)
{
status_str = "GETONSPAWN error: " + resultstr;
no_error = false;
}
}
else
{
no_error = false;
}
}
}
else
{
status_str = "Invalid GETONSPAWN args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.GETFROMFILE)
{
// syntax is GETFROMFILE,filename
if (value_keywordargs.Length > 1)
{
string filename = value_keywordargs[1];
string filestring = null;
// read in the string from the file
if (System.IO.File.Exists(filename) == true)
{
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)
{
filestring += line;
}
sr.Close();
}
}
catch
{
status_str = "GETFROMFILE error: " + filename;
no_error = false;
}
// set the property value
string result = SetPropertyValue(spawner, o, arglist[0], filestring);
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
}
}
else
{
status_str = "Invalid GETFROMFILE args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.GETACCOUNTTAG)
{
// syntax is GETACCOUNTTAG,tagname
if (value_keywordargs.Length > 1)
{
string tagname = value_keywordargs[1];
string tagvalue = null;
// get the value of the account tag from the triggering mob
if (trigmob != null && !trigmob.Deleted)
{
Account acct = trigmob.Account as Account;
if (acct != null)
{
tagvalue = acct.GetTag(tagname);
}
}
else
{
no_error = false;
}
if (tagvalue != null)
{
// set the property value
string result = SetPropertyValue(spawner, o, arglist[0], tagvalue);
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
}
else
{
status_str = "Invalid GETACCOUNTTAG tagname : " + tagname;
no_error = false;
}
}
else
{
status_str = "Invalid GETACCOUNTTAG args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.MUL)
{
// increment the property value by the amount. Use the format propname/MUL,min,max/ or propname/MUL,value
if (value_keywordargs.Length > 1)
{
// get a random number
string incvalue = "0";
if (value_keywordargs.Length > 2)
{
double d0, d1;
if(double.TryParse(value_keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out d0) && double.TryParse(value_keywordargs[2], NumberStyles.Any, CultureInfo.InvariantCulture, out d1))
{
incvalue = String.Format("{0}", Utility.RandomMinMax((int)(10000*d0), (int)(10000*d1)) / 10000.0);
}
else{ status_str = "Invalid MUL args : " + arglist[1]; no_error = false; }
}
else
{
incvalue = value_keywordargs[1];
}
// get the current property value
Type ptype;
string tmpvalue = GetPropertyValue(spawner, o, arglist[0], out ptype);
// see if it was successful
if (ptype == null)
{
status_str = String.Format("Cant find {0}", arglist[0]);
no_error = false;
}
else
{
string currentvalue = "0";
try
{
string[] arglist2 = ParseString(tmpvalue, 2, "=");
string[] arglist3 = ParseString(arglist2[1], 2, " ");
currentvalue = arglist3[0].Trim();
}
catch { }
string tmpstr = currentvalue;
// should use the actual ptype info to do the multiplication. Maybe later.
double d0,d1;
if(double.TryParse(currentvalue, NumberStyles.Any, CultureInfo.InvariantCulture, out d0) && double.TryParse(incvalue, NumberStyles.Any, CultureInfo.InvariantCulture, out d1))
{
tmpstr = ((int)(d0*d1)).ToString();
}
else{ status_str = "Invalid MUL args : " + arglist[1]; no_error = false; }
// set the property value using the incremented value
string result = SetPropertyValue(spawner, o, arglist[0], tmpstr);
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
}
}
else
{
status_str = "Invalid MUL args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.INC)
{
// increment the property value by the amount. Use the format propname/INC,min,max/ or propname/INC,value
if (value_keywordargs.Length > 1)
{
// get a random number
string incvalue = "0";
if (value_keywordargs.Length > 2)
{
int min,max;
if(int.TryParse(value_keywordargs[1], out min) && int.TryParse(value_keywordargs[2], out max))
{
incvalue = String.Format("{0}", Utility.RandomMinMax(min, max));
}
else{ status_str = "Invalid INC args : " + arglist[1]; no_error = false; }
}
else
{
incvalue = value_keywordargs[1];
}
// get the current property value
Type ptype;
string tmpvalue = GetPropertyValue(spawner, o, arglist[0], out ptype);
// see if it was successful
if (ptype == null)
{
status_str = String.Format("Cant find {0}", arglist[0]);
no_error = false;
}
else
{
string currentvalue = "0";
try
{
string[] arglist2 = ParseString(tmpvalue, 2, "=");
string[] arglist3 = ParseString(arglist2[1], 2, " ");
currentvalue = arglist3[0].Trim();
}
catch { }
string tmpstr = currentvalue;
// should use the actual ptype info to do the addition. Maybe later.
double d0,d1;
if(double.TryParse(currentvalue, NumberStyles.Any, CultureInfo.InvariantCulture, out d0) && double.TryParse(incvalue, NumberStyles.Any, CultureInfo.InvariantCulture, out d1))
{
tmpstr=((int)(d0+d1)).ToString();
}
else
{ status_str = "Invalid INC args : " + arglist[1]; no_error = false; }
// set the property value using the incremented value
string result = SetPropertyValue(spawner, o, arglist[0], tmpstr);
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
}
}
else
{
status_str = "Invalid INC args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.MOB)
{
// lookup the mob id based on the name. format is /MOB,name[,type]/
if (value_keywordargs.Length > 1)
{
string typestr = null;
if (value_keywordargs.Length > 2)
{
typestr = value_keywordargs[2];
}
// lookup the name
Mobile mob_id = null;
try
{
mob_id = FindMobileByName(spawner, value_keywordargs[1], typestr); // the format of this will be 0xvalue "name"
}
catch { status_str = "Invalid MOB args : " + arglist[1]; no_error = false; }
// set the property value using this format (M) id name
string result = SetPropertyObject(spawner, o, arglist[0], mob_id);
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
}
else
{
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.TRIGMOB)
{
string result = SetPropertyObject(spawner, o, arglist[0], trigmob);
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.AMOUNTCARRIED)
{
// syntax is AMOUNTCARRIED,itemtype[[,banksearch],itemname]
int amount = 0;
if (value_keywordargs.Length > 1)
{
string typestr = value_keywordargs[1], namestr="*";
bool banksearch = false;
if(value_keywordargs.Length > 2)
{
if(!bool.TryParse(value_keywordargs[2], out banksearch))
{
status_str = "Invalid AMOUNTCARRIED banksearch boolean : " + arglist[1];
no_error = false;
}
else if(value_keywordargs.Length > 3)
{
namestr=value_keywordargs[3];
}
}
// get the list of items being carried of the specified type
Type targetType = SpawnerType.GetType(typestr);
if (targetType != null && trigmob != null && trigmob.Backpack != null)
{
Item[] items = trigmob.Backpack.FindItemsByType( targetType, true );
for ( int i = 0; i < items.Length; ++i )
{
if(CheckNameMatch(namestr, items[i].Name))
amount += items[i].Amount;
}
if(banksearch && trigmob.BankBox!=null)
{
items = trigmob.BankBox.FindItemsByType( targetType, true );
for ( int i = 0; i < items.Length; ++i )
{
if(CheckNameMatch(namestr, items[i].Name))
amount += items[i].Amount;
}
}
}
string result = SetPropertyValue(spawner, o, arglist[0], amount.ToString());
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
}
else
{
status_str = "Invalid AMOUNTCARRIED args : " + arglist[1];
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.PLAYERSINRANGE)
{
// syntax is PLAYERSINRANGE,range
int nplayers = 0;
int range = 0;
// get the number of players in range
if (value_keywordargs.Length > 1)
{
int.TryParse(value_keywordargs[1], out range);
}
// count nearby players
if (refobject is Item)
{
IPooledEnumerable ie = ((Item)refobject).GetMobilesInRange(range);
foreach (Mobile p in ie )
{
if (p.Player && p.AccessLevel == AccessLevel.Player) nplayers++;
}
ie.Free();
}
else if (refobject is Mobile)
{
IPooledEnumerable ie = ((Mobile)refobject).GetMobilesInRange(range);
foreach (Mobile p in ie)
{
if (p.Player && p.AccessLevel == AccessLevel.Player) nplayers++;
}
ie.Free();
}
string result = SetPropertyValue(spawner, o, arglist[0], nplayers.ToString());
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.TRIGSKILL)
{
if (value_keywordargs.Length > 1)
{
if (spawner != null && spawner.TriggerSkill != null)
{
string skillstr = null;
// syntax is TRIGSKILL,name|value|cap|base
if (value_keywordargs[1].ToLower() == "name")
{
skillstr = spawner.TriggerSkill.Name;
}
else
if (value_keywordargs[1].ToLower() == "value")
{
skillstr = spawner.TriggerSkill.Value.ToString();
}
else
if (value_keywordargs[1].ToLower() == "cap")
{
skillstr = spawner.TriggerSkill.Cap.ToString();
}
else
if (value_keywordargs[1].ToLower() == "base")
{
skillstr = spawner.TriggerSkill.Base.ToString();
}
string result = SetPropertyValue(spawner, o, arglist[0], skillstr);
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
}
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == valuemodKeyword.RANDNAME)
{
if (value_keywordargs.Length > 1)
{
string result = SetPropertyValue(spawner, o, arglist[0], NameList.RandomName(value_keywordargs[1]));
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
}
else
{
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
}
else if (IsTypemodKeyword(keywordargs[0]))
{
typemodKeyword kw = typemodKeywordHash[keywordargs[0]];
if (kw == typemodKeyword.MUSIC)
{
SendMusicToPlayers(arglist[0], trigmob, refobject, out status_str);
if (status_str != null)
{
no_error = false;
}
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
//
// SOUND keyword
//
else if (kw == typemodKeyword.SOUND)
{
int sound = -1;
// try to get the soundnumber argument
if (keywordargs.Length < 2)
{
status_str = "Missing sound number";
no_error = false;
}
else
{
if(!int.TryParse(keywordargs[1], out sound))
{ status_str = "Improper sound number format"; no_error = false; }
}
try
{
if (sound >= 0 && o is IEntity)
{
Effects.PlaySound(((IEntity)o).Location, ((IEntity)o).Map, sound);
}
}
catch { }
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
//
// EFFECT keyword
//
else if (kw == typemodKeyword.EFFECT)
{
int effect = -1;
int duration = 1;
// syntax is EFFECT,itemid,duration,[x,y,z]
// try to get the effect argument
if (keywordargs.Length < 2)
{
status_str = "Missing effect number";
no_error = false;
}
else
{
if(!int.TryParse(keywordargs[1], out effect))
{ status_str = "Improper effect number format"; no_error = false; }
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out duration))
{ status_str = "Improper effect duration format"; no_error = false; }
}
// by default just use the spawn location
Point3D eloc;
Map emap = Map.Internal;
if (o is Mobile)
{
eloc = ((Mobile)o).Location;
emap = ((Mobile)o).Map;
}
else if (o is Item)
{
eloc = ((Item)o).Location;
emap = ((Item)o).Map;
}
else
{
// should never get here
eloc = new Point3D(0, 0, 0);
}
if (keywordargs.Length > 3)
{
// is this applied to the trig mob or to a location?
if (keywordargs.Length > 5)
{
int x=0;
int y=0;
int z=0;
if(!int.TryParse(keywordargs[3], out x) || !int.TryParse(keywordargs[4], out y) || !int.TryParse(keywordargs[5], out z))
{ status_str = "Improper effect location format"; }
eloc = new Point3D(x, y, z);
}
}
if (effect >= 0 && emap != Map.Internal)
{
Effects.SendLocationEffect(eloc, emap, effect, duration);
}
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
//
// BOLTEFFECT keyword
//
else if (kw == typemodKeyword.BOLTEFFECT)
{
int sound = 0x29;
int hue = 0;
// syntax is BOLTEFFECT[,sound[,hue]]
// try to get the effect argument
if (keywordargs.Length > 1)
{
if(!int.TryParse(keywordargs[1], out sound))
{ status_str = "Improper sound id"; no_error = false; }
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out hue))
{ status_str = "Improper hue"; no_error = false; }
}
if (o is IEntity)
{
SendBoltEffect((IEntity)o, sound, hue);
}
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
//
// MEFFECT keyword
//
else if (kw == typemodKeyword.MEFFECT)
{
int effect = -1;
int duration = 0;
int speed = 1;
Point3D eloc1 = new Point3D(0, 0, 0);
Point3D eloc2 = new Point3D(0, 0, 0);
Map emap = Map.Internal;
bool hasloc = false;
// syntax is MEFFECT,itemid[,speed][,x,y,z][,x2,y2,z2]
// try to get the effect argument
if (keywordargs.Length < 2)
{
status_str = "Missing effect number";
no_error = false;
}
else
{
if(!int.TryParse(keywordargs[1], out effect))
{ status_str = "Improper effect number format"; no_error = false; }
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out speed))
{ status_str = "Improper effect speed format"; no_error = false; }
}
// by default just use the spawn location
if (o is Mobile)
{
eloc2 = ((Mobile)o).Location;
emap = ((Mobile)o).Map;
}
else if (o is Item)
{
eloc2 = ((Item)o).Location;
emap = ((Item)o).Map;
}
if (keywordargs.Length > 8)
{
int x=0;
int y=0;
int z=0;
if(!int.TryParse(keywordargs[3], out x) || !int.TryParse(keywordargs[4], out y) || !int.TryParse(keywordargs[5], out z))
{ status_str = "Improper effect location format"; }
eloc1 = new Point3D(x, y, z);
x=y=z=0;
if(!int.TryParse(keywordargs[6], out x) || !int.TryParse(keywordargs[7], out y) || !int.TryParse(keywordargs[8], out z))
{ status_str = "Improper effect location format"; }
eloc2 = new Point3D(x, y, z);
hasloc = true;
}
else
if (keywordargs.Length > 5)
{
int x = 0;
int y = 0;
int z = 0;
if(!int.TryParse(keywordargs[3], out x) || !int.TryParse(keywordargs[4], out y) || !int.TryParse(keywordargs[5], out z))
{ status_str = "Improper effect location format"; }
eloc1 = new Point3D(x, y, z);
hasloc = true;
}
if (effect >= 0 && hasloc && emap != Map.Internal)
{
Effects.SendPacket(eloc1, emap, new HuedEffect(EffectType.Moving, -1, -1, effect, eloc1, eloc2, speed, duration, false, false, 0, 0));
}
else
if (effect >= 0 && refobject is IEntity && o is IEntity)
{
//Effects.SendLocationEffect(eloc, emap, effect, duration);
//public static void SendMovingEffect( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes )
Effects.SendMovingEffect((IEntity)refobject, (IEntity)o, effect, speed, duration, false, false);
}
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
//
// PEFFECT keyword
//
else if (kw == typemodKeyword.PEFFECT)
{
int effect = -1;
int duration = 1;
// syntax is PEFFECT,itemid,duration,[x,y,z]
// try to get the effect argument
if (keywordargs.Length < 2)
{
status_str = "Missing effect number";
no_error = false;
}
else
{
if(!int.TryParse(keywordargs[1], out effect))
{ status_str = "Improper effect number format"; no_error = false; }
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out duration))
{ status_str = "Improper effect duration format"; no_error = false; }
}
// by default just use the spawn location
Point3D eloc;
Map emap = Map.Internal;
if (o is Mobile)
{
eloc = ((Mobile)o).Location;
emap = ((Mobile)o).Map;
}
else if (o is Item)
{
eloc = ((Item)o).Location;
emap = ((Item)o).Map;
}
else
{
// should never get here
eloc = new Point3D(0, 0, 0);
}
if (keywordargs.Length > 3)
{
// is this applied to the trig mob or to a location?
if (keywordargs.Length > 5)
{
int x = 0;
int y = 0;
int z = 0;
if(!int.TryParse(keywordargs[3], out x) || !int.TryParse(keywordargs[4], out y) || !int.TryParse(keywordargs[5], out z))
{ status_str = "Improper effect location format"; }
eloc = new Point3D(x, y, z);
}
}
if (effect >= 0 && emap != Map.Internal)
{
Effects.SendLocationEffect(eloc, emap, effect, duration);
}
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
//
// POISON keyword
//
else if (kw == typemodKeyword.POISON)
{
ApplyPoisonToPlayers(arglist[0], o as Mobile, o, out status_str);
//ApplyPoisonToPlayers(arglist[0], trigmob, refobject, out status_str);
if (status_str != null)
{
no_error = false;
}
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
else if (kw == typemodKeyword.DAMAGE)
{
// the syntax is DAMAGE,damage,phys,fire,cold,pois,energy[,range][,playeronly]
ApplyDamageToPlayers(arglist[0], o as Mobile, o, out status_str);
//ApplyDamageToPlayers(arglist[0], trigmob, refobject, out status_str);
if (status_str != null)
{
no_error = false;
}
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
else if (kw == typemodKeyword.ADD)
{
no_error = AddItemToTarget(spawner, o, keywordargs, arglist, trigmob, refobject, false, out remainder, out status_str);
}
else if (kw == typemodKeyword.EQUIP)
{
no_error = AddItemToTarget(spawner, o, keywordargs, arglist, trigmob, refobject, true, out remainder, out status_str);
}
else if (kw == typemodKeyword.DELETE)
{
if (o is Item)
{
((Item)o).Delete();
}
else if (o is Mobile)
{
if (!((Mobile)o).Player)
{
((Mobile)o).Delete();
}
}
else if (o is XmlAttachment)
{
((XmlAttachment)o).Delete();
}
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
else if (kw == typemodKeyword.KILL)
{
if (o is Mobile)
{
((Mobile)o).Kill();
}
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
else if (kw == typemodKeyword.UNEQUIP)
{
// syntax is UNEQUIP,layer[,delete]
Layer layer = Layer.Invalid;
bool remove = false;
if (keywordargs.Length > 1)
{
#if Framework_4_0
if(!Enum.TryParse(keywordargs[1], true, out layer))
#else
if(!TryParse(keywordargs[1], true, out layer))
#endif
{ status_str = "Invalid layer"; }
}
if (keywordargs.Length > 2)
{
if (keywordargs[2] == "delete")
{
remove = true;
}
else bool.TryParse(keywordargs[2], out remove);
}
if (o is Mobile && layer != Layer.Invalid)
{
Mobile m = (Mobile)o;
// go through all of the items on the mobile
List<Item> packlist = m.Items;
for (int i = 0; i < packlist.Count; ++i)
{
Item item = (Item)packlist[i];
// check the layer
// if it matches then unequip it
if (item.Layer == layer)
{
if (remove)
{
item.Delete();
}
else
{
m.AddToBackpack(item);
}
}
}
}
if (status_str != null)
{
no_error = false;
}
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
else if (kw == typemodKeyword.ATTACH)
{
no_error = AddAttachmentToTarget(spawner, o, keywordargs, arglist, trigmob, refobject, out remainder, out status_str);
}
else if (kw == typemodKeyword.MSG)
{
// syntax is MSG[,probability][,hue]
// if the object is a mobile then display a msg over the mob or item
double drop_probability = 1;
int hue = 0x3b2;
if (keywordargs.Length > 1)
{
if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability))
{ status_str = "Invalid msg probability : " + arglist[1]; no_error = false; }
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out hue))
{ status_str = "Invalid MSG hue : " + arglist[1]; no_error = false; }
}
if (hue < 0) hue = 0;
if (o is Mobile || o is Item)
{
string msgstr = arglist[1];
// test the drop probability
if (Utility.RandomDouble() < drop_probability)
{
if (o is Mobile)
((Mobile)o).PublicOverheadMessage(MessageType.Regular, hue, false, msgstr);
else
if (o is Item)
((Item)o).PublicOverheadMessage(MessageType.Regular, hue, false, msgstr);
}
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == typemodKeyword.ASCIIMSG)
{
// syntax is ASCIIMSG[,probability][,hue][,font]
// if the object is a mobile then display a msg over the mob or item
double drop_probability = 1;
int hue = 0x3b2;
int font = 3;
if (keywordargs.Length > 1)
{
if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability))
{ status_str = "Invalid msg probability : " + arglist[1]; no_error = false; }
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out hue))
{ status_str = "Invalid MSG hue : " + arglist[1]; no_error = false; }
}
if (keywordargs.Length > 3)
{
if(!int.TryParse(keywordargs[3], out font))
{ status_str = "Invalid MSG font : " + arglist[1]; no_error = false; }
}
if (hue < 0) hue = 0;
if (font < 0) font = 0;
if (o is Mobile || o is Item)
{
string msgstr = arglist[1];
// test the drop probability
if (Utility.RandomDouble() < drop_probability)
{
if (o is Mobile)
PublicOverheadMobileMessage((Mobile)o, MessageType.Regular, hue, font, msgstr, true);
else
if (o is Item)
PublicOverheadItemMessage((Item)o, MessageType.Regular, hue, font, msgstr);
}
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == typemodKeyword.SENDMSG)
{
// syntax is SENDMSG[,probability][,hue]/msg
// if the object is a mobile then display a msg over the mob or item
double drop_probability = 1;
int hue = 0x3b2;
int font = 3;
if (keywordargs.Length > 1)
{
if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability))
{ status_str = "Invalid msg probability : " + arglist[1]; no_error = false; }
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out hue))
{ status_str = "Invalid SENDMSG hue : " + arglist[1]; no_error = false; }
}
if (hue < 0) hue = 0;
if (o is Mobile)
{
string msgstr = arglist[1];
// test the drop probability
if (Utility.RandomDouble() < drop_probability)
{
((Mobile)o).Send(new UnicodeMessage(Serial.MinusOne, -1, MessageType.Regular, hue, font, "ENU", "System", msgstr));
}
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == typemodKeyword.SENDASCIIMSG)
{
// syntax is SENDASCIIMSG[,probability][,hue][,font]
// if the object is a mobile then display a msg over the mob or item
double drop_probability = 1;
int hue = 0x3b2;
int font = 3;
if (keywordargs.Length > 1)
{
if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability))
{ status_str = "Invalid msg probability : " + arglist[1]; no_error = false; }
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out hue))
{ status_str = "Invalid MSG hue : " + arglist[1]; no_error = false; }
}
if (keywordargs.Length > 3)
{
if(!int.TryParse(keywordargs[3], out font))
{ status_str = "Invalid MSG font : " + arglist[1]; no_error = false; }
}
if (hue < 0) hue = 0;
if (font < 0) font = 0;
if (o is Mobile)
{
string msgstr = arglist[1];
// test the drop probability
if (Utility.RandomDouble() < drop_probability)
{
((Mobile)o).Send(new AsciiMessage(Serial.MinusOne, -1, MessageType.Regular, hue, font, "System", msgstr));
}
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == typemodKeyword.SAY)
{
// if the object is a mobile then display a msg over the mob
double drop_probability = 1;
if (keywordargs.Length > 1)
{
if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability))
{ status_str = "Invalid say probability : " + arglist[1]; no_error = false; }
}
if (o is Mobile)
{
string msgstr = arglist[1];
// test the drop probability
if (Utility.RandomDouble() < drop_probability)
{
((Mobile)o).Say(msgstr);
}
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == typemodKeyword.SPEECH)
{
// syntax is SPEECH[,probability][,keywordnumber]
// if the object is a mobile then have it speak with optional keyword arg
double drop_probability = 1;
if (keywordargs.Length > 1)
{
if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability))
{ status_str = "Invalid speech probability : " + arglist[1]; no_error = false; }
}
int keyword_number = -1;
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out keyword_number))
{ status_str = "Invalid keyword number : " + arglist[1]; no_error = false; }
}
if (o is Mobile)
{
string msgstr = arglist[1];
// test the drop probability
if (Utility.RandomDouble() < drop_probability)
{
int[] keywordarray = new int[] { };
if (keyword_number >= 0)
{
keywordarray = new int[] { keyword_number };
}
((Mobile)o).DoSpeech(msgstr, keywordarray, MessageType.Regular, 0x3B2);
}
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == typemodKeyword.OFFSET)
{
// syntax is OFFSET,x,y[,z]
// shift the location of the object by the specified amount
int xoffset = 0;
int yoffset = 0;
int zoffset = 0;
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[1], out xoffset) || !int.TryParse(keywordargs[2], out yoffset))
{ status_str = "Invalid xy offset : " + arglist[1]; no_error = false; }
}
if (keywordargs.Length > 3)
{
if(!int.TryParse(keywordargs[3], out zoffset))
{ status_str = "Invalid zoffset : " + arglist[1]; no_error = false; }
}
if (o is Mobile)
{
Point3D loc = ((Mobile)o).Location;
((Mobile)o).Location = new Point3D(loc.X + xoffset, loc.Y + yoffset, loc.Z + zoffset);
}
else if (o is Item)
{
Point3D loc = ((Item)o).Location;
((Item)o).Location = new Point3D(loc.X + xoffset, loc.Y + yoffset, loc.Z + zoffset);
}
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
else if (kw == typemodKeyword.ANIMATE)
{
// syntax is ANIMATE,action[,framecount][,repeatcount][,forward true/false][,repeat true/false][delay]
// Animate( int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay )
int action=-1;
int framecount = 7;
int repeatcount = 1;
bool forward = true;
bool repeat = false;
int delay = 0;
if (keywordargs.Length > 1)
{
if(!int.TryParse(keywordargs[1], out action))
{ status_str = "Invalid action : " + arglist[1]; no_error = false; action=-1; }
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out framecount))
{ status_str = "Invalid framecount : " + arglist[1]; no_error = false; framecount=7; }
}
if (keywordargs.Length > 3)
{
if(!int.TryParse(keywordargs[3], out repeatcount))
{ status_str = "Invalid repeatcount : " + arglist[1]; no_error = false; repeatcount=1; }
}
if (keywordargs.Length > 4)
{
if(!bool.TryParse(keywordargs[4], out forward))
{ status_str = "Invalid forward : " + arglist[1]; no_error = false; forward=true; }
}
if (keywordargs.Length > 5)
{
if(!bool.TryParse(keywordargs[5], out repeat))
{ status_str = "Invalid repeat : " + arglist[1]; no_error = false; }
}
if (keywordargs.Length > 6)
{
if(!int.TryParse(keywordargs[6], out delay))
{ status_str = "Invalid delay : " + arglist[1]; no_error = false; }
}
if (o is Mobile && action >= 0)
{
((Mobile)o).Animate(action, framecount, repeatcount, forward, repeat, delay);
}
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
else if (kw == typemodKeyword.FACETO)
{
// the mobile will turn to the direction coordinates
// syntax is FACETO,x,y
if (o is Mobile)
{
Mobile m=(Mobile)o;
int dx=m.X, dy=m.Y;
if (keywordargs.Length > 2)
{
Int32.TryParse(keywordargs[1], out dx);
Int32.TryParse(keywordargs[2], out dy);
}
m.Direction = m.GetDirectionTo(dx,dy);
}
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
else if (kw == typemodKeyword.SETVALUE)
{
// syntax is SETVALUE,varname,value,duration - it's a wrapper for xmlvalue
if (keywordargs.Length > 3)
{
int val;
double duration;
int.TryParse(keywordargs[2], out val);
double.TryParse(keywordargs[3], NumberStyles.Any, CultureInfo.InvariantCulture, out duration);
XmlValue x = (XmlValue)XmlAttach.FindAttachment(o, typeof(XmlValue), keywordargs[1]);
if(x!=null)
{
x.Value+=val;
x.Expiration=TimeSpan.FromMinutes(duration);
}
else
{
XmlAttach.AttachTo(o, new XmlValue(keywordargs[1], val, duration));
}
}
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
else if (kw == typemodKeyword.FLASH)
{
//the mobile, only player, will get a flash effect
//syntax is FLASH,int (from 1 to 5)
// 1 is fade to black
// 2 is fade to white
// 3 is light flash
// 4 is light to black flash
// 5 is black flash
if(o is PlayerMobile)
{
PlayerMobile m=(PlayerMobile)o;
if(m.NetState!=null && m.NetState.Running)
{
short flash=0;
if(short.TryParse(keywordargs[1], out flash) && flash>0 && flash<6)
{
ScreenEffect se = new ScreenEffect((ScreenEffectType)(flash-1));
if(se!=null)
{
Packet.Acquire(se);
m.Send(se);
}
Packet.Release(se);
}
}
}
if (arglist.Length < 2) break;
remainder = singlearglist[1];
}
else if (kw == typemodKeyword.PRIVMSG)
{
// syntax is PRIVMSG[,probability][,hue]
// if the object is a mobile actively connected display the message
double drop_probability = 1;
int hue = 0x3b2;
if (keywordargs.Length > 1)
{
if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability))
{ status_str = "Invalid msg probability : " + arglist[1]; no_error = false; }
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out hue))
{ status_str = "Invalid MSG hue : " + arglist[1]; no_error = false; }
}
if (hue < 0) hue = 0;
if (o is Mobile)
{
string msgstr = arglist[1];
// test the drop probability
if (Utility.RandomDouble() < drop_probability)
{
Mobile mob = (Mobile)o;
mob.PrivateOverheadMessage(MessageType.Regular, hue, false, msgstr, mob.NetState);
}
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
else if (kw == typemodKeyword.BCAST)
{
// syntax is BCAST[,hue][,font]/message
int hue = 0x482;
int font = -1; // default unicode messages
if (keywordargs.Length > 1)
{
if(!int.TryParse(keywordargs[1], out hue))
{ status_str = "Invalid hue : " + arglist[1]; no_error = false; hue=0x482; }
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out font))
{ status_str = "Invalid font : " + arglist[1]; no_error = false; font=-1; }
}
if (font >= 0)
{
// broadcast an ascii message to all players
BroadcastAsciiMessage(AccessLevel.Player, hue, font, arglist[1]);
}
else
{
// broadcast a message to all players
CommandHandlers.BroadcastMessage(AccessLevel.Player, hue, arglist[1]);
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
}
//else // check for protected properties
// if(arglist[0].ToLower() == "accesslevel")
//{
// status_str = "accesslevel is a protected property";
// if(arglist.Length < 3) break;
// remainder = arglist[2];
//}
else
{
// check for the literal char
if (singlearglist[1] != null && singlearglist[1].Length > 0 && singlearglist[1][0] == '@')
{
//support for literal terminator
singlearglist = ParseLiteralTerminator(singlearglist[1]);
string lstr = singlearglist[0];
if (terminated && lstr[lstr.Length - 1] == '/')
lstr = lstr.Remove(lstr.Length - 1, 1);
string result = SetPropertyValue(spawner, o, arglist[0], lstr.Remove(0, 1));
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
if(singlearglist.Length>1 && singlearglist[1] != null)
{
// if(singlearglist[1].Length>0 && singlearglist[1][0]=='/')
// singlearglist[1].Remove(0, 1);
remainder = singlearglist[1];
}
else
{
remainder=null;
break;
}
}
else
{
string result = SetPropertyValue(spawner, o, arglist[0], arglist[1]);
// see if it was successful
if (result != "Property has been set.")
{
status_str = arglist[0] + " : " + result;
no_error = false;
}
if (arglist.Length < 3) break;
remainder = arglist[2];
}
}
}
}
}
return (no_error);
}
#endregion
#region Property testing
public static bool TestMobProperty(XmlSpawner spawner, Mobile mobile, string testString, Mobile trigmob, out string status_str)
{
status_str = null;
// now make sure the mobile itself is there
if (mobile == null || mobile.Deleted)
{
return false;
}
bool testreturn = CheckPropertyString(spawner, mobile, testString, trigmob, out status_str);
return testreturn;
}
public static bool TestItemProperty(XmlSpawner spawner, Item ObjectPropertyItem, string testString, Mobile trigmob, out string status_str)
{
status_str = null;
// now make sure the item itself is there
if (ObjectPropertyItem == null || ObjectPropertyItem.Deleted)
{
status_str = "Trigger Object not found";
return false;
}
bool testreturn = CheckPropertyString(spawner, ObjectPropertyItem, testString, trigmob, out status_str);
return testreturn;
}
public static PropertyInfo LookupPropertyInfo(XmlSpawner spawner, Type type, string propname)
{
if (spawner == null || type == null || propname == null) return null;
// look up the info in the current list
if (spawner.PropertyInfoList == null) spawner.PropertyInfoList = new List<TypeInfo>();
PropertyInfo pinfo = null;
TypeInfo tinfo = null;
foreach (TypeInfo to in spawner.PropertyInfoList)
{
// check the type
if (to.t == type)
{
// found it
tinfo = to;
// now search the property list
foreach (PropertyInfo p in to.plist)
{
if (Insensitive.Equals(p.Name, propname))
{
pinfo = p;
}
}
}
}
// did we find the property?
if (pinfo != null)
{
return pinfo;
}
else
{
// if it cant be found, then do the full search and add it to the list
PropertyInfo[] props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public);
foreach (PropertyInfo p in props)
{
if (Insensitive.Equals(p.Name, propname))
{
// did we find the type at least?
if (tinfo == null)
{
// if not then add the type to the list
tinfo = new TypeInfo();
tinfo.t = type;
spawner.PropertyInfoList.Add(tinfo);
}
// and add the property to the tinfo property list
tinfo.plist.Add(p);
return p;
}
}
}
return null;
}
public static string ParseForKeywords(XmlSpawner spawner, object o, string valstr, Mobile trigmob, bool literal, out Type ptype)
{
ptype = null;
if (valstr == null || valstr.Length <= 0) return null;
string str = valstr.Trim();
// look for keywords
// need to handle the case of nested arglists like arg,arg,<arg,arg>
// handle value keywords that may take comma args
// itemarglist[1] will contain arg2/arg3/arg4>/arg5
// additemstr should have the full list of args <arg2/arg3/arg4>/arg5 if they are there. In the case of /arg1/ADD/arg2
// it will just have arg2
string[] groupedarglist = ParseString(str, 2, "[");
// take that argument list that should like like arg2/ag3/arg4>/arg5
// need to find the matching ">"
string[] groupargs = null;
string groupargstring = null;
if (groupedarglist.Length > 1)
{
groupargs = ParseToMatchingParen(groupedarglist[1], '[', ']');
// and get the first part of the string without the > so itemargs[0] should be arg2/ag3/arg4
groupargstring = groupargs[0];
}
// need to handle comma args that may be grouped with the () such as the (ATTACHMENT,args) arg
//string[] arglist = ParseString(groupedarglist[0],4,",");
string[] arglist = groupedarglist[0].Trim().Split(',');
if (groupargstring != null && groupargstring.Length > 0)
{
if (arglist != null && arglist.Length > 0)
arglist[arglist.Length - 1] = groupargstring;
}
string pname = arglist[0].Trim();
char startc = str[0];
// first see whether it is a standard numeric value
if ((startc == '.') || (startc == '-') || (startc == '+') || (startc >= '0' && startc <= '9'))
{
// determine the type
if (str.IndexOf(".") >= 0)
{
ptype = typeof(Double);
}
else
{
ptype = typeof(Int32);
}
return str;
}
else
// or a string
if (startc == '"' || startc == '(')
{
ptype = typeof(String);
return str;
}
else
// or an enum
if (startc == '#')
{
ptype = typeof(String);
return str.Substring(1);
}
// or a bool
else if ((str.ToLower()) == "true" || (str.ToLower() == "false"))
{
ptype = typeof(Boolean);
return str;
}
// then look for a keyword
else if (IsValueKeyword(pname))
{
valueKeyword kw = valueKeywordHash[pname];
//if(pname == "GETONMOB" && arglist.Length > 2)
if ((kw == valueKeyword.GETONMOB) && arglist.Length > 2)
{
// syntax is GETONMOB,mobname[,mobtype],property
string propname = arglist[2];
string typestr = null;
if (arglist.Length > 3)
{
typestr = arglist[2];
propname = arglist[3];
}
Mobile testmobile = FindMobileByName(spawner, arglist[1], typestr);
string getvalue = GetPropertyValue(spawner, testmobile, propname, out ptype);
return ParseGetValue(getvalue, ptype);
}
else if ((kw == valueKeyword.GET) && arglist.Length > 2)
{
// syntax is GET,[itemname -OR- SETITEM][,itemtype],property
string propname = arglist[2];
string typestr = null;
if (arglist.Length > 3)
{
typestr = arglist[2];
propname = arglist[3];
}
// is the itemname a serialno?
object testitem = null;
if (arglist[1].StartsWith("0x"))
{
int serial;
if(!int.TryParse(arglist[1].Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out serial))
serial=-1;
if (serial >= 0)
testitem = World.FindEntity(serial);
}
else if(arglist[1]=="SETITEM" && spawner!=null && !spawner.Deleted && spawner.SetItem!=null)
{
testitem = spawner.SetItem;
}
else
{
testitem = FindItemByName(spawner, arglist[1], typestr);
}
string getvalue = GetPropertyValue(spawner, testitem, propname, out ptype);
return ParseGetValue(getvalue, ptype);
}
else if ((kw == valueKeyword.GETONCARRIED) && arglist.Length > 2)
{
// syntax is GETONCARRIED,itemname[,itemtype][,equippedonly],property
string propname = arglist[2];
string typestr = null;
bool equippedonly = false;
// if the itemtype arg has been specified then check it
if (arglist.Length > 3)
{
propname = arglist[3];
typestr = arglist[2];
}
if (arglist.Length > 4)
{
propname = arglist[4];
if (arglist[3].ToLower() == "equippedonly")
{
equippedonly = true;
}
else
{
bool.TryParse(arglist[3], out equippedonly);
}
}
Item testitem = SearchMobileForItem(trigmob, ParseObjectType(arglist[1]), typestr, false, equippedonly);
string getvalue = GetPropertyValue(spawner, testitem, propname, out ptype);
return ParseGetValue(getvalue, ptype);
}
else if ((kw == valueKeyword.GETONNEARBY) && arglist.Length > 3)
{
// syntax is GETONNEARBY,range,name[,type][,searchcontainers],property
// or GETONNEARBY,range,name[,type][,searchcontainers],[ATTACHMENT,type,name,property]
string targetname = arglist[2];
string propname = arglist[3];
string typestr = null;
bool searchcontainers = false;
int range;
if(!int.TryParse(arglist[1], out range))
range = -1;
if (arglist.Length > 4)
{
typestr = arglist[3];
propname = arglist[4];
}
if (arglist.Length > 5)
{
bool.TryParse(arglist[4], out searchcontainers);
propname = arglist[5];
}
Type targettype = null;
if (typestr != null)
{
targettype = SpawnerType.GetType(typestr);
}
if (range >= 0)
{
// get all of the nearby objects
object relativeto = spawner;
if (o is XmlAttachment)
{
relativeto = ((XmlAttachment)o).AttachedTo;
}
List<object> nearbylist = GetNearbyObjects(relativeto, targetname, targettype, typestr, range, searchcontainers, null);
// apply the properties from the first valid thing on the list
foreach (object nearbyobj in nearbylist)
{
string getvalue = GetPropertyValue(spawner, nearbyobj, propname, out ptype);
return ParseGetValue(getvalue, ptype);
}
}
else
return null;
}
else if ((kw == valueKeyword.GETONTRIGMOB) && arglist.Length > 1)
{
// syntax is GETONTRIGMOB,property
string getvalue = GetPropertyValue(spawner, trigmob, arglist[1], out ptype);
return ParseGetValue(getvalue, ptype);
}
else if ((kw == valueKeyword.GETVAR) && arglist.Length > 1)
{
// syntax is GETVAR,varname
string varname = arglist[1];
if (o is XmlAttachment)
o = ((XmlAttachment)o).AttachedTo;
// look for the xmllocalvariable attachment with the given name
XmlLocalVariable var = (XmlLocalVariable)XmlAttach.FindAttachment(o, typeof(XmlLocalVariable), varname);
if (var != null)
{
return var.Data;
}
else
{
return null;
}
}
else if ((kw == valueKeyword.GETONPARENT) && arglist.Length > 1)
{
// syntax is GETONPARENT,property
string getvalue = null;
if (o is Item)
{
getvalue = GetPropertyValue(spawner, ((Item)o).Parent, arglist[1], out ptype);
}
else
if (o is XmlAttachment)
{
getvalue = GetPropertyValue(spawner, ((XmlAttachment)o).AttachedTo, arglist[1], out ptype);
}
return ParseGetValue(getvalue, ptype);
}
else if ((kw == valueKeyword.GETONGIVEN) && arglist.Length > 1)
{
// syntax is GETONGIVEN,property
Item taken = null;
if (o is XmlAttachment)
{
taken = GetGiven(((XmlAttachment)o).AttachedTo);
}
else
{
taken = GetGiven(o);
}
string getvalue = GetPropertyValue(spawner, taken, arglist[1], out ptype);
return ParseGetValue(getvalue, ptype);
}
else if ((kw == valueKeyword.GETONTAKEN) && arglist.Length > 1)
{
// syntax is GETONTAKEN,property
Item taken = null;
if (o is XmlAttachment)
{
taken = GetTaken(((XmlAttachment)o).AttachedTo);
}
else
{
taken = GetTaken(o);
}
string getvalue = GetPropertyValue(spawner, taken, arglist[1], out ptype);
return ParseGetValue(getvalue, ptype);
}
else if ((kw == valueKeyword.GETONTHIS) && arglist.Length > 1)
{
// syntax is GETONTHIS,property
string getvalue = GetPropertyValue(spawner, o, arglist[1], out ptype);
return ParseGetValue(getvalue, ptype);
}
else if ((kw == valueKeyword.GETONSPAWN) && arglist.Length > 2)
{
// syntax is GETONSPAWN[,spawnername],subgroup,property
// get the target from the spawn list
string subgroupstr = arglist[1];
string propstr = arglist[2];
string spawnerstr = null;
if (arglist.Length > 3)
{
spawnerstr = arglist[1];
subgroupstr = arglist[2];
propstr = arglist[3];
}
int subgroup;
if(!int.TryParse(subgroupstr, out subgroup))
subgroup = -1;
if (subgroup == -1) return null;
if (spawnerstr != null)
{
spawner = FindSpawnerByName(spawner, spawnerstr);
}
// check for the special COUNT property keyword
if (propstr == "COUNT")
{
ptype = typeof(int);
// get all of the currently active spawns with the specified subgroup
List<object> so = XmlSpawner.GetSpawnedList(spawner, subgroup);
if (so == null) return "0";
// and return the count
return so.Count.ToString();
}
else
{
object targetobj = XmlSpawner.GetSpawned(spawner, subgroup);
if (targetobj == null) return null;
string getvalue = GetPropertyValue(spawner, targetobj, propstr, out ptype);
return ParseGetValue(getvalue, ptype);
}
}
else if ((kw == valueKeyword.GETFROMFILE) && arglist.Length > 1)
{
// syntax is GETFROMFILE,filename
ptype = typeof(string);
string filename = arglist[1];
string filestring = null;
// read in the string from the file
if (System.IO.File.Exists(filename) == true)
{
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)
{
filestring += line;
}
sr.Close();
}
}
catch { }
}
return filestring;
}
else if ((kw == valueKeyword.GETACCOUNTTAG) && arglist.Length > 1)
{
// syntax is GETACCOUNTTAG,tagname
ptype = typeof(string);
string tagname = arglist[1];
string tagvalue = null;
// get the value of the account tag from the triggering mob
if (trigmob != null && !trigmob.Deleted)
{
Account acct = trigmob.Account as Account;
if (acct != null)
{
tagvalue = '"' + acct.GetTag(tagname) + '"';
}
}
return tagvalue;
}
else if ((kw == valueKeyword.RND) && arglist.Length > 2)
{
// syntax is RND,min,max
string randvalue = "0";
ptype = typeof(Int32);
int min,max;
if(int.TryParse(arglist[1], out min) && int.TryParse(arglist[2], out max))
randvalue=string.Format("{0}", Utility.RandomMinMax(min, max));
// return the random number as the value
return randvalue;
}
else if ((kw == valueKeyword.RNDBOOL))
{
// syntax is RNDBOOL
ptype = typeof(bool);
// return the random number as the value
return Utility.RandomBool().ToString();
}
else if ((kw == valueKeyword.RNDLIST) && arglist.Length > 1)
{
// syntax is RNDLIST,val1,val2,...
ptype = typeof(Int32);
// compute a random index into the arglist
int randindex = Utility.Random(1, arglist.Length - 1);
// return the list entry as the value
return arglist[randindex];
}
else if ((kw == valueKeyword.RNDSTRLIST) && arglist.Length > 1)
{
// syntax is RNDSTRLIST,val1,val2,...
ptype = typeof(string);
// compute a random index into the arglist
int randindex = Utility.Random(1, arglist.Length - 1);
if(trigmob!=null)
{
if(arglist[randindex].Contains("$TRIGNAME"))
arglist[randindex]=arglist[randindex].Replace("$TRIGNAME", trigmob.Name);
}
// return the list entry as the value
return arglist[randindex];
}
else if ((kw == valueKeyword.AMOUNTCARRIED) && arglist.Length > 1)
{
// syntax is AMOUNTCARRIED,itemtype[,banksearch[,itemname]]
ptype = typeof(Int32);
int amount = 0;
string typestr = arglist[1];
if (typestr != null)
{
string namestr="*";
bool banksearch = false;
if(arglist.Length > 2)
{
if(!bool.TryParse(arglist[2], out banksearch) && arglist[2].ToLowerInvariant() != "banksearch")
{
return null;
}
else if(arglist.Length > 3)
{
namestr=arglist[3];
}
}
// get the list of items being carried of the specified type
Type targetType = SpawnerType.GetType(typestr);
if (targetType != null && trigmob != null && trigmob.Backpack != null)
{
Item[] items = trigmob.Backpack.FindItemsByType( targetType, true );
for ( int i = 0; i < items.Length; ++i )
{
if(CheckNameMatch(namestr, items[i].Name))
amount += items[i].Amount;
}
if(banksearch && trigmob.BankBox!=null)
{
items = trigmob.BankBox.FindItemsByType( targetType, true );
for ( int i = 0; i < items.Length; ++i )
{
if(CheckNameMatch(namestr, items[i].Name))
amount += items[i].Amount;
}
}
}
}
return amount.ToString();
}
else if ((kw == valueKeyword.PLAYERSINRANGE) && arglist.Length > 1)
{
// syntax is PLAYERSINRANGE,range
ptype = typeof(Int32);
int nplayers = 0;
int range;
// get the number of players in range
int.TryParse(arglist[1], out range);
// count nearby players
if(spawner!=null && spawner.SpawnRegion!=null && range<0)
{
foreach(Mobile p in spawner.SpawnRegion.GetPlayers())
{
if (p.AccessLevel <= spawner.TriggerAccessLevel) nplayers++;
}
}
else if (o is Item)
{
IPooledEnumerable ie = ((Item)o).GetMobilesInRange(range);
foreach (Mobile p in ie)
{
if (p.Player && p.AccessLevel == AccessLevel.Player) nplayers++;
}
ie.Free();
}
else if (o is Mobile)
{
IPooledEnumerable ie = ((Mobile)o).GetMobilesInRange(range);
foreach (Mobile p in ie)
{
if (p.Player && p.AccessLevel == AccessLevel.Player) nplayers++;
}
ie.Free();
}
return nplayers.ToString();
}
else if ((kw == valueKeyword.TRIGSKILL) && arglist.Length > 1)
{
if (spawner != null && spawner.TriggerSkill != null)
{
// syntax is TRIGSKILL,name|value|cap|base
if (arglist[1].ToLower() == "name")
{
ptype = typeof(string);
return spawner.TriggerSkill.Name;
}
else if (arglist[1].ToLower() == "value")
{
ptype = typeof(double);
return spawner.TriggerSkill.Value.ToString();
}
else if (arglist[1].ToLower() == "cap")
{
ptype = typeof(double);
return spawner.TriggerSkill.Cap.ToString();
}
else if (arglist[1].ToLower() == "base")
{
ptype = typeof(double);
return spawner.TriggerSkill.Base.ToString();
}
}
return null;
}
if ((kw == valueKeyword.RANDNAME) && arglist.Length > 1)
{
// syntax is RANDNAME,nametype
return NameList.RandomName(arglist[1]);
}
else
{
// an invalid keyword format will be passed as literal
return str;
}
}
else if (literal)
{
ptype = typeof(String);
return str;
}
else
{
// otherwise treat it as a property name
string result = GetPropertyValue(spawner, o, pname, out ptype);
return ParseGetValue(result, ptype);
}
}
public static string ParseGetValue(string str, Type ptype)
{
// the results of getPropertyValue takes the form
// propname = value
// or
// propname = value (hexvalue)
if (str == null) return null;
// find the separator
string[] arglist = str.Split("=".ToCharArray(), 2);
if (arglist.Length > 1)
{
if (IsNumeric(ptype))
{
// parse the value portion and get rid of the possible (hexvalue) portion of the string
string[] arglist2 = arglist[1].Trim().Split(" ".ToCharArray(), 2);
return arglist2[0];
}
else
{
// for everything else
// pass on as is
return arglist[1].Trim();
}
}
else
{
return null;
}
}
public static bool CheckSubstitutedPropertyString(XmlSpawner spawner, object o, string testString, Mobile trigmob, out string status_str)
{
string substitutedtest = ApplySubstitution(spawner, o, trigmob, testString);
return CheckPropertyString(spawner, o, substitutedtest, trigmob, out status_str);
}
public static bool CheckPropertyString(XmlSpawner spawner, object o, string testString, Mobile trigmob, out string status_str)
{
status_str = null;
if (o == null) return false;
if (testString == null || testString.Length < 1)
{
status_str = "Null property test string";
return false;
}
// parse the property test string for and(&)/or(|) operators
string[] arglist = ParseString(testString, 2, "&|");
if (arglist.Length < 2)
{
bool returnval = CheckSingleProperty(spawner, o, testString, trigmob, out status_str);
// simple conditional test with no and/or operators
return returnval;
}
else
{
// test each half independently and combine the results
bool first = CheckSingleProperty(spawner, o, arglist[0], trigmob, out status_str);
// this will recursively parse the property test string with implicit nesting for multiple logical tests of the
// form A * B * C * D being grouped as A * (B * (C * D))
bool second = CheckPropertyString(spawner, o, arglist[1], trigmob, out status_str);
int andposition = testString.IndexOf("&");
int orposition = testString.IndexOf("|");
// combine them based upon the operator
if ((andposition > 0 && orposition <= 0) || (andposition > 0 && andposition < orposition))
{
// and operator
return (first && second);
}
else
if ((orposition > 0 && andposition <= 0) || (orposition > 0 && orposition < andposition))
{
// or operator
return (first || second);
}
else
{
// should never get here
return false;
}
}
}
public static bool CheckSingleProperty(XmlSpawner spawner, object o, string testString, Mobile trigmob, out string status_str)
{
status_str = null;
if (o == null || testString == null || testString.Length == 0) return false;
//get the prop name and test value
// format will be prop=prop, or prop>prop, prop<prop, prop!prop
// also support the 'not' operator ~ at the beginning of a test, like ~prop=prop
testString = testString.Trim();
bool invertreturn = false;
if (testString.Length > 0 && testString[0] == '~')
{
invertreturn = true;
testString = testString.Substring(1, testString.Length - 1);
}
string[] arglist = ParseString(testString, 2, "=><!");
if (arglist.Length < 2)
{
status_str = "invalid property string : " + testString;
return false;
}
bool hasequal = false;
bool hasnotequals = false;
bool hasgreaterthan = false;
bool haslessthan = false;
if (testString.IndexOf("=") > 0)
{
hasequal = true;
}
else
if (testString.IndexOf("!") > 0)
{
hasnotequals = true;
}
else
if (testString.IndexOf(">") > 0)
{
hasgreaterthan = true;
}
else
if (testString.IndexOf("<") > 0)
{
haslessthan = true;
}
// does it have a valid operator?
if (!hasequal && !hasgreaterthan && !haslessthan && !hasnotequals)
return false;
Type ptype1;
Type ptype2;
string value1 = ParseForKeywords(spawner, o, arglist[0].Trim(), trigmob, false, out ptype1);
// see if it was successful
if (ptype1 == null)
{
status_str = arglist[0] + " : " + value1;
return invertreturn;
//return false;
}
string value2 = ParseForKeywords(spawner, o, arglist[1].Trim(), trigmob, false, out ptype2);
// see if it was successful
if (ptype2 == null)
{
status_str = arglist[1] + " : " + value2;
return invertreturn;
//return false;
}
// look for hex numeric specifications
int base1 = 10;
int base2 = 10;
if (IsNumeric(ptype1) && !string.IsNullOrEmpty(value1) && value1.StartsWith("0x"))
{
base1 = 16;
}
if (IsNumeric(ptype2) && !string.IsNullOrEmpty(value2) && value2.StartsWith("0x"))
{
base2 = 16;
}
// and do the type dependent comparisons
if (ptype2 == typeof(TimeSpan) || ptype1 == typeof(TimeSpan))
{
if (hasequal)
{
TimeSpan ts1,ts2;
if(TimeSpan.TryParse(value1, out ts1) && TimeSpan.TryParse(value2, out ts2))
{
if(ts1==ts2) return !invertreturn;
}
else
{
status_str = "invalid timespan comparison : {0}" + testString;
}
}
else if (hasnotequals)
{
TimeSpan ts1,ts2;
if(TimeSpan.TryParse(value1, out ts1) && TimeSpan.TryParse(value2, out ts2))
{
if(ts1!=ts2) return !invertreturn;
}
else
{
status_str = "invalid timespan comparison : {0}" + testString;
}
}
else if (hasgreaterthan)
{
TimeSpan ts1,ts2;
if(TimeSpan.TryParse(value1, out ts1) && TimeSpan.TryParse(value2, out ts2))
{
if(ts1>ts2) return !invertreturn;
}
else
{
status_str = "invalid timespan comparison : {0}" + testString;
}
}
else if (haslessthan)
{
TimeSpan ts1,ts2;
if(TimeSpan.TryParse(value1, out ts1) && TimeSpan.TryParse(value2, out ts2))
{
if(ts1<ts2) return !invertreturn;
}
else
{
status_str = "invalid timespan comparison : {0}" + testString;
}
}
}
else
// and do the type dependent comparisons
if (ptype2 == typeof(DateTime) || ptype1 == typeof(DateTime))
{
if (hasequal)
{
DateTime dt1,dt2;
if(DateTime.TryParse(value1, out dt1) && DateTime.TryParse(value2, out dt2))
{
if(dt1==dt2) return !invertreturn;
}
else
{
status_str = "invalid DateTime comparison : {0}" + testString;
}
}
else if (hasnotequals)
{
DateTime dt1,dt2;
if(DateTime.TryParse(value1, out dt1) && DateTime.TryParse(value2, out dt2))
{
if(dt1!=dt2) return !invertreturn;
}
else
{
status_str = "invalid DateTime comparison : {0}" + testString;
}
}
else if (hasgreaterthan)
{
DateTime dt1,dt2;
if(DateTime.TryParse(value1, out dt1) && DateTime.TryParse(value2, out dt2))
{
if(dt1>dt2) return !invertreturn;
}
else
{
status_str = "invalid DateTime comparison : {0}" + testString;
}
}
else if (haslessthan)
{
DateTime dt1,dt2;
if(DateTime.TryParse(value1, out dt1) && DateTime.TryParse(value2, out dt2))
{
if(dt1<dt2) return !invertreturn;
}
else
{
status_str = "invalid DateTime comparison : {0}" + testString;
}
}
}
else
// and do the type dependent comparisons
if (IsNumeric(ptype2) && IsNumeric(ptype1))
{
//TODO: howto convert with tryparse?
if (hasequal)
{
try
{
if (Convert.ToInt64(value1, base1) == Convert.ToInt64(value2, base2)) return !invertreturn;
}
catch
{
status_str = "invalid int comparison : {0}" + testString;
}
}
else if (hasnotequals)
{
try
{
if (Convert.ToInt64(value1, base1) != Convert.ToInt64(value2, base2)) return !invertreturn;
}
catch
{
status_str = "invalid int comparison : {0}" + testString;
}
}
else if (hasgreaterthan)
{
try
{
if (Convert.ToInt64(value1, base1) > Convert.ToInt64(value2, base2)) return !invertreturn;
}
catch { status_str = "invalid int comparison : {0}" + testString; }
}
else if (haslessthan)
{
try
{
if (Convert.ToInt64(value1, base1) < Convert.ToInt64(value2, base2)) return !invertreturn;
}
catch { status_str = "invalid int comparison : {0}" + testString; }
}
}
else
if ((ptype2 == typeof(double)) && IsNumeric(ptype1))
{
//TODO: howto convert correctly with int64.tryparse?
if (hasequal)
{
try
{
if (Convert.ToInt64(value1, base1) == double.Parse(value2)) return !invertreturn;
}
catch
{
status_str = "invalid int comparison : {0}" + testString;
}
}
else
if (hasnotequals)
{
try
{
if (Convert.ToInt64(value1, base1) != double.Parse(value2)) return !invertreturn;
}
catch
{
status_str = "invalid int comparison : {0}" + testString;
}
}
else
if (hasgreaterthan)
{
try
{
if (Convert.ToInt64(value1, base1) > double.Parse(value2)) return !invertreturn;
}
catch { status_str = "invalid int comparison : {0}" + testString; }
}
else
if (haslessthan)
{
try
{
if (Convert.ToInt64(value1, base1) < double.Parse(value2)) return !invertreturn;
}
catch { status_str = "invalid int comparison : {0}" + testString; }
}
}
else
if ((ptype1 == typeof(double)) && IsNumeric(ptype2))
{
//TODO: howto convert correctly with int64.tryparse?
if (hasequal)
{
try
{
if (double.Parse(value1) == Convert.ToInt64(value2, base2)) return !invertreturn;
}
catch
{
status_str = "invalid int comparison : {0}" + testString;
}
}
else
if (hasnotequals)
{
try
{
if (double.Parse(value1) != Convert.ToInt64(value2, base2)) return !invertreturn;
}
catch
{
status_str = "invalid int comparison : {0}" + testString;
}
}
else
if (hasgreaterthan)
{
try
{
if (double.Parse(value1) > Convert.ToInt64(value2, base2)) return !invertreturn;
}
catch { status_str = "invalid int comparison : {0}" + testString; }
}
else
if (haslessthan)
{
try
{
if (double.Parse(value1) < Convert.ToInt64(value2, base2)) return !invertreturn;
}
catch { status_str = "invalid int comparison : {0}" + testString; }
}
}
else
if ((ptype1 == typeof(double)) && (ptype2 == typeof(double)))
{
double val1=0,val2=0;
if (hasequal)
{
if(double.TryParse(value1, NumberStyles.Any, CultureInfo.InvariantCulture, out val1) && double.TryParse(value2, NumberStyles.Any, CultureInfo.InvariantCulture, out val2))
{
if(val1==val2)
return !invertreturn;
}
else
{
status_str = "invalid int comparison : {0}" + testString;
}
}
else if (hasnotequals)
{
if(double.TryParse(value1, NumberStyles.Any, CultureInfo.InvariantCulture, out val1) && double.TryParse(value2, NumberStyles.Any, CultureInfo.InvariantCulture, out val2))
{
if(val1!=val2)
return !invertreturn;
}
else
{
status_str = "invalid int comparison : {0}" + testString;
}
}
else if (hasgreaterthan)
{
if(double.TryParse(value1, NumberStyles.Any, CultureInfo.InvariantCulture, out val1) && double.TryParse(value2, NumberStyles.Any, CultureInfo.InvariantCulture, out val2))
{
if(val1>val2)
return !invertreturn;
}
else { status_str = "invalid int comparison : {0}" + testString; }
}
else if (haslessthan)
{
if(double.TryParse(value1, NumberStyles.Any, CultureInfo.InvariantCulture, out val1) && double.TryParse(value2, NumberStyles.Any, CultureInfo.InvariantCulture, out val2))
{
if(val1<val2)
return !invertreturn;
}
else { status_str = "invalid int comparison : {0}" + testString; }
}
}
else
if (ptype2 == typeof(Boolean) && ptype1 == typeof(Boolean))
{
bool val1, val2;
if (hasequal)
{
if(bool.TryParse(value1, out val1) && bool.TryParse(value2, out val2))
{
if(val1==val2) return !invertreturn;
}
else{ status_str = "invalid bool comparison : {0}" + testString; }
}
else if (hasnotequals)
{
if(bool.TryParse(value1, out val1) && bool.TryParse(value2, out val2))
{
if(val1!=val2) return !invertreturn;
}
else{ status_str = "invalid bool comparison : {0}" + testString; }
}
}
else
if (ptype2 == typeof(Double) || ptype2 == typeof(Double))
{
double val1=0, val2=0;
if (hasequal)
{
if(double.TryParse(value1, NumberStyles.Any, CultureInfo.InvariantCulture, out val1) && double.TryParse(value2, NumberStyles.Any, CultureInfo.InvariantCulture, out val2))
{
if(val1==val2) return !invertreturn;
}
else{ status_str = "invalid double comparison : {0}" + testString; }
}
else if (hasnotequals)
{
if(double.TryParse(value1, NumberStyles.Any, CultureInfo.InvariantCulture, out val1) && double.TryParse(value2, NumberStyles.Any, CultureInfo.InvariantCulture, out val2))
{
if(val1!=val2) return !invertreturn;
}
else{ status_str = "invalid double comparison : {0}" + testString; }
}
else if (hasgreaterthan)
{
if(double.TryParse(value1, NumberStyles.Any, CultureInfo.InvariantCulture, out val1) && double.TryParse(value2, NumberStyles.Any, CultureInfo.InvariantCulture, out val2))
{
if(val1>val2) return !invertreturn;
}
else{ status_str = "invalid double comparison : {0}" + testString; }
}
else if (haslessthan)
{
if(double.TryParse(value1, NumberStyles.Any, CultureInfo.InvariantCulture, out val1) && double.TryParse(value2, NumberStyles.Any, CultureInfo.InvariantCulture, out val2))
{
if(val1<val2) return !invertreturn;
}
else{ status_str = "invalid double comparison : {0}" + testString; }
}
}
else
{
// by default just do a string comparison
if (hasequal)
{
if (value1 == value2) return !invertreturn;
}
else
if (hasnotequals)
{
if (value1 != value2) return !invertreturn;
}
}
return invertreturn;
}
#endregion
#region Search object methods
private static bool CheckNameMatch(string targetname, string name)
{
// a "*" targetname will match anything
// a null or empty targetname will match a null name
// otherwise the strings must match
return (targetname == "*") || (name == targetname) || (targetname != null && targetname.Length == 0 && name == null);
}
private static void GetItemsIn(Item source, string targetname, Type targettype, string typestr, ref List<object> nearbylist, string proptest)
{
string status_str;
if (source != null && source.Items != null && nearbylist != null)
{
foreach (Item i in source.Items)
{
// check the type and name
Type itemtype = i.GetType();
if (!i.Deleted && CheckNameMatch(targetname, i.Name) && (typestr == null ||
(itemtype != null && targettype != null && (itemtype.Equals(targettype) || itemtype.IsSubclassOf(targettype)))))
{
if (proptest == null || CheckPropertyString(null, i, proptest, null, out status_str))
nearbylist.Add(i);
}
if (i is Container)
{
GetItemsIn(i, targetname, targettype, typestr, ref nearbylist, proptest);
}
}
}
}
private static List<object> GetNearbyObjects(object invoker, string targetname, Type targettype, string typestr, int range, bool searchcontainers, string proptest)
{
IPooledEnumerable itemlist = null;
IPooledEnumerable mobilelist = null;
List<object> nearbylist = new List<object>();
string status_str;
// get nearby items
if (targettype == null || targettype == typeof(Item) || targettype.IsSubclassOf(typeof(Item)))
{
if (invoker is Item)
{
itemlist = ((Item)invoker).GetItemsInRange(range);
}
else
if (invoker is Mobile)
{
itemlist = ((Mobile)invoker).GetItemsInRange(range);
}
if (itemlist != null)
{
foreach (Item i in itemlist)
{
// check the type and name
Type itemtype = i.GetType();
if (searchcontainers)
{
if (i is Container)
GetItemsIn(i, targetname, targettype, typestr, ref nearbylist, proptest);
}
else
if (!i.Deleted && CheckNameMatch(targetname, i.Name) && (typestr == null ||
(itemtype != null && targettype != null && (itemtype.Equals(targettype) || itemtype.IsSubclassOf(targettype)))))
{
if (proptest == null || CheckPropertyString(null, i, proptest, null, out status_str))
nearbylist.Add(i);
}
}
itemlist.Free();
}
}
// get nearby mobiles
if (targettype == null || targettype == typeof(Mobile) || targettype.IsSubclassOf(typeof(Mobile)))
{
if (invoker is Item)
{
mobilelist = ((Item)invoker).GetMobilesInRange(range);
}
else
if (invoker is Mobile)
{
mobilelist = ((Mobile)invoker).GetMobilesInRange(range);
}
if (mobilelist != null)
{
foreach (Mobile m in mobilelist)
{
// check the type and name
Type mobtype = m.GetType();
if (!m.Deleted && CheckNameMatch(targetname, m.Name) && (typestr == null ||
(mobtype != null && targettype != null && (mobtype.Equals(targettype) || mobtype.IsSubclassOf(targettype)))))
{
if (proptest == null || CheckPropertyString(null, m, proptest, null, out status_str))
nearbylist.Add(m);
}
}
mobilelist.Free();
}
}
return nearbylist;
}
public static Item SearchMobileForItem(Mobile m, string targetName, string typeStr, bool searchbank)
{
return SearchMobileForItem(m, targetName, typeStr, searchbank, false);
}
public static Item SearchMobileForItem(Mobile m, string targetName, string typeStr, bool searchbank, bool equippedonly)
{
if (m != null && !m.Deleted)
{
// go through all of the items in the pack
List<Item> packlist = m.Items;
for (int i = 0; i < packlist.Count; ++i)
{
Item item = packlist[i];
// dont search bank boxes
if (item is BankBox && !searchbank && !equippedonly) continue;
// recursively search containers
if (item != null && !item.Deleted)
{
if (item is Container && !equippedonly)
{
Item itemTarget = SearchPackForItem((Container)item, targetName, typeStr);
if (itemTarget != null) return itemTarget;
}
// test the item name against the trigger string
// if a typestring has been specified then check against that as well
if (CheckNameMatch(targetName, item.Name))
{
if ((typeStr == null || CheckType(item, typeStr)))
{
//found it
return item;
}
}
}
}
// now check any item that might be held
Item held = m.Holding;
if (held != null && !held.Deleted && !equippedonly)
{
if (held is Container)
{
Item itemTarget = SearchPackForItem((Container)held, targetName, typeStr);
if (itemTarget != null) return itemTarget;
}
// test the item name against the trigger string
if (CheckNameMatch(targetName, held.Name))
{
if (typeStr == null || CheckType(held, typeStr))
{
//found it
return held;
}
}
}
}
return null;
}
public static List<Item> SearchMobileForItems(Mobile m, string targetName, string typeStr, bool searchbank, bool equippedonly)
{
List<Item> itemlist = new List<Item>();
if (m != null && !m.Deleted)
{
// go through all of the items in the pack
List<Item> packlist = m.Items;
for (int i = 0; i < packlist.Count; ++i)
{
Item item = packlist[i];
// dont search bank boxes
if (item is BankBox && (!searchbank || equippedonly)) continue;
// recursively search containers
if (item != null && !item.Deleted)
{
if (item is Container && !equippedonly)
{
itemlist.AddRange(SearchPackForItems((Container)item, targetName, typeStr));
}
// test the item name against the trigger string
// if a typestring has been specified then check against that as well
else if (CheckNameMatch(targetName, item.Name))
{
if ((typeStr == null || CheckType(item, typeStr)))
{
//found it
itemlist.Add(item);
}
}
}
}
// now check any item that might be held
Item held = m.Holding;
if (held != null && !held.Deleted && !equippedonly)
{
if (held is Container)
{
itemlist.AddRange(SearchPackForItems((Container)held, targetName, typeStr));
}
// test the item name against the trigger string
else if (CheckNameMatch(targetName, held.Name))
{
if (typeStr == null || CheckType(held, typeStr))
{
//found it
itemlist.Add(held);
}
}
}
}
return itemlist;
}
public static Item SearchPackForItemType(Container pack, string targetName)
{
if (pack != null && !pack.Deleted && targetName != null && targetName.Length > 0)
{
Type targetType = SpawnerType.GetType(targetName);
// go through all of the items in the pack
List<Item> packlist = pack.Items;
for (int i = 0; i < packlist.Count; ++i)
{
Item item = (Item)packlist[i];
if (item != null && !item.Deleted)
{
if (item is Container)
{
Item itemTarget = SearchPackForItemType((Container)item, targetName);
if (itemTarget != null) return itemTarget;
}
// test the item name against the trigger string
if (item.GetType() == targetType)
{
//found it
return item;
}
}
}
}
return null;
}
public static Item SearchMobileForItemType(Mobile m, string targetName, bool searchbank)
{
if (m != null && !m.Deleted && targetName != null && targetName.Length > 0)
{
Type targetType = SpawnerType.GetType(targetName);
// go through all of the items in the pack
List<Item> packlist = m.Items;
for (int i = 0; i < packlist.Count; ++i)
{
Item item = (Item)packlist[i];
// dont search bank boxes
if (item is BankBox && !searchbank) continue;
// recursively search containers
if (item != null && !item.Deleted)
{
if (item is Container)
{
Item itemTarget = SearchPackForItemType((Container)item, targetName);
if (itemTarget != null) return itemTarget;
}
// test the item type against the trigger string
if ((item.GetType() == targetType))
{
//found it
return item;
}
}
}
// now check any item that might be held
Item held = m.Holding;
if (held != null && !held.Deleted)
{
if (held is Container)
{
Item itemTarget = SearchPackForItemType((Container)held, targetName);
if (itemTarget != null) return itemTarget;
}
// test the item name against the trigger string
if (held.GetType() == targetType)
{
//found it
return held;
}
}
}
return null;
}
public static Item SearchPackForItem(Container pack, string targetName, string typestr)
{
if (pack != null && !pack.Deleted)
{
Type targettype = null;
if (typestr != null)
{
targettype = SpawnerType.GetType(typestr);
}
// go through all of the items in the pack
List<Item> packlist = pack.Items;
for (int i = 0; i < packlist.Count; ++i)
{
Item item = (Item)packlist[i];
if (item != null && !item.Deleted)
{
if (item is Container)
{
Item itemTarget = SearchPackForItem((Container)item, targetName, typestr);
if (itemTarget != null) return itemTarget;
}
// test the item name against the trigger string
if (CheckNameMatch(targetName, item.Name))
{
if (targettype == null || (item.GetType().Equals(targettype) || item.GetType().IsSubclassOf(targettype)))
{
//found it
return item;
}
}
}
}
}
return null;
}
public static List<Item> SearchPackForItems(Container pack, string targetName, string typestr)
{
List<Item> itemlist = new List<Item>();
if (pack != null && !pack.Deleted)
{
Type targettype = null;
if (typestr != null)
{
targettype = SpawnerType.GetType(typestr);
}
// go through all of the items in the pack
List<Item> packlist = pack.Items;
for (int i = 0; i < packlist.Count; ++i)
{
Item item = (Item)packlist[i];
if (item != null && !item.Deleted)
{
if (item is Container)
{
itemlist.AddRange(SearchPackForItems((Container)item, targetName, typestr));
}
// test the item name against the trigger string since it's not a container
else if (CheckNameMatch(targetName, item.Name))
{
if (targettype == null || (item.GetType().Equals(targettype) || item.GetType().IsSubclassOf(targettype)))
{
//found it
itemlist.Add(item);
}
}
}
}
}
return itemlist;
}
public static List<Item> SearchPackListForItemType(Container pack, string targetName, List<Item> itemlist)
{
if (pack != null && !pack.Deleted && targetName != null && targetName.Length > 0)
{
Type targetType = SpawnerType.GetType(targetName);
if (targetType == null) return null;
// go through all of the items in the pack
List<Item> packlist = pack.Items;
for (int i = 0; i < packlist.Count; ++i)
{
Item item = packlist[i];
if (item != null && !item.Deleted && item is Container)
{
itemlist = SearchPackListForItemType((Container)item, targetName, itemlist);
}
// test the item name against the trigger string
if (item != null && !item.Deleted && (item.GetType().IsSubclassOf(targetType) || item.GetType().Equals(targetType)))
{
//found it
itemlist.Add(item);
}
}
}
return itemlist;
}
public static List<Item> FindItemListByType(Mobile m, string targetName, bool searchbank)
{
List<Item> itemlist = new List<Item>();
if (m != null && !m.Deleted && targetName != null && targetName.Length > 0)
{
Type targetType = SpawnerType.GetType(targetName);
// go through all of the items on the mobile
List<Item> packlist = m.Items;
for (int i = 0; i < packlist.Count; ++i)
{
Item item = packlist[i];
// dont search bank boxes
if (item is BankBox && !searchbank) continue;
// recursively search containers
if (item != null && !item.Deleted)
{
if (item is Container)
{
itemlist = SearchPackListForItemType((Container)item, targetName, itemlist);
}
// test the item name against the trigger string
if (item.GetType().IsSubclassOf(targetType) || item.GetType().Equals(targetType))
{
//found it
// add the item to the list
itemlist.Add(item);
}
}
}
// now check any item that might be held
Item held = m.Holding;
if (held != null && !held.Deleted)
{
if (held is Container)
{
itemlist = SearchPackListForItemType((Container)held, targetName, itemlist);
}
// test the item name against the trigger string
if (held.GetType().IsSubclassOf(targetType) || held.GetType().Equals(targetType))
{
//found it
// add the item to the list
itemlist.Add(held);
}
}
}
return itemlist;
}
public static bool CheckForNotCarried(Mobile m, string objectivestr)
{
if (m == null || objectivestr == null) return true;
// parse the objective string that might be of the form 'obj &| obj &| obj ...'
string[] arglist = ParseString(objectivestr, 2, "&|");
if (arglist.Length < 2)
{
// simple test with no and/or operators
return SingleCheckForNotCarried(m, objectivestr);
}
else
{
// test each half independently and combine the results
bool first = SingleCheckForNotCarried(m, arglist[0]);
// this will recursively parse the property test string with implicit nesting for multiple logical tests of the
// form A * B * C * D being grouped as A * (B * (C * D))
bool second = CheckForNotCarried(m, arglist[1]);
int andposition = objectivestr.IndexOf("&");
int orposition = objectivestr.IndexOf("|");
// for the & operator
// notrigger if
// notcarrying A | notcarrying B
// people will actually think of it as not(carrying A | carrying B)
// which is
// notrigger if
// notcarrying A && notcarrying B
// similarly for the & operator
// combine them based upon the operator
if ((andposition > 0 && orposition <= 0) || (andposition > 0 && andposition < orposition))
{
// and operator (see explanation above)
return (first || second);
}
else if ((orposition > 0 && andposition <= 0) || (orposition > 0 && orposition < andposition))
{
// or operator (see explanation above)
return (first && second);
}
else
{
// should never get here
return false;
}
}
}
public static bool SingleCheckForNotCarried(Mobile m, string objectivestr)
{
if (m == null || objectivestr == null) return true;
bool has_no_such_item = true;
// check to see whether there is an objective specification as well. The format is name[,type][,EQUIPPED][,objective,objective,...]
string[] objstr = ParseString(objectivestr, 8, ",");
string itemname = objstr[0];
// check for attachment keyword
if (itemname == "ATTACHMENT")
{
// syntax is ATTACHMENT,name,type
if (objstr.Length > 1)
{
string aname = objstr[1];
Type atype = null;
if (objstr.Length > 2)
{
atype = SpawnerType.GetType(objstr[2]);
}
// try to find the attachment on the mob
if (XmlAttach.FindAttachmentOnMobile(m, atype, aname) != null)
return false;
else
return true;
}
else
return true;
}
bool equippedonly = false;
string typestr = null;
int objoffset = 1;
// is there a type specification?
while (objoffset < objstr.Length)
{
if (objstr[objoffset] != null && objstr[objoffset].Length > 0)
{
char startc = objstr[objoffset][0];
if (startc >= '0' && startc <= '9')
{
// this is the start of the numeric objective specifications
break;
}
else
if (objstr[objoffset] == "EQUIPPED")
{
equippedonly = true;
}
else
{
// treat as a type specification if it does not begin with a numeric char
// and is not the EQUIPPED keyword
typestr = objstr[objoffset];
}
}
objoffset++;
}
// look for the item
Item testitem = SearchMobileForItem(m, itemname, typestr, false, equippedonly);
// found the item
if (testitem != null)
{
// check to see if it is a quest token item. If so, then check validity, otherwise just finding it is enough
if (testitem is IXmlQuest && ((IXmlQuest)testitem).IsValid)
{
IXmlQuest token = (IXmlQuest)testitem;
if (objstr.Length > objoffset)
{
has_no_such_item = true;
// get any objectives and test for them. If any of the required conditions are true, then block trigger
for (int n = objoffset; n < objstr.Length; n++)
{
int x=0;
if(int.TryParse(objstr[n], out x))
{
switch (x - objoffset + 1)
{
case 1:
if (token.Completed1) has_no_such_item = false;
break;
case 2:
if (token.Completed2) has_no_such_item = false;
break;
case 3:
if (token.Completed3) has_no_such_item = false;
break;
case 4:
if (token.Completed4) has_no_such_item = false;
break;
case 5:
if (token.Completed5) has_no_such_item = false;
break;
}
}
}
}
else
has_no_such_item = false;
}
else
{
// is the equippedonly flag set? If so then see if the item is equipped
if ((equippedonly && testitem.Parent == m) || !equippedonly)
has_no_such_item = false;
}
}
return has_no_such_item;
}
public static bool CheckForCarried(Mobile m, string objectivestr)
{
if (m == null || objectivestr == null) return true;
// parse the objective string that might be of the form 'obj &| obj &| obj ...'
string[] arglist = ParseString(objectivestr, 2, "&|");
if (arglist.Length < 2)
{
// simple test with no and/or operators
return SingleCheckForCarried(m, objectivestr);
}
else
{
// test each half independently and combine the results
bool first = SingleCheckForCarried(m, arglist[0]);
// this will recursively parse the property test string with implicit nesting for multiple logical tests of the
// form A * B * C * D being grouped as A * (B * (C * D))
bool second = CheckForCarried(m, arglist[1]);
int andposition = objectivestr.IndexOf("&");
int orposition = objectivestr.IndexOf("|");
// combine them based upon the operator
if ((andposition > 0 && orposition <= 0) || (andposition > 0 && andposition < orposition))
{
// and operator
return (first && second);
}
else if ((orposition > 0 && andposition <= 0) || (orposition > 0 && orposition < andposition))
{
// or operator
return (first || second);
}
else
{
// should never get here
return false;
}
}
}
public static bool SingleCheckForCarried(Mobile m, string objectivestr)
{
if (m == null || objectivestr == null) return false;
bool has_valid_item = false;
// check to see whether there is an objective specification as well. The format is name[,type][,EQUIPPED][,objective,objective,...]
string[] objstr = ParseString(objectivestr, 8, ",");
string itemname = objstr[0];
// check for attachment keyword
if (itemname == "ATTACHMENT")
{
// syntax is ATTACHMENT,name,type
if (objstr.Length > 1)
{
string aname = objstr[1];
Type atype = null;
if (objstr.Length > 2)
{
atype = SpawnerType.GetType(objstr[2]);
}
// try to find the attachment on the mob
if (XmlAttach.FindAttachmentOnMobile(m, atype, aname) != null)
return true;
else
return false;
}
else
return false;
}
bool equippedonly = false;
string typestr = null;
int objoffset = 1;
// is there a type specification?
while (objoffset < objstr.Length)
{
if (objstr[objoffset] != null && objstr[objoffset].Length > 0)
{
char startc = objstr[objoffset][0];
if (startc >= '0' && startc <= '9')
{
// this is the start of the numeric objective specifications
break;
}
else if (objstr[objoffset].ToLowerInvariant() == "equipped")
{
equippedonly = true;
}
else
{
// treat as a type specification if it does not begin with a numeric char
// and is not the EQUIPPED keyword
typestr = objstr[objoffset];
}
}
objoffset++;
}
Item testitem = SearchMobileForItem(m, itemname, typestr, false, equippedonly);
// found the item
if (testitem != null)
{
// check to see if it is a quest token item. If so, then check validity, otherwise just finding it is enough
if (testitem is IXmlQuest)
{
IXmlQuest token = (IXmlQuest)testitem;
if (token.IsValid)
{
if (objstr.Length > objoffset)
{
has_valid_item = true;
// get any objectives and test for them. If any of the required conditions are false, then dont trigger
for (int n = objoffset; n < objstr.Length; n++)
{
int x=0;
if(int.TryParse(objstr[n], out x))
{
switch (x - objoffset + 1)
{
case 1:
if (!token.Completed1) has_valid_item = false;
break;
case 2:
if (!token.Completed2) has_valid_item = false;
break;
case 3:
if (!token.Completed3) has_valid_item = false;
break;
case 4:
if (!token.Completed4) has_valid_item = false;
break;
case 5:
if (!token.Completed5) has_valid_item = false;
break;
}
}
}
}
else
// if an objective list has not been specified then just a valid item is enough
has_valid_item = true;
}
}
else
{
// is the equippedonly flag set? If so then see if the item is equipped
if ((equippedonly && testitem.Parent == m) || !equippedonly)
has_valid_item = true;
}
}
return has_valid_item;
}
public static Item FindItemByName(XmlSpawner fromspawner, string name, string typestr)
{
if (name == null) return null;
int count = 0;
Item founditem = FindInRecentItemSearchList(fromspawner, name, typestr);
if (founditem != null)
{
return founditem;
}
Type targettype = null;
if (typestr != null)
{
targettype = SpawnerType.GetType(typestr);
}
// search through all items in the world and find the first one with a matching name
foreach (Item item in World.Items.Values)
{
Type itemtype = item.GetType();
if (!item.Deleted && (name.Length == 0 || String.Compare(item.Name, name, true) == 0))
{
if (typestr == null ||
(itemtype != null && targettype != null && (itemtype.Equals(targettype) || itemtype.IsSubclassOf(targettype))))
{
founditem = item;
count++;
// added the break in to return the first match instead of forcing uniqueness (overrides the count test)
break;
}
}
//if(count > 1) break;
}
// if a unique item is found then success
if (count == 1)
{
// add this to the recent search list
AddToRecentItemSearchList(fromspawner, founditem);
return (founditem);
}
else
return null;
}
public static Mobile FindMobileByName(XmlSpawner fromspawner, string name, string typestr)
{
if (name == null) return null;
int count = 0;
Mobile foundmobile = FindInRecentMobileSearchList(fromspawner, name, typestr);
if (foundmobile != null) return foundmobile;
Type targettype = null;
if (typestr != null)
{
targettype = SpawnerType.GetType(typestr);
}
// search through all mobiles in the world and find one with a matching name
foreach (Mobile mobile in World.Mobiles.Values)
{
Type mobtype = mobile.GetType();
if (!mobile.Deleted && ((name.Length == 0 || String.Compare(mobile.Name, name, true) == 0)) && (typestr == null ||
(mobtype != null && targettype != null && (mobtype.Equals(targettype) || mobtype.IsSubclassOf(targettype)))))
{
foundmobile = mobile;
count++;
// added the break in to return the first match instead of forcing uniqueness (overrides the count test)
break;
}
//if(count > 1) break;
}
// if a unique item is found then success
if (count == 1)
{
// add this to the recent search list
AddToRecentMobileSearchList(fromspawner, foundmobile);
return (foundmobile);
}
else
return null;
}
public static XmlSpawner FindSpawnerByName(XmlSpawner fromspawner, string name)
{
if (name==null) return null;
if (name.StartsWith("0x"))
{
int serial = -1;
try
{
serial = Convert.ToInt32(name, 16);
}
catch { }
return World.FindEntity(serial) as XmlSpawner;
}
else
{
// do a quick search through the recent search list to see if it is there
XmlSpawner foundspawner = FindInRecentSpawnerSearchList(fromspawner, name);
if (foundspawner != null) return foundspawner;
int count=0;
// search through all xmlspawners in the world and find one with a matching name
foreach (Item item in World.Items.Values)
{
if (item is XmlSpawner)
{
XmlSpawner spawner = (XmlSpawner)item;
if (!spawner.Deleted && (String.Compare(spawner.Name, name, true) == 0))
{
foundspawner = spawner;
count++;
// added the break in to return the first match instead of forcing uniqueness (overrides the count test)
break;
}
//if(count > 1) break;
}
}
// if a unique item is found then success
if (count == 1)
{
// add this to the recent search list
AddToRecentSpawnerSearchList(fromspawner, foundspawner);
return (foundspawner);
}
else
return null;
}
}
public static void AddToRecentSpawnerSearchList(XmlSpawner spawner, XmlSpawner target)
{
if (spawner == null || target == null) return;
if (spawner.RecentSpawnerSearchList == null)
{
spawner.RecentSpawnerSearchList = new List<XmlSpawner>();
}
spawner.RecentSpawnerSearchList.Add(target);
// check the length and truncate if it gets too long
if (spawner.RecentSpawnerSearchList.Count > 100)
{
spawner.RecentSpawnerSearchList.RemoveAt(0);
}
}
public static XmlSpawner FindInRecentSpawnerSearchList(XmlSpawner spawner, string name)
{
if (spawner == null || name == null || spawner.RecentSpawnerSearchList == null) return null;
List<XmlSpawner> deletelist = null;
XmlSpawner foundspawner = null;
foreach (XmlSpawner s in spawner.RecentSpawnerSearchList)
{
if (s.Deleted)
{
// clean it up
if (deletelist == null)
deletelist = new List<XmlSpawner>();
deletelist.Add(s);
}
else
if (String.Compare(s.Name, name, true) == 0)
{
foundspawner = s;
break;
}
}
if (deletelist != null)
{
foreach (XmlSpawner i in deletelist)
spawner.RecentSpawnerSearchList.Remove(i);
}
return (foundspawner);
}
public static void AddToRecentItemSearchList(XmlSpawner spawner, Item target)
{
if (spawner == null || target == null) return;
if (spawner.RecentItemSearchList == null)
{
spawner.RecentItemSearchList = new List<Item>();
}
spawner.RecentItemSearchList.Add(target);
// check the length and truncate if it gets too long
if (spawner.RecentItemSearchList.Count > 100)
{
spawner.RecentItemSearchList.RemoveAt(0);
}
}
public static Item FindInRecentItemSearchList(XmlSpawner spawner, string name, string typestr)
{
if (spawner == null || name == null || spawner.RecentItemSearchList == null) return null;
List<Item> deletelist = null;
Item founditem = null;
Type targettype = null;
if (typestr != null)
{
targettype = SpawnerType.GetType(typestr);
}
foreach (Item item in spawner.RecentItemSearchList)
{
if (item.Deleted)
{
// clean it up
if (deletelist == null)
deletelist = new List<Item>();
deletelist.Add(item);
}
else
if (name.Length == 0 || String.Compare(item.Name, name, true) == 0)
{
if (typestr == null ||
(item.GetType() != null && targettype != null && (item.GetType().Equals(targettype) || item.GetType().IsSubclassOf(targettype))))
{
founditem = item;
break;
}
}
}
if (deletelist != null)
{
foreach (Item i in deletelist)
spawner.RecentItemSearchList.Remove(i);
}
return (founditem);
}
public static void AddToRecentMobileSearchList(XmlSpawner spawner, Mobile target)
{
if (spawner == null || target == null) return;
if (spawner.RecentMobileSearchList == null)
{
spawner.RecentMobileSearchList = new List<Mobile>();
}
spawner.RecentMobileSearchList.Add(target);
// check the length and truncate if it gets too long
if (spawner.RecentMobileSearchList.Count > 100)
{
spawner.RecentMobileSearchList.RemoveAt(0);
}
}
public static Mobile FindInRecentMobileSearchList(XmlSpawner spawner, string name, string typestr)
{
if (spawner == null || name == null || spawner.RecentMobileSearchList == null) return null;
List<Mobile> deletelist = null;
Mobile foundmobile = null;
Type targettype = null;
if (typestr != null)
{
targettype = SpawnerType.GetType(typestr);
}
foreach (Mobile m in spawner.RecentMobileSearchList)
{
if (m.Deleted)
{
// clean it up
if (deletelist == null)
deletelist = new List<Mobile>();
deletelist.Add(m);
}
else
if (name.Length == 0 || String.Compare(m.Name, name, true) == 0)
{
if (typestr == null ||
(m.GetType() != null && targettype != null && (m.GetType().Equals(targettype) || m.GetType().IsSubclassOf(targettype))))
{
foundmobile = m;
break;
}
}
}
if (deletelist != null)
{
foreach (Mobile i in deletelist)
spawner.RecentMobileSearchList.Remove(i);
}
return (foundmobile);
}
#endregion
#region Add object methods
public static bool AddAttachmentToTarget(XmlSpawner spawner, object o, string[] keywordargs, string[] arglist, Mobile trigmob,
object refobject, out string remainder, out string status_str)
{
remainder = "";
status_str = null;
if (o == null || keywordargs == null || arglist == null) return false;
// Use the format /ATTACH,drop_probability/attachmenttype,name[,args]/
// or /ATTACH,drop_probability/<attachmenttype,name[,args]/propname1/value1/propname2/value2/...>/
double drop_probability = 1;
if (keywordargs.Length > 1)
{
bool converterror = false;
try { drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture); }
catch { status_str = "Invalid drop probability : " + arglist[1]; converterror = true; }
if (converterror) return false;
}
// o is the object to which the attachment will be attached
// handle the nested item property specification using <>
string attachargstring = null;
// attachtypestr will be the actual attachment type to be created. In the simple form it will be arglist[1]
// for the string /arg1/ATTACH/arg2/arg3/arg4/arg5 arglist [0] will contain ATTACH , arglist[1] will be arg2,
// and arglist[2] will be arg3/arg4/arg5
// if nested property specs
// arglist[1] will be <arg2 and arglist[2] will be arg3/ar4>/arg5
// the drop probability will be in probargs
string[] probargs = ParseString(arglist[0], 2, ",");
string attachtypestr = arglist[1];
// get the argument list after the < if any , note for the string /arg1/ATTACH/<arg2/arg3/arg4>/arg5 arglist [0] will contain ATTACH
// arglist[1] will be <arg2 and arglist[2] will be arg3/ar4>/arg5
// but note arglist[1] could also be <arg2>
// remainder will have ATTACH/<arg2/arg3/arg4>/arg5
//
// can also deal with nested cases of ATTACH/<args/ADD/<args>> and ATTACH/<args/ADD/<args>/ADD/<args>> although there is no clear
// reason why this syntax should be used at this time
string addattachstr = arglist[1];
if (arglist.Length > 2)
addattachstr = arglist[1] + "/" + arglist[2];
// check to see if the first char is a "<"
if (addattachstr.IndexOf("<") == 0)
{
// attacharglist[1] will contain arg2/arg3/arg4>/arg5
// addattachstr should have the full list of args <arg2/arg3/arg4>/arg5 if they are there. In the case of /arg1/ADD/arg2
// it will just have arg2
string[] attacharglist = ParseString(addattachstr, 2, "<");
// take that argument list that should like like arg2/ag3/arg4>/arg5
// need to find the matching ">"
//string[] attachargs = ParseString(attacharglist[1],2,">");
string[] attachargs = ParseToMatchingParen(attacharglist[1], '<', '>');
// and get the first part of the string without the > so attachargs[0] should be arg2/ag3/arg4
attachargstring = attachargs[0];
// and attachargs[1] should be the remainder
if (attachargs.Length > 1)
{
// but have to get rid of any trailing / that might be after the >
string[] trailstr = ParseSlashArgs(attachargs[1], 2);
if (trailstr.Length > 1)
remainder = trailstr[1];
else
remainder = attachargs[1];
}
else
remainder = "";
// get the type info by pulling out the first arg in attachargstring
string[] tempattacharg = ParseSlashArgs(attachargstring, 2);
// and get the type info from it
attachtypestr = tempattacharg[0];
}
else
{
// otherwise its just a regular case with arglist[2] containing the rest of the arguments
if (arglist.Length > 2)
remainder = arglist[2];
else
remainder = "";
}
// test the drop probability
if (Utility.RandomDouble() >= drop_probability) return true;
Type type = null;
if (attachtypestr != null)
{
type = SpawnerType.GetType(ParseObjectType(attachtypestr));
}
// if so then create it
if (type != null && type.IsSubclassOf(typeof(XmlAttachment)))
{
object newo = XmlSpawner.CreateObject(type, attachtypestr, false, true);
if (newo is XmlAttachment)
{
XmlAttachment attachment = (XmlAttachment)newo;
// could call applyobjectstringproperties on a nested propertylist here to set attachment attributes
if (attachargstring != null)
{
ApplyObjectStringProperties(spawner, attachargstring, attachment, trigmob, refobject, out status_str);
}
// add the attachment to the target
if (!XmlAttach.AttachTo(spawner, o, attachment))
{
status_str = String.Format("Attachment {0} not added", attachtypestr);
return false;
}
}
else
{
status_str = "Invalid ATTACH. No such attachment : " + attachtypestr;
return false;
}
}
else
{
status_str = "Invalid ATTACH. No such attachment : " + attachtypestr;
return false;
}
return true;
}
public static bool AddItemToTarget(XmlSpawner spawner, object o, string[] keywordargs, string[] arglist, Mobile trigmob,
object refobject, bool equip, out string remainder, out string status_str)
{
remainder = "";
status_str = null;
if (o == null || keywordargs == null || arglist == null) return false;
// if the object is a mobile then add the item in the next arg to its pack. Use the format /ADD,drop_probability/itemtype/
// or /ADD,drop_probability/<itemtype/propname1/value1/propname2/value2/...>/
double drop_probability = 1;
if (keywordargs.Length > 1)
{
bool converterror = false;
try { drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture); }
catch { status_str = "Invalid drop probability : " + arglist[1]; converterror = true; }
if (converterror) return false;
}
Mobile m = null;
if (o is Mobile || (o is Container))
{
Container pack = null;
if (o is Mobile)
{
m = (Mobile)o;
if (!m.Deleted)
{
pack = m.Backpack;
// auto add a pack if the mob doesnt have one
if (pack == null)
{
pack = new Backpack();
m.AddItem(pack);
}
}
}
else
{
pack = o as Container;
}
if (pack != null)
{
// handle the nested item property specification using <>
string itemargstring = null;
// itemtypestr will be the actual item type to be created. In the simple form it will be arglist[1]
// for the string /arg1/ADD/arg2/arg3/arg4/arg5 arglist [0] will contain ADD , arglist[1] will be arg2,
// and arglist[2] will be arg3/arg4/arg5
// if nested property specs
// arglist[1] will be <arg2 and arglist[2] will be arg3/ar4>/arg5
// the drop probability will be in probargs
string[] probargs = ParseCommaArgs(arglist[0], 2);
string itemtypestr = arglist[1];
// get the argument list after the < if any , note for the string /arg1/ADD/<arg2/arg3/arg4>/arg5 arglist [0] will contain ADD
// arglist[1] will be <arg2 and arglist[2] will be arg3/ar4>/arg5
// but note arglist[1] could also be <arg2>
// remainder will have ADD/<arg2/arg3/arg4>/arg5
//
// also need to deal with nested cases of ADD/<args/ADD/<args>> and ADD/<args/ADD/<args>/ADD<args>>
string additemstr = arglist[1];
if (arglist.Length > 2)
additemstr = arglist[1] + "/" + arglist[2];
// check to see if the first char is a "<"
if (additemstr.IndexOf("<") == 0)
{
// itemarglist[1] will contain arg2/arg3/arg4>/arg5
// additemstr should have the full list of args <arg2/arg3/arg4>/arg5 if they are there. In the case of /arg1/ADD/arg2
// it will just have arg2
string[] itemarglist = ParseString(additemstr, 2, "<");
// take that argument list that should like like arg2/ag3/arg4>/arg5
// need to find the matching ">"
//string[] itemargs = ParseString(itemarglist[1],2,">");
string[] itemargs = ParseToMatchingParen(itemarglist[1], '<', '>');
// and get the first part of the string without the > so itemargs[0] should be arg2/ag3/arg4
itemargstring = itemargs[0];
// and itemargs[1] should be the remainder
if (itemargs.Length > 1)
{
// but have to get rid of any trailing / that might be after the >
string[] trailstr = ParseSlashArgs(itemargs[1], 2);
if (trailstr.Length > 1)
remainder = trailstr[1];
else
remainder = itemargs[1];
}
else
remainder = "";
// get the type info by pulling out the first arg in itemargstring
string[] tempitemarg = ParseSlashArgs(itemargstring, 2);
// and get the type info from it
itemtypestr = tempitemarg[0];
}
else
{
// otherwise its just a regular case with arglist[2] containing the rest of the arguments
if (arglist.Length > 2)
remainder = arglist[2];
else
remainder = "";
}
// test the drop probability
if (Utility.RandomDouble() >= drop_probability) return true;
// is it a valid item specification?
string baseitemtype = ParseObjectType(itemtypestr);
#region itemKeyword
if (IsSpecialItemKeyword(baseitemtype))
{
// itemtypestr will have the form keyword[,x[,y]]
string[] itemkeywordargs = ParseCommaArgs(itemtypestr, 3);
itemKeyword kw = itemKeywordHash[baseitemtype];
switch (kw)
{
// deal with the special keywords
case itemKeyword.ARMOR:
{
// syntax is ARMOR,min,max
//get the min,max
if (itemkeywordargs.Length == 3)
{
int min = 0;
int max = 0;
bool converterror = false;
try { min = int.Parse(itemkeywordargs[1]); }
catch { status_str = "Invalid ARMOR args : " + itemtypestr; converterror = true; }
try { max = int.Parse(itemkeywordargs[2]); }
catch { status_str = "Invalid ARMOR args : " + itemtypestr; converterror = true; }
if (converterror) return false;
Item item = MagicArmor(min, max, false, false);
if (item != null)
{
if (equip && m != null)
{
if (!m.EquipItem(item)) pack.DropItem(item);
}
else
{
pack.DropItem(item);
}
// could call applyobjectstringproperties on a nested propertylist here to set item attributes
if (itemargstring != null)
{
ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str);
}
}
}
else
{
status_str = "ARMOR takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.WEAPON:
{
// syntax is WEAPON,min,max
//get the min,max
if (itemkeywordargs.Length == 3)
{
int min = 0;
int max = 0;
bool converterror = false;
try { min = int.Parse(itemkeywordargs[1]); }
catch { status_str = "Invalid WEAPON args : " + itemtypestr; converterror = true; }
try { max = int.Parse(itemkeywordargs[2]); }
catch { status_str = "Invalid WEAPON args : " + itemtypestr; converterror = true; }
if (converterror) return false;
Item item = MagicWeapon(min, max, false);
if (item != null)
{
if (equip && m != null)
{
if (!m.EquipItem(item)) pack.DropItem(item);
}
else
pack.DropItem(item);
// could call applyobjectstringproperties on a nested propertylist here to set item attributes
if (itemargstring != null)
{
ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str);
}
}
}
else
{
status_str = "WEAPON takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.JEWELRY:
{
// syntax is JEWELRY,min,max
//get the min,max
if (itemkeywordargs.Length == 3)
{
int min = 0;
int max = 0;
bool converterror = false;
try { min = int.Parse(itemkeywordargs[1]); }
catch { status_str = "Invalid JEWELRY args : " + itemtypestr; converterror = true; }
try { max = int.Parse(itemkeywordargs[2]); }
catch { status_str = "Invalid JEWELRY args : " + itemtypestr; converterror = true; }
if (converterror) return false;
Item item = MagicJewelry(min, max);
if (item != null)
{
if (equip && m != null)
{
if (!m.EquipItem(item)) pack.DropItem(item);
}
else
pack.DropItem(item);
// could call applyobjectstringproperties on a nested propertylist here to set item attributes
if (itemargstring != null)
{
ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str);
}
}
}
else
{
status_str = "JEWELRY takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.SHIELD:
{
// syntax is SHIELD,min,max
//get the min,max
if (itemkeywordargs.Length == 3)
{
int min = 0;
int max = 0;
bool converterror = false;
try { min = int.Parse(itemkeywordargs[1]); }
catch { status_str = "Invalid SHIELD args : " + itemtypestr; converterror = true; }
try { max = int.Parse(itemkeywordargs[2]); }
catch { status_str = "Invalid SHIELD args : " + itemtypestr; converterror = true; }
if (converterror) return false;
Item item = MagicShield(min, max);
if (item != null)
{
if (equip && m != null)
{
if (!m.EquipItem(item)) pack.DropItem(item);
}
else
pack.DropItem(item);
// could call applyobjectstringproperties on a nested propertylist here to set item attributes
if (itemargstring != null)
{
ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str);
}
}
}
else
{
status_str = "SHIELD takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.JARMOR:
{
// syntax is JARMOR,min,max
//get the min,max
if (itemkeywordargs.Length == 3)
{
int min = 0;
int max = 0;
bool converterror = false;
try { min = int.Parse(itemkeywordargs[1]); }
catch { status_str = "Invalid JARMOR args : " + itemtypestr; converterror = true; }
try { max = int.Parse(itemkeywordargs[2]); }
catch { status_str = "Invalid JARMOR args : " + itemtypestr; converterror = true; }
if (converterror) return false;
Item item = MagicArmor(min, max, true, true);
if (item != null)
{
if (equip && m != null)
{
if (!m.EquipItem(item)) pack.DropItem(item);
}
else
pack.DropItem(item);
// could call applyobjectstringproperties on a nested propertylist here to set item attributes
if (itemargstring != null)
{
ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str);
}
}
}
else
{
status_str = "JARMOR takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.SARMOR:
{
// syntax is SARMOR,min,max
//get the min,max
if (itemkeywordargs.Length == 3)
{
int min = 0;
int max = 0;
bool converterror = false;
try { min = int.Parse(itemkeywordargs[1]); }
catch { status_str = "Invalid SARMOR args : " + itemtypestr; converterror = true; }
try { max = int.Parse(itemkeywordargs[2]); }
catch { status_str = "Invalid SARMOR args : " + itemtypestr; converterror = true; }
if (converterror) return false;
Item item = MagicArmor(min, max, false, true);
if (item != null)
{
if (equip && m != null)
{
if (!m.EquipItem(item)) pack.DropItem(item);
}
else
pack.DropItem(item);
// could call applyobjectstringproperties on a nested propertylist here to set item attributes
if (itemargstring != null)
{
ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str);
}
}
}
else
{
status_str = "SARMOR takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.JWEAPON:
{
// syntax is JWEAPON,min,max
//get the min,max
if (itemkeywordargs.Length == 3)
{
int min = 0;
int max = 0;
bool converterror = false;
try { min = int.Parse(itemkeywordargs[1]); }
catch { status_str = "Invalid JWEAPON args : " + itemtypestr; converterror = true; }
try { max = int.Parse(itemkeywordargs[2]); }
catch { status_str = "Invalid JWEAPON args : " + itemtypestr; converterror = true; }
if (converterror) return false;
Item item = MagicWeapon(min, max, true);
if (item != null)
{
if (equip && m != null)
{
if (!m.EquipItem(item)) pack.DropItem(item);
}
else
pack.DropItem(item);
// could call applyobjectstringproperties on a nested propertylist here to set item attributes
if (itemargstring != null)
{
ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str);
}
}
}
else
{
status_str = "JWEAPON takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.SCROLL:
{
// syntax is SCROLL,mincircle,maxcircle
//get the min,max
if (itemkeywordargs.Length == 3)
{
int minCircle = 0;
int maxCircle = 0;
if(!int.TryParse(itemkeywordargs[1], out minCircle))
{
status_str = "Invalid SCROLL args : " + itemtypestr;
return false;
}
if(!int.TryParse(itemkeywordargs[2], out maxCircle))
{
status_str = "Invalid SCROLL args : " + itemtypestr;
return false;
}
int circle = Utility.RandomMinMax(minCircle, maxCircle);
int min = (circle - 1) * 8;
Item item = Loot.RandomScroll(min, min + 7, SpellbookType.Regular);
if (item != null)
{
pack.DropItem(item);
// could call applyobjectstringproperties on a nested propertylist here to set item attributes
if (itemargstring != null)
{
ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str);
}
}
}
else
{
status_str = "SCROLL takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.POTION:
{
// syntax is POTION
Item item = Loot.RandomPotion();
if (item != null)
{
pack.DropItem(item);
// could call applyobjectstringproperties on a nested propertylist here to set item attributes
if (itemargstring != null)
{
ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str);
}
}
break;
}
case itemKeyword.TAKEN:
{
// syntax is TAKEN
Item item = GetTaken(refobject);
if (item != null)
{
pack.DropItem(item);
// could call applyobjectstringproperties on a nested propertylist here to set item attributes
if (itemargstring != null)
{
ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str);
}
}
break;
}
case itemKeyword.GIVEN:
{
// syntax is GIVEN
Item item = GetGiven(refobject);
if (item != null)
{
pack.DropItem(item);
// could call applyobjectstringproperties on a nested propertylist here to set item attributes
if (itemargstring != null)
{
ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str);
}
}
break;
}
case itemKeyword.ITEM:
{
// syntax is ITEM,serial
if (itemkeywordargs.Length == 2)
{
int serial = -1;
bool converterror = false;
try { serial = Convert.ToInt32(itemkeywordargs[1], 16); }
catch { status_str = "Invalid ITEM args : " + itemtypestr; converterror = true; }
if (converterror) return false;
Item item = World.FindItem(serial);
if (item != null)
{
pack.DropItem(item);
// could call applyobjectstringproperties on a nested propertylist here to set item attributes
if (itemargstring != null)
{
ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str);
}
}
}
else
{
status_str = "ITEM takes 1 arg : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.LOOT:
{
// syntax is LOOT,methodname
if (itemkeywordargs.Length == 2)
{
Item item = null;
// look up the method
Type ltype = typeof(Loot);
if (ltype != null)
{
MethodInfo method = null;
try
{
// get the zero-arg method with the specified name
method = ltype.GetMethod(itemkeywordargs[1], new Type[0]);
}
catch { }
if (method != null && method.IsStatic)
{
ParameterInfo[] pinfo = method.GetParameters();
// check to make sure the method for this object has the right args
if (pinfo.Length == 0)
{
// method must be public static with no arguments returning an Item class object
try
{
item = method.Invoke(null, null) as Item;
}
catch { }
}
else
{
status_str = "LOOT method must be zero arg : " + itemtypestr;
return false;
}
}
else
{
status_str = "LOOT no valid method found : " + itemtypestr;
return false;
}
}
if (item != null)
{
pack.DropItem(item);
// could call applyobjectstringproperties on a nested propertylist here to set item attributes
if (itemargstring != null)
{
ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str);
}
}
}
else
{
status_str = "LOOT takes 1 arg : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.NECROSCROLL:
{
// syntax is NECROSCROLL,index
if (itemkeywordargs.Length == 2)
{
int index = 0;
if(!int.TryParse(itemkeywordargs[1], out index))
{
status_str = "Invalid NECROSCROLL args : " + itemtypestr;
return false;
}
if (Core.AOS)
{
Item item = Loot.Construct(Loot.NecromancyScrollTypes, index);
if (item != null)
{
pack.DropItem(item);
// could call applyobjectstringproperties on a nested propertylist here to set item attributes
if (itemargstring != null)
{
ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str);
}
}
}
}
else
{
status_str = "NECROSCROLL takes 1 arg : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.LOOTPACK:
{
// syntax is LOOTPACK,type
if (itemkeywordargs.Length == 2)
{
LootPack lootpack = null;
string loottype = itemkeywordargs[1];
if (loottype.ToLower() == "poor")
{
lootpack = LootPack.Poor;
}
else if (loottype.ToLower() == "meager")
{
lootpack = LootPack.Meager;
}
else if (loottype.ToLower() == "average")
{
lootpack = LootPack.Average;
}
else if (loottype.ToLower() == "rich")
{
lootpack = LootPack.Rich;
}
else if (loottype.ToLower() == "filthyrich")
{
lootpack = LootPack.FilthyRich;
}
else if (loottype.ToLower() == "ultrarich")
{
lootpack = LootPack.UltraRich;
}
else if (loottype.ToLower() == "superboss")
{
lootpack = LootPack.SuperBoss;
}
else
{
status_str = "Invalid LOOTPACK type: " + loottype;
return false;
}
int m_KillersLuck = 0;
if (trigmob != null)
{
m_KillersLuck = LootPack.GetLuckChanceForKiller(trigmob);
}
bool converterror = false;
try
{
// generate the nospawn component of the lootpack
lootpack.Generate(m, pack, false, m_KillersLuck);
// generate the spawn component (basically gold) requires a mobile and wont work in containers
// because Generate does a test for TryDropItem for stackables which requires a valid mob argument,
// any stackable generated in a container will fail
// so just test for a valid mobile and only do the atspawn generate for them.
if (m != null)
lootpack.Generate(m, pack, true, m_KillersLuck);
}
catch
{
status_str = "Unable to add LOOTPACK";
converterror = true;
}
if (converterror) return false;
}
else
{
status_str = "LOOTPACK takes 1 arg : " + itemtypestr;
return false;
}
break;
}
}
}
#endregion
else
{
Type type = SpawnerType.GetType(ParseObjectType(itemtypestr));
// if so then create it
if (type != null)
{
object newo = XmlSpawner.CreateObject(type, itemtypestr);
if (newo is Item)
{
Item item = newo as Item;
if (equip && m != null)
{
if (!m.EquipItem(item)) pack.DropItem(item);
}
else
pack.DropItem(item);
// could call applyobjectstringproperties on a nested propertylist here to set item attributes
if (itemargstring != null)
{
ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str);
}
}
else
{
status_str = "Invalid ADD. No such item : " + itemtypestr;
if (newo is BaseCreature)
((BaseCreature)newo).Delete();
return false;
}
}
else
{
status_str = "Invalid ADD. No such item : " + itemtypestr;
return false;
}
}
}
else
{
status_str = "Invalid ADD. mobile has no pack.";
if (arglist.Length < 3) return false;
remainder = arglist[2];
return false;
}
}
else
{
status_str = "Invalid ADD. must be mobile or container.";
if (arglist.Length < 3) return false;
remainder = arglist[2];
return false;
}
return true;
}
#endregion
#region String parsing methods
public static string ApplySubstitution(XmlSpawner spawner, object o, Mobile trigmob, string typeName)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
// go through the string looking for instances of {keyword}
string remaining = typeName;
while (remaining != null && remaining.Length > 0)
{
int startindex = remaining.IndexOf('{');
if (startindex == -1 || startindex + 1 >= remaining.Length)
{
// if there are no more delimiters then append the remainder and finish
sb.Append(remaining);
break;
}
// might be a substitution, check for keywords
int endindex = remaining.Substring(startindex + 1).IndexOf("}");
// if the ending delimiter cannot be found then just append and finish
if (endindex == -1)
{
sb.Append(remaining);
break;
}
// get the string up to the delimiter
string firstpart = remaining.Substring(0, startindex);
sb.Append(firstpart);
string keypart = remaining.Substring(startindex + 1, endindex);
// try to evaluate and then substitute the arg
Type ptype;
string value = ParseForKeywords(spawner, o, keypart.Trim(), trigmob, true, out ptype);
// trim off the " from strings
if (value != null)
{
value = value.Trim('"');
}
// replace the parsed value for the keyword
sb.Append(value);
// continue processing the rest of the string
if (endindex + startindex + 2 >= remaining.Length) break;
remaining = remaining.Substring(endindex + startindex + 2, remaining.Length - endindex - startindex - 2);
}
return sb.ToString();
}
public static string ParseObjectType(string str)
{
string[] arglist = ParseSlashArgs(str, 2);
if (arglist != null && arglist.Length > 0)
{
// parse out any arguments of the form typename,arg,arg,..
string[] typeargs = ParseCommaArgs(arglist[0], 2);
if (typeargs.Length > 1)
{
return (typeargs[0]);
}
return arglist[0];
}
else
return null;
}
public static string[] ParseObjectArgs(string str)
{
string[] arglist = ParseSlashArgs(str, 2);
if (arglist.Length > 0)
{
string itemtypestring = arglist[0];
// parse out any arguments of the form typename,arg,arg,..
// find the first arg if it is there
string[] typeargs = null;
int argstart = 0;
if (itemtypestring != null && itemtypestring.Length > 0)
argstart = itemtypestring.IndexOf(",") + 1;
if (argstart > 1 && argstart < itemtypestring.Length)
{
typeargs = ParseCommaArgs(itemtypestring.Substring(argstart), 15);
}
return (typeargs);
}
else
return null;
}
// take a string of the form str-opendelim-str-closedelim-str-closedelimstr
public static string[] ParseToMatchingParen(string str, char opendelim, char closedelim)
{
int nopen = 1;
int nclose = 0;
int splitpoint = str.Length;
for (int i = 0; i < str.Length; i++)
{
// walk through the string until a matching close delimstr is found
if (str[i] == opendelim) nopen++;
if (str[i] == closedelim) nclose++;
if (nopen == nclose)
{
splitpoint = i;
break;
}
}
string[] args = new string[2];
// allow missing closing delimiters at the end of the line, basically just treat eol as a closing delim
args[0] = str.Substring(0, splitpoint);
args[1] = "";
if (splitpoint + 1 < str.Length)
{
args[1] = str.Substring(splitpoint + 1, str.Length - splitpoint - 1);
}
return args;
}
public static string[] ParseString(string str, int nitems, string delimstr)
{
if (str == null || delimstr == null) return null;
char[] delims = delimstr.ToCharArray();
string[] args = null;
str = str.Trim();
args = str.Split(delims, nitems);
return args;
}
public static string[] ParseSlashArgs(string str, int nitems)
{
if (str == null) return null;
string[] args = null;
str = str.Trim();
// this supports strings that may have special html formatting in them that use the /
if (str.IndexOf("</") >= 0 || str.IndexOf("/>") >= 0)
{
// or use indexof to do it with more context control
List<string> tmparray = new List<string>();
// find the next slash char
int index = 0;
int preindex = 0;
int searchindex = 0;
int length = str.Length;
while (index >= 0 && searchindex < length && tmparray.Count < nitems - 1)
{
index = str.IndexOf('/', searchindex);
if (index >= 0)
{
// check the char before it and after it to ignore </ and />
if ((index > 0 && str[index - 1] == '<') || (index < length - 1 && str[index + 1] == '>'))
{
// skip it
searchindex = index + 1;
}
else
{
// split it
tmparray.Add(str.Substring(preindex, index - preindex));
preindex = index + 1;
searchindex = preindex;
}
}
}
// is there still room for more args?
if (tmparray.Count <= nitems - 1 && preindex < length)
{
// searched past the end and didnt find anything
tmparray.Add(str.Substring(preindex, length - preindex));
}
// turn tmparray into a string[]
args = new string[tmparray.Count];
tmparray.CopyTo(args);
}
else
{
// just use split to do it with no context control
args = str.Split(slashdelim, nitems);
}
return args;
}
public static string[] ParseSpaceArgs(string str, int nitems)
{
if (str == null) return null;
string[] args = null;
str = str.Trim();
args = str.Split(spacedelim, nitems);
return args;
}
public static string[] ParseCommaArgs(string str, int nitems)
{
if (str == null) return null;
string[] args = null;
str = str.Trim();
args = str.Split(commadelim, nitems);
return args;
}
public static string[] ParseLiteralTerminator(string str)
{
if (str == null) return null;
string[] args = null;
str = str.Trim();
args = str.Split(literalend, 2);
return args;
}
public static string[] ParseSemicolonArgs(string str, int nitems)
{
if (str == null) return null;
string[] args = null;
str = str.Trim();
args = str.Split(semicolondelim, nitems);
return args;
}
public static string[] SplitString(string str, string separator)
{
if (str == null || separator == null) return null;
int lastindex = 0;
int index = 0;
List<string> strargs = new List<string>();
while (index >= 0)
{
// go through the string and find the first instance of the separator
index = str.IndexOf(separator);
if (index < 0)
{
// no separator so its the end of the string
strargs.Add(str);
break;
}
string arg = str.Substring(lastindex, index);
strargs.Add(arg);
str = str.Substring(index + separator.Length, str.Length - (index + separator.Length));
}
// now make the string args
string[] args = new string[strargs.Count];
for (int i = 0; i < strargs.Count; i++)
{
args[i] = strargs[i];
}
return args;
}
#endregion
#region Keyword support methods
public static void BroadcastAsciiMessage(AccessLevel ac, int hue, int font, string message)
{
foreach (NetState state in NetState.Instances)
{
Mobile m = state.Mobile;
if (m != null && m.AccessLevel >= ac)
//m.SendMessage(hue, message);
m.Send(new AsciiMessage(Serial.MinusOne, -1, MessageType.Regular, hue, font, "System", message));
}
}
public static void BroadcastSound(AccessLevel ac, int soundid)
{
foreach (NetState state in NetState.Instances)
{
Mobile m = state.Mobile;
if (m != null && m.AccessLevel >= ac)
{
m.ProcessDelta();
state.Send(new PlaySound(soundid, m.Location));
}
}
}
public static void PublicOverheadMobileMessage(Mobile mob, MessageType type, int hue, int font, string text, bool noLineOfSight)
{
if (mob != null && mob.Map != null)
{
Packet p = null;
IPooledEnumerable eable = mob.Map.GetClientsInRange(mob.Location);
foreach (NetState state in eable)
{
if (state.Mobile.CanSee(mob) && (noLineOfSight || state.Mobile.InLOS(mob)))
{
if (p == null)
{
p = new AsciiMessage(mob.Serial, mob.Body, type, hue, font, mob.Name, text);
p.Acquire();
}
state.Send(p);
}
}
Packet.Release(p);
eable.Free();
}
}
public static void PublicOverheadItemMessage(Item item, MessageType type, int hue, int font, string text)
{
if (item != null && item.Map != null)
{
Packet p = null;
Point3D worldLoc = item.GetWorldLocation();
IPooledEnumerable eable = item.Map.GetClientsInRange(worldLoc, item.GetMaxUpdateRange());
foreach (NetState state in eable)
{
Mobile m = state.Mobile;
if (m.CanSee(item) && m.InRange(worldLoc, item.GetUpdateRange(m)))
{
if (p == null)
{
p = new AsciiMessage(item.Serial, item.ItemID, type, hue, font, item.Name, text);
p.Acquire();
}
state.Send(p);
}
}
Packet.Release(p);
eable.Free();
}
}
public static Item GetTaken(object o)
{
// find the XmlSaveItem attachment
XmlSaveItem si = (XmlSaveItem)XmlAttach.FindAttachment(o, typeof(XmlSaveItem), "Taken");
if (si != null)
{
return si.SavedItem;
}
return null;
}
public static Item GetGiven(object o)
{
// find the XmlSaveItem attachment
XmlSaveItem si = (XmlSaveItem)XmlAttach.FindAttachment(o, typeof(XmlSaveItem), "Given");
if (si != null)
{
return si.SavedItem;
}
return null;
}
// modified from 1.0.0 core packet.cs
public sealed class XmlPlayMusic : Packet
{
public XmlPlayMusic(short number)
: base(0x6D, 3)
{
UnderlyingStream.Write(number);
}
}
// -------------------------------------------------------------
// Begin modified code from Beta-36 Basecreature.cs
// -------------------------------------------------------------
public static Item MagicJewelry(int minLevel, int maxLevel)
{
BaseCreature.Cap(ref minLevel, 0, 5);
BaseCreature.Cap(ref maxLevel, 0, 5);
if (Core.AOS)
{
Item item = Loot.RandomJewelry();
if (item == null)
return null;
int attributeCount, min, max;
BaseCreature.GetRandomAOSStats(minLevel, maxLevel, out attributeCount, out min, out max);
if (item is BaseJewel)
BaseRunicTool.ApplyAttributesTo((BaseJewel)item, attributeCount, min, max);
return item;
}
else
{
Item jewel = Loot.RandomJewelry();
return jewel;
}
}
public static Item MagicArmor(int minLevel, int maxLevel, bool jewel, bool shield)
{
BaseCreature.Cap(ref minLevel, 0, 5);
BaseCreature.Cap(ref maxLevel, 0, 5);
if (Core.AOS)
{
Item item = null;
if (jewel)
item = Loot.RandomArmorOrShieldOrJewelry();
else
if (shield)
item = Loot.RandomArmorOrShield();
else
item = Loot.RandomArmor();
if (item == null)
return null;
int attributeCount, min, max;
BaseCreature.GetRandomAOSStats(minLevel, maxLevel, out attributeCount, out min, out max);
if (item is BaseArmor)
BaseRunicTool.ApplyAttributesTo((BaseArmor)item, attributeCount, min, max);
else if (item is BaseJewel)
BaseRunicTool.ApplyAttributesTo((BaseJewel)item, attributeCount, min, max);
return item;
}
else
{
BaseArmor armor = Loot.RandomArmorOrShield();
if (armor == null)
return null;
armor.ProtectionLevel = (ArmorProtectionLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel);
armor.Durability = (ArmorDurabilityLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel);
return armor;
}
}
public static Item MagicShield(int minLevel, int maxLevel)
{
BaseCreature.Cap(ref minLevel, 0, 5);
BaseCreature.Cap(ref maxLevel, 0, 5);
if (Core.AOS)
{
Item item = Loot.RandomShield();
if (item == null)
return null;
int attributeCount, min, max;
BaseCreature.GetRandomAOSStats(minLevel, maxLevel, out attributeCount, out min, out max);
if (item is BaseArmor)
BaseRunicTool.ApplyAttributesTo((BaseArmor)item, attributeCount, min, max);
return item;
}
else
{
BaseArmor armor = Loot.RandomShield();
if (armor == null)
return null;
armor.ProtectionLevel = (ArmorProtectionLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel);
armor.Durability = (ArmorDurabilityLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel);
return armor;
}
}
public static Item MagicWeapon(int minLevel, int maxLevel, bool jewel)
{
BaseCreature.Cap(ref minLevel, 0, 5);
BaseCreature.Cap(ref maxLevel, 0, 5);
if (Core.AOS)
{
Item item = null;
if (jewel)
item = Loot.RandomWeaponOrJewelry();
else
item = Loot.RandomWeapon();
if (item == null)
return null;
int attributeCount, min, max;
BaseCreature.GetRandomAOSStats(minLevel, maxLevel, out attributeCount, out min, out max);
if (item is BaseWeapon)
BaseRunicTool.ApplyAttributesTo((BaseWeapon)item, attributeCount, min, max);
else if (item is BaseJewel)
BaseRunicTool.ApplyAttributesTo((BaseJewel)item, attributeCount, min, max);
return item;
}
else
{
BaseWeapon weapon = Loot.RandomWeapon();
if (weapon == null)
return null;
if (0.05 > Utility.RandomDouble())
weapon.Slayer = SlayerName.Silver;
weapon.DamageLevel = (WeaponDamageLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel);
weapon.AccuracyLevel = (WeaponAccuracyLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel);
weapon.DurabilityLevel = (WeaponDurabilityLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel);
return weapon;
}
}
// -------------------------------------------------------------
// End modified code from Beta-36 Basecreature.cs
// -------------------------------------------------------------
public static void SendMusicToPlayers(string arglist, Mobile triggermob, object refobject, out string status_str)
{
status_str = null;
Item refitem = null;
Mobile refmob = null;
if (refobject is Item)
{
refitem = (Item)refobject;
}
else
if (refobject is Mobile)
{
refmob = (Mobile)refobject;
}
// look for the other args
string[] musicstr = ParseString(arglist, 3, ",");
int range = 0;
if (musicstr.Length < 2)
{
status_str = "missing musicname in MUSIC";
}
if (musicstr.Length > 2)
{
// get the range arg
if(!int.TryParse(musicstr[2], out range))
status_str = "bad range arg in MUSIC";
}
if ((range > 0) || (triggermob != null && !triggermob.Deleted))
{
// send the music to all players within range if range is > 0
if (range > 0)
{
IPooledEnumerable rangelist = null;
if (refitem != null && !refitem.Deleted)
{
rangelist = refitem.GetClientsInRange(range);
}
else if (refmob != null && !refmob.Deleted)
{
rangelist = refmob.GetClientsInRange(range);
}
if (rangelist != null)
{
foreach (NetState p in rangelist)
{
if (p != null)
{
// stop any ongoing music
p.Send(PlayMusic.InvalidInstance);
// and play the new music
short musicnumber = -1;
if(!short.TryParse(musicstr[1], out musicnumber))
musicnumber = -1;
if (musicnumber == -1)
{
MusicName music;
#if Framework_4_0
if(Enum.TryParse(musicstr[1], true, out music))
#else
if(TryParse(musicstr[1], true, out music))
#endif
p.Send(PlayMusic.GetInstance(music));
}
else
{
p.Send(new XmlPlayMusic(musicnumber));
}
}
}
rangelist.Free();
}
}
else
{
// just send it to the mob who triggered
// stop any ongoing music
triggermob.Send(PlayMusic.InvalidInstance);
// and play the new music
//triggermob.Send(PlayMusic.GetInstance((MusicName)Enum.Parse(typeof(MusicName), musicstr[1], true)));
//m_mob_who_triggered.Region.Music = (MusicName)Enum.Parse(typeof(MusicName), musicstr[1]);
// and play the new music
short musicnumber = -1;
if(!short.TryParse(musicstr[1], out musicnumber))
musicnumber = -1;
if (musicnumber == -1)
{
MusicName music;
#if Framework_4_0
if(Enum.TryParse(musicstr[1], true, out music))
#else
if(TryParse(musicstr[1], true, out music))
#endif
triggermob.Send(PlayMusic.GetInstance(music));
}
else
{
triggermob.Send(new XmlPlayMusic(musicnumber));
}
}
}
}
public static void ResurrectPlayers(string arglist, Mobile triggermob, object refobject, out string status_str)
{
status_str = null;
Item refitem = null;
Mobile refmob = null;
if (refobject is Item)
{
refitem = (Item)refobject;
}
else
if (refobject is Mobile)
{
refmob = (Mobile)refobject;
}
// syntax is RESURRECT[,range][,PETS]
// look for the range arg
string[] str = ParseString(arglist, 3, ",");
int range = 0;
bool petres = false;
if (str.Length > 1)
{
if(!int.TryParse(str[1], out range))
status_str = "bad range arg in RESURRECT";
}
if (str.Length > 2)
{
// get the range arg
if (str[2].ToLower() == "pets")
petres = true;
else bool.TryParse(str[2], out petres);
}
try
{
if ((range > 0) || (triggermob != null && !triggermob.Deleted))
{
// resurrect all players within range if range is > 0
if (range > 0)
{
IPooledEnumerable rangelist = null;
if (refitem != null && !refitem.Deleted)
{
rangelist = refitem.GetMobilesInRange(range);
}
else if (refmob != null && !refmob.Deleted)
{
rangelist = refmob.GetMobilesInRange(range);
}
if (rangelist != null)
{
foreach (Mobile p in rangelist)
{
if (!petres && p is PlayerMobile && p.Body.IsGhost)
{
p.Resurrect();
}
else if (petres && p is BaseCreature && ((BaseCreature)p).ControlMaster == triggermob && ((BaseCreature)p).Controlled && ((BaseCreature)p).IsDeadPet)
{
((BaseCreature)p).ResurrectPet();
}
}
rangelist.Free();
}
}
else
{
// just send it to the mob who triggered
if (triggermob.Body.IsGhost)
triggermob.Resurrect();
}
}
}
catch { }
}
public static void ApplyPoisonToPlayers(string arglist, Mobile triggermob, object refobject, out string status_str)
{
status_str = null;
Item refitem = null;
Mobile refmob = null;
if (refobject is Item)
{
refitem = (Item)refobject;
}
else if (refobject is Mobile)
{
refmob = (Mobile)refobject;
}
// look for the other args
string[] str = ParseString(arglist, 4, ",");
bool playeronly = false;
int range = 0;
if (str.Length < 2)
{
status_str = "missing poisontype in POISON";
}
if (str.Length > 2)
{
// get the range arg
if(!int.TryParse(str[2], out range))
status_str = "bad range arg in POISON";
}
if (str.Length > 3)
{
if(str[3].ToLower() == "playeronly")
playeronly = true;
else bool.TryParse(str[3], out playeronly);
}
try
{
if ((range > 0) || (triggermob != null && !triggermob.Deleted))
{
// apply the poison to all players within range if range is > 0
if (range > 0)
{
IPooledEnumerable rangelist = null;
if (refitem != null && !refitem.Deleted)
{
rangelist = refitem.GetMobilesInRange(range);
}
else if (refmob != null && !refmob.Deleted)
{
rangelist = refmob.GetMobilesInRange(range);
}
if (rangelist != null)
{
foreach (Mobile p in rangelist)
{
if (p is PlayerMobile || !playeronly)
p.ApplyPoison(p, Poison.Parse(str[1]));
}
rangelist.Free();
}
}
else
{
// just apply it to the mob who triggered
triggermob.ApplyPoison(triggermob, Poison.Parse(str[1]));
}
}
}
catch { }
}
public static void ApplyDamageToPlayers(string arglist, Mobile triggermob, object refobject, out string status_str)
{
status_str = null;
Item refitem = null;
Mobile refmob = null;
if (refobject is Item)
{
refitem = (Item)refobject;
}
else if (refobject is Mobile)
{
refmob = (Mobile)refobject;
}
// look for the other args. Syntax is DAMAGE,damage,phys,fire,cold,pois,energy[,range][,playeronly]
string[] str = ParseString(arglist, 9, ",");
bool playeronly = false;
int range = -1;
int damage=0, phys=0, fire=0, cold=0, pois=0, ener=0;
if(str.Length < 3)
{
// we consider all the damage as physical
if(str.Length > 1 && int.TryParse(str[1], out damage))
phys = 100;
else
status_str = "bad damage arg in DAMAGE";
}
else if(str.Length < 7)
{
status_str = "missing damage args in DAMAGE";
}
else if(!int.TryParse(str[1], out damage) |
!int.TryParse(str[2], out phys) |
!int.TryParse(str[3], out fire) |
!int.TryParse(str[4], out cold) |
!int.TryParse(str[5], out pois) |
!int.TryParse(str[6], out ener))
{
status_str = "bad damage args in DAMAGE";
}
if (str.Length > 7)
{
// get the range arg
if(!int.TryParse(str[7], out range))
{
range = -1;
status_str = "bad range arg in DAMAGE";
}
}
if (str.Length > 8)
{
if(str[8].ToLower() == "playeronly")
playeronly = true;
else
bool.TryParse(str[8], out playeronly);
}
try
{
if (range >= 0 || (triggermob != null && !triggermob.Deleted))
{
// apply the poison to all players within range if range is > 0
if (range >= 0)
{
IPooledEnumerable rangelist = null;
if (refitem != null && !refitem.Deleted)
{
rangelist = refitem.GetMobilesInRange(range);
}
else if (refmob != null && !refmob.Deleted)
{
rangelist = refmob.GetMobilesInRange(range);
}
if (rangelist != null)
{
foreach (Mobile p in rangelist)
{
if (p is PlayerMobile || !playeronly)
AOS.Damage(p, damage, phys, fire, cold, pois, ener);
}
rangelist.Free();
}
}
else
{
// just apply it to the mob who triggered
AOS.Damage(triggermob, damage, phys, fire, cold, pois, ener);
}
}
}
catch { }
}
public static void SendBoltEffect(IEntity e, int sound, int hue)
{
Map map = e.Map;
if (map == null)
return;
if (e is Item)
((Item)e).ProcessDelta();
else if (e is Mobile)
((Mobile)e).ProcessDelta();
Packet preEffect = null, boltEffect = null, playSound = null;
IPooledEnumerable eable = map.GetClientsInRange(e.Location);
foreach (NetState state in eable)
{
if (Effects.SendParticlesTo(state))
{
if (preEffect == null)
preEffect = Packet.Acquire(new TargetParticleEffect(e, 0, 10, 5, 0, 0, 5031, 3, 0));
state.Send(preEffect);
}
if (boltEffect == null)
boltEffect = Packet.Acquire(new BoltEffect(e, hue));
state.Send(boltEffect);
if (sound > 0)
{
if (playSound == null)
playSound = Packet.Acquire(new PlaySound(sound, e));
state.Send(playSound);
}
}
Packet.Release(preEffect);
Packet.Release(boltEffect);
Packet.Release(playSound);
eable.Free();
}
public static void ExecuteActions(Mobile mob, object attachedto, string actions)
{
if (actions == null || actions.Length <= 0) return;
// execute any action associated with it
// allow for multiple action strings on a single line separated by a semicolon
string[] args = actions.Split(';');
for (int j = 0; j < args.Length; j++)
{
ExecuteAction(mob, attachedto, args[j]);
}
}
public static void ExecuteAction(Mobile trigmob, object attachedto, 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 { }
}
}
#endregion
#region Spawn methods
public static void AddSpawnItem(XmlSpawner spawner, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface,
string propertyString, out string status_str)
{
AddSpawnItem(spawner, spawner, theSpawn, item, location, map, trigmob, requiresurface, null, propertyString, false, out status_str);
}
public static void AddSpawnItem(XmlSpawner spawner, object invoker, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface,
string propertyString, out string status_str)
{
AddSpawnItem(spawner, invoker, theSpawn, item, location, map, trigmob, requiresurface, null, propertyString, false, out status_str);
}
public static void AddSpawnItem(XmlSpawner spawner, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface,
string propertyString, bool smartspawn, out string status_str)
{
AddSpawnItem(spawner, spawner, theSpawn, item, location, map, trigmob, requiresurface, null, propertyString, smartspawn, out status_str);
}
public static void AddSpawnItem(XmlSpawner spawner, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface,
List<XmlSpawner.SpawnPositionInfo> spawnpositioning, string propertyString, out string status_str)
{
AddSpawnItem(spawner, spawner, theSpawn, item, location, map, trigmob, requiresurface, spawnpositioning, propertyString, false, out status_str);
}
public static void AddSpawnItem(XmlSpawner spawner, object invoker, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface,
List<XmlSpawner.SpawnPositionInfo> spawnpositioning, string propertyString, out string status_str)
{
AddSpawnItem(spawner, invoker, theSpawn, item, location, map, trigmob, requiresurface, spawnpositioning, propertyString, false, out status_str);
}
public static void AddSpawnItem(XmlSpawner spawner, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface,
List<XmlSpawner.SpawnPositionInfo> spawnpositioning, string propertyString, bool smartspawn, out string status_str)
{
AddSpawnItem(spawner, spawner, theSpawn, item, location, map, trigmob, requiresurface, spawnpositioning, propertyString, smartspawn, out status_str);
}
public static void AddSpawnItem(XmlSpawner spawner, object invoker, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface,
List<XmlSpawner.SpawnPositionInfo> spawnpositioning, string propertyString, bool smartspawn, out string status_str)
{
status_str = null;
if (item == null || theSpawn == null) return;
// add the item to the spawned list
theSpawn.SpawnedObjects.Add(item);
item.Spawner = spawner;
if (spawner != null)
{
// this is being called by a spawner so use spawner information for placement
if (!spawner.Deleted)
{
// set the item amount
if (spawner.StackAmount > 1 && item.Stackable)
{
item.Amount = spawner.StackAmount;
}
// if this is in any container such as a pack then add to the container.
if (spawner.Parent is Container)
{
Container c = (Container)spawner.Parent;
Point3D loc = spawner.Location;
if (!smartspawn)
{
item.OnBeforeSpawn(loc, map);
}
item.Location = loc;
// check to see whether we drop or add the item based on the spawnrange
// this will distribute multiple items around the spawn point, and allow precise
// placement of single spawns at the spawn point
if (spawner.SpawnRange > 0)
c.DropItem(item);
else
c.AddItem(item);
}
else
{
// if the spawn entry is in a subgroup and has a packrange, then get the packcoord
Point3D packcoord = Point3D.Zero;
if (theSpawn.PackRange >= 0 && theSpawn.SubGroup > 0)
{
packcoord = spawner.GetPackCoord(theSpawn.SubGroup);
}
Point3D loc = spawner.GetSpawnPosition(requiresurface, theSpawn.PackRange, packcoord, spawnpositioning);
if (!smartspawn)
{
item.OnBeforeSpawn(loc, map);
}
// standard placement for all items in the world
item.MoveToWorld(loc, map);
}
}
else
{
// if the spawner has already been deleted then delete the item since it cannot be cleaned up by spawner deletion any longer
item.Delete();
return;
}
}
else
{
if (!smartspawn)
{
item.OnBeforeSpawn(location, map);
}
// use the location and map info passed in
// this allows AddSpawnItem to be called by objects other than spawners as long as they pass in a valid SpawnObject
item.MoveToWorld(location, map);
}
// clear the taken flag on all newly spawned items
ItemFlags.SetTaken(item, false);
if (!smartspawn)
{
item.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
BaseXmlSpawner.ApplyObjectStringProperties(spawner, propertyString, item, trigmob, spawner, out status_str);
// if the object has an OnAfterSpawnAndModify method, then invoke it
//InvokeOnAfterSpawnAndModify(item);
}
/*
// hash table for optimizing OnAfterSpawnAndModify method invocation
private static Hashtable OnAfterSpawnAndModifyMethodHash;
public static void InvokeOnAfterSpawnAndModify(object o)
{
if(o == null) return;
// try looking this up in the lookup table
if(OnAfterSpawnAndModifyMethodHash == null)
{
OnAfterSpawnAndModifyMethodHash = new Hashtable();
}
MethodInfo minfo = null;
if(!OnAfterSpawnAndModifyMethodHash.Contains(o.GetType()))
{
// not found so look it up the long way
minfo = o.GetType().GetMethod("OnAfterSpawnAndModify");
if(minfo != null)
{
ParameterInfo [] pinfo = minfo.GetParameters();
// check to make sure the OnSpawned method for this object has the right args
if(pinfo.Length != 0)
{
minfo = null;
}
}
OnAfterSpawnAndModifyMethodHash.Add(o.GetType(),minfo);
} else
{
// look it up in the hash table
minfo = (MethodInfo) OnAfterSpawnAndModifyMethodHash[o.GetType()];
}
try{
if(minfo != null)
{
minfo.Invoke(o, null);
}
} catch {}
}
*/
public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, bool requiresurface,
Mobile triggermob, Point3D location, Map map, out string status_str)
{
return SpawnTypeKeyword(invoker, TheSpawn, typeName, substitutedtypeName, requiresurface, null,
triggermob, location, map, null, out status_str, 0);
}
public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, bool requiresurface,
Mobile triggermob, Point3D location, Map map, XmlGumpCallback gumpcallback, out string status_str, byte loops)
{
return SpawnTypeKeyword(invoker, TheSpawn, typeName, substitutedtypeName, requiresurface, null,
triggermob, location, map, gumpcallback, out status_str, loops);
}
public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, bool requiresurface,
List<XmlSpawner.SpawnPositionInfo> spawnpositioning, Mobile triggermob, Point3D location, Map map, out string status_str, byte loops)
{
return SpawnTypeKeyword(invoker, TheSpawn, typeName, substitutedtypeName, requiresurface, spawnpositioning,
triggermob, location, map, null, out status_str, loops);
}
public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, bool requiresurface,
List<XmlSpawner.SpawnPositionInfo> spawnpositioning, Mobile triggermob, Point3D location, Map map, XmlGumpCallback gumpcallback, out string status_str, byte loops)
{
status_str = null;
if (typeName == null || TheSpawn == null || substitutedtypeName == null) return false;
XmlSpawner spawner = invoker as XmlSpawner;
// check for any special keywords that might appear in the type such as SET, GIVE, or TAKE
#region typeKeyword
if (IsTypeKeyword(typeName))
{
typeKeyword kw = typeKeywordHash[typeName];
switch (kw)
{
case typeKeyword.SET:
{
// the syntax is SET/prop/value/prop2/value...
// check for the SET,itemname or serialno[,itemtype]/prop/value form is used
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
string[] keywordargs = ParseString(arglist[0], 3, ",");
if (keywordargs.Length > 1)
{
string typestr = null;
if (keywordargs.Length > 2)
{
typestr = keywordargs[2];
}
// is the itemname a serialno?
object setitem = null;
if (keywordargs[1].StartsWith("0x"))
{
int serial = -1;
try
{
serial = Convert.ToInt32(keywordargs[1], 16);
}
catch { }
if (serial >= 0)
setitem = World.FindEntity(serial);
}
else
{
// just look it up by name
setitem = FindItemByName(spawner, keywordargs[1], typestr);
}
if (setitem == null)
{
status_str = "cant find unique item :" + keywordargs[1];
return false;
}
else
{
ApplyObjectStringProperties(spawner, substitutedtypeName, setitem, triggermob, invoker, out status_str);
}
}
else if (spawner != null)
{
ApplyObjectStringProperties(spawner, substitutedtypeName, spawner.SetItem, triggermob, invoker, out status_str);
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.SETONMOB:
{
// the syntax is SETONMOB,mobname[,mobtype]/prop/value/prop2/value...
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
Mobile mob = null;
if (arglist.Length > 0)
{
string[] keywordargs = ParseString(arglist[0], 3, ",");
if (keywordargs.Length > 1)
{
string typestr = null;
if (keywordargs.Length > 2)
{
typestr = keywordargs[2];
}
mob = FindMobileByName(spawner, keywordargs[1], typestr);
if (mob == null)
{
status_str = String.Format("named mob '{0}' not found", keywordargs[1]);
}
}
else
{
status_str = "missing mob name in SETONMOB";
}
}
if (mob != null)
{
ApplyObjectStringProperties(spawner, substitutedtypeName, mob, triggermob, invoker, out status_str);
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.SETONTHIS:
{
// the syntax is SETONTHIS[,proptest=value]/prop/value/prop2/value2/prop3/value3/..
//string [] arglist = ParseString(substitutedtypeName,3,"/");
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
string proptest = null;
if(arglist.Length > 0)
{
string[] objstr = ParseString(arglist[0], 2, ",");
if (objstr.Length > 1)
{
proptest = objstr[1];
}
}
else
{
status_str = "missing args to SETONTHIS";
return false;
}
if(invoker != null && (proptest == null || CheckPropertyString(null, invoker, proptest, null, out status_str)))
{
ApplyObjectStringProperties(spawner, substitutedtypeName, invoker, triggermob, invoker, out status_str);
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.SETONTRIGMOB:
{
// the syntax is SETONTRIGMOB/prop/value/prop2/value...
ApplyObjectStringProperties(spawner, substitutedtypeName, triggermob, triggermob, invoker, out status_str);
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.SETACCOUNTTAG:
{
// the syntax is SETACCOUNTTAG,tagname/value
string[] arglist = ParseSlashArgs(substitutedtypeName, 2);
if (arglist.Length > 1)
{
string[] objstr = ParseString(arglist[0], 2, ",");
if (objstr.Length < 2)
{
status_str = "missing tagname in SETACCOUNTTAG";
return false;
}
string tagname = objstr[1];
string tagval = arglist[1];
// set the tag value
// get the value of the account tag from the triggering mob
if (triggermob != null && !triggermob.Deleted)
{
Account acct = triggermob.Account as Account;
if (acct != null)
{
acct.SetTag(tagname, tagval);
}
}
}
else
{
status_str = "no value assigned to SETACCOUNTTAG";
return false;
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.FOREACH:
{
// the syntax is FOREACH,objecttype[,name][,range]/action
string[] arglist = ParseSlashArgs(substitutedtypeName, 2);
if(arglist.Length > 1)
{
string[] objstr = ParseString(arglist[0], 4, ",");
if (objstr.Length < 2)
{
status_str = "missing objecttype in FOREACH";
return false;
}
Type objecttype = SpawnerType.GetType(objstr[1]);
if(objecttype != null)
{
int range = -1;
string objectname = "*";
if(objstr.Length > 2)
{
objectname = objstr[2];
if(objstr.Length > 3 && !int.TryParse(objstr[3], out range))
range = -1;
}
if((spawner==null || spawner.Deleted) && range<0)
{
status_str = "invalid range outside of spawner in FOREACH";
return false;
}
string remaining = arglist[1];
if(typeof(Mobile).IsAssignableFrom(objecttype))
{
List<Mobile> mobs = new List<Mobile>();
if(spawner!=null)
{
if(spawner.SpawnRegion!=null && spawner.HasRegionPoints(spawner.SpawnRegion))
{
foreach(Mobile m in spawner.SpawnRegion.GetMobiles())
{
if(objecttype.IsAssignableFrom(m.GetType()) && CheckNameMatch(objectname, m.Name))
mobs.Add(m);
}
}
else
{
foreach(Mobile m in map.GetMobilesInBounds(spawner.SpawnerBounds))
{
if(objecttype.IsAssignableFrom(m.GetType()) && CheckNameMatch(objectname, m.Name))
{
mobs.Add(m);
}
}
}
}
else if(invoker!=null && invoker is IEntity)
{
IPooledEnumerable eable = map.GetMobilesInRange(((IEntity)invoker).Location, range);
foreach(Mobile m in eable)
{
if(objecttype.IsAssignableFrom(m.GetType()) && CheckNameMatch(objectname, m.Name))
mobs.Add(m);
}
eable.Free();
}
for(int x = mobs.Count - 1; x>=0; --x)
{
if(mobs[x].AccessLevel < AccessLevel.Counselor)
ApplyObjectStringProperties(spawner, substitutedtypeName, mobs[x], mobs[x], invoker, out status_str);
}
}
else if(typeof(Item).IsAssignableFrom(objecttype))
{
List<Item> items = new List<Item>();
if(spawner!=null)
{
if(spawner.SpawnRegion!=null && spawner.HasRegionPoints(spawner.SpawnRegion))
{
foreach(Item i in GetItems(spawner.SpawnRegion))
{
if(objecttype.IsAssignableFrom(i.GetType()) && CheckNameMatch(objectname, i.Name))
items.Add(i);
}
}
else
{
foreach(Item i in map.GetItemsInBounds(spawner.SpawnerBounds))
{
if(objecttype.IsAssignableFrom(i.GetType()) && CheckNameMatch(objectname, i.Name))
items.Add(i);
}
}
}
else if(invoker!=null && invoker is IEntity)
{
foreach(Item i in map.GetItemsInRange(((IEntity)invoker).Location, range))
{
if(objecttype.IsAssignableFrom(i.GetType()) && CheckNameMatch(objectname, i.Name))
items.Add(i);
}
}
for(int x = items.Count - 1; x>=0; --x)
ApplyObjectStringProperties(spawner, substitutedtypeName, items[x], triggermob, invoker, out status_str);
}
else
{
status_str = "invalid TYPE specified in FOREACH";
return false;
}
}
else
{
status_str = "invalid TYPE specified in FOREACH";
return false;
}
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.SETVAR:
{
// the syntax is SETVAR,varname/value
string[] arglist = ParseSlashArgs(substitutedtypeName, 2);
if (arglist.Length > 1)
{
string[] objstr = ParseString(arglist[0], 2, ",");
if (objstr.Length < 2)
{
status_str = "missing varname in SETVAR";
return false;
}
string varname = objstr[1];
string varval = arglist[1];
// find the xmllocalvariable attachment with that name
XmlLocalVariable a = (XmlLocalVariable)XmlAttach.FindAttachment(invoker, typeof(XmlLocalVariable), varname);
if (a == null)
{
// doesnt already exist so add it
XmlAttach.AttachTo(invoker, new XmlLocalVariable(varname, varval));
}
else
{
a.Data = varval;
}
}
else
{
status_str = "no value assigned to SETVAR";
return false;
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.SETONNEARBY:
{
// the syntax is SETONNEARBY,range,name[,type][,searchcontainers][,proptest]/prop/value/prop/value...
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
string typestr = null;
string targetname = null;
string proptest = null;
int range = -1;
bool searchcontainers = false;
if (arglist.Length > 0)
{
string[] objstr = ParseString(arglist[0], 6, ",");
if (objstr.Length < 3)
{
status_str = "missing range or name in SETONNEARBY";
return false;
}
if(!int.TryParse(objstr[1], out range))
range=-1;
if (range < 0)
{
status_str = "invalid range in SETONNEARBY";
return false;
}
targetname = objstr[2];
if (objstr.Length > 3)
{
typestr = objstr[3];
}
if (objstr.Length > 4)
{
bool.TryParse(objstr[4], out searchcontainers);
}
if (objstr.Length > 5)
{
proptest = objstr[5];
}
}
else
{
status_str = "missing args to SETONNEARBY";
return false;
}
Type targettype = null;
if (typestr != null)
{
targettype = SpawnerType.GetType(typestr);
}
List<object> nearbylist = GetNearbyObjects(invoker, targetname, targettype, typestr, range, searchcontainers, proptest);
// apply the properties to everything on the list
foreach (object nearbyobj in nearbylist)
{
ApplyObjectStringProperties(spawner, substitutedtypeName, nearbyobj, triggermob, invoker, out status_str);
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.SETONPETS:
{
// the syntax is SETONPETS,range[,name]/prop/value/prop/value...
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
string typestr = "BaseCreature";
string targetname = "*";
int range = -1;
bool searchcontainers = false;
if (arglist.Length > 0)
{
string[] objstr = ParseString(arglist[0], 3, ",");
if (objstr.Length < 2)
{
status_str = "missing range in SETONPETS";
return false;
}
if(!int.TryParse(objstr[1], out range))
range=-1;
if (range < 0)
{
status_str = "invalid range in SETONPETS";
return false;
}
if(objstr.Length > 2)
targetname = objstr[2];
}
else
{
status_str = "missing args to SETONPETS";
return false;
}
Type targettype = null;
if (typestr != null)
{
targettype = SpawnerType.GetType(typestr);
}
// get all of the nearby pets
List<object> nearbylist = GetNearbyObjects(triggermob, targetname, targettype, typestr, range, searchcontainers, null);
// apply the properties to everything on the list
foreach (object nearbyobj in nearbylist)
{
// is this a pet of the triggering mob
BaseCreature pet = nearbyobj as BaseCreature;
if (pet != null && pet.Controlled && pet.ControlMaster == triggermob)
{
ApplyObjectStringProperties(spawner, substitutedtypeName, nearbyobj, triggermob, invoker, out status_str);
}
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.SETONCARRIED:
{
// the syntax is SETONCARRIED,itemname[,itemtype][,equippedonly]/prop/value/prop2/value...
// or SETONCARRIED,itemname[,itemtype]/prop/value
// first find the carried item
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
string typestr = null;
string itemname = null;
bool equippedonly = false;
if (arglist.Length > 0)
{
string[] objstr = ParseString(arglist[0], 4, ",");
if (objstr.Length < 2)
{
status_str = "missing itemname in SETONCARRIED";
return false;
}
itemname = objstr[1];
if (objstr.Length > 2)
{
typestr = objstr[2];
}
if (objstr.Length > 3)
{
if (objstr[3].ToLower() == "equippedonly")
{
equippedonly = true;
}
else
{
bool.TryParse(objstr[3], out equippedonly);
}
}
}
else
{
status_str = "missing args to SETONCARRIED";
return false;
}
Item testitem = SearchMobileForItem(triggermob, ParseObjectType(itemname), typestr, false, equippedonly);
ApplyObjectStringProperties(spawner, substitutedtypeName, testitem, triggermob, invoker, out status_str);
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.SETONSPAWN:
{
// the syntax is SETONSPAWN[,spawnername],subgroup/prop/value/prop2/value...
// or SETONSPAWN[,spawnername],subgroup/prop/value
// first find the spawn
int subgroup = -1;
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
XmlSpawner targetspawner = spawner;
if (arglist.Length > 0)
{
string[] keywordargs = ParseString(arglist[0], 3, ",");
if (keywordargs.Length < 2)
{
status_str = "missing subgroup in SETONSPAWN";
return false;
}
else
{
string subgroupstr = keywordargs[1];
string spawnerstr = null;
if (keywordargs.Length > 2)
{
spawnerstr = keywordargs[1];
subgroupstr = keywordargs[2];
}
if (spawnerstr != null)
{
targetspawner = FindSpawnerByName(spawner, spawnerstr);
}
if(!int.TryParse(subgroupstr, out subgroup))
subgroup=-1;
}
}
if (subgroup == -1)
{
status_str = "invalid subgroup in SETONSPAWN";
return false;
}
List<object> spawnedlist = XmlSpawner.GetSpawnedList(targetspawner, subgroup);
if (spawnedlist == null) return true;
foreach (object targetobj in spawnedlist)
{
if (targetobj == null) return true;
// dont apply it to keyword tags
if (targetobj is KeywordTag) continue;
// set the properties on the target object
ApplyObjectStringProperties(spawner, substitutedtypeName, targetobj, triggermob, spawner, out status_str);
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.SETONSPAWNENTRY:
{
// the syntax is SETONSPAWNENTRY[,spawnername],entrystring/prop/value/prop2/value...
// find the spawn entry
string entrystring = null;
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
XmlSpawner targetspawner = spawner;
if (arglist.Length > 0)
{
string[] keywordargs = ParseString(arglist[0], 3, ",");
if (keywordargs.Length < 2)
{
status_str = "missing entrystring in SETONSPAWNENTRY";
return false;
}
else
{
entrystring = keywordargs[1];
string spawnerstr = null;
if (keywordargs.Length > 2)
{
spawnerstr = keywordargs[1];
entrystring = keywordargs[2];
}
if (spawnerstr != null)
{
targetspawner = FindSpawnerByName(spawner, spawnerstr);
}
}
}
if (entrystring == null || entrystring.Length == 0)
{
status_str = "invalid entrystring in SETONSPAWNENTRY";
return false;
}
int entryindex = -1;
// is the entrystring a number?
if (entrystring[0] >= '0' && entrystring[0] <= '9')
{
if(!int.TryParse(entrystring, out entryindex))
entryindex=-1;
}
if (targetspawner == null || targetspawner.SpawnObjects == null) return true;
for (int i = 0; i < targetspawner.SpawnObjects.Length; i++)
{
XmlSpawner.SpawnObject targetobj = targetspawner.SpawnObjects[i];
// is this references by entrystring or entryindex?
if ((entryindex == i)
|| (entryindex == -1 && targetobj != null && targetobj.TypeName != null && targetobj.TypeName.IndexOf(entrystring) >= 0))
{
// set the properties on the spawn entry object
ApplyObjectStringProperties(spawner, substitutedtypeName, targetobj, triggermob, spawner, out status_str);
}
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.SETONPARENT:
{
// the syntax is SETONPARENT/prop/value/prop2/value...
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
if (invoker != null && (invoker is Item))
{
ApplyObjectStringProperties(spawner, substitutedtypeName, ((Item)invoker).Parent, triggermob, invoker, out status_str);
}
else if (invoker != null && (invoker is XmlAttachment))
{
ApplyObjectStringProperties(spawner, substitutedtypeName, ((XmlAttachment)invoker).Attached, triggermob, invoker, out status_str);
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.TAKEGIVE:
{
// syntax TAKEGIVE[,quantity[,true*,[type]]]/itemnametotake/GIVE/itemtypetogive *search in banca
string[] arglist = ParseSlashArgs(substitutedtypeName, 5);
string[] givelist = null;
string targetName;
string typestr = null;
if (arglist.Length < 4)
{
status_str = "invalid TAKEGIVE specification";
return false;
}
else
{
givelist = new string[arglist.Length - 2];
targetName = arglist[1];
Array.Copy(arglist, 2, givelist, 0, arglist.Length -2);
}
string[] keywordargs = ParseString(arglist[0], 4, ",");
string[] givekeywordargs = ParseString(givelist[0], 2, ",");
int quantity = 0;
bool banksearch = false;
bool success = false;
List<Item> toRemove = new List<Item>();
if (keywordargs.Length > 1)
{
if(!int.TryParse(keywordargs[1], out quantity))
{
status_str = "Invalid TAKE quantity : " + arglist[1];
return false;
}
}
if (keywordargs.Length > 2)
{
if(!bool.TryParse(keywordargs[2], out banksearch))
{
status_str = "Invalid TAKE bankflag : " + arglist[1];
return false;
}
}
if (keywordargs.Length > 3)
{
typestr = keywordargs[3];
}
// search the trigger mob for the named item
Item itemTarget = SearchMobileForItem(triggermob, targetName, typestr, banksearch);
// found the item so get rid of it
if (itemTarget != null)
{
// if a quantity was specified and the item is stackable, then try to take the quantity
if (quantity > 0 && itemTarget.Stackable)
{
List<Item> itemlist = SearchMobileForItems(triggermob, targetName, typestr, banksearch, false);
itemlist.Reverse();
int totaltaken = 0;
int totake = quantity;
int remaining=0;
int taken=0;
foreach(Item it in itemlist)
{
remaining = it.Amount - quantity;
if(remaining <= 0)
{
taken = it.Amount;
totaltaken += taken;
toRemove.Add(it);
quantity -= taken;
}
else
{
totaltaken += quantity;
it.Amount = remaining;
break;
}
}
if(totaltaken>=totake)
{
for(int i=toRemove.Count - 1; i>=0; --i)
toRemove[i].Delete();
success=true;
}
}
else//non stackable, we have to find them all
{
// dont save quest holders
if (itemTarget is XmlQuestBook || itemTarget is IXmlQuest || quantity<=1)
{
toRemove.Add(itemTarget);
}
else
{
List<Item> itemlist = SearchMobileForItems(triggermob, targetName, typestr, banksearch, false);
itemlist.Reverse();
for(int i=itemlist.Count - 1, totake=quantity;i>=0 && totake>0;--i, --totake)
{
toRemove.Add(itemlist[i]);
}
}
if(toRemove.Count>=quantity)
{
for(int i=toRemove.Count - 1; i>=0; --i)
toRemove[i].Delete();
success=true;
}
}
string remainder;
if(success)
AddItemToTarget(spawner, triggermob, givekeywordargs, givelist, triggermob, invoker, false, out remainder, out status_str);
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.GIVE:
{
//syntax is GIVE[,probability (0.01=1% 1=100%)]/itemtypetogive
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
string remainder;
if (arglist.Length > 1)
{
// check for any special keywords such as the additem option or the subproperty specification
// note this will be an arg to some property
string[] keywordargs = ParseString(arglist[0], 2, ",");
AddItemToTarget(spawner, triggermob, keywordargs, arglist, triggermob, invoker, false, out remainder, out status_str);
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.TAKE:
{
// syntax TAKE[,prob[,quantity[,true,[type]]]]/itemname
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
string targetName;
string typestr = null;
if (arglist.Length > 1)
{
targetName = arglist[1];
}
else
{
status_str = "invalid TAKE specification";
return false;
}
string[] keywordargs = ParseString(arglist[0], 5, ",");
double drop_probability = 1;
int quantity = 0;
bool banksearch = false;
Item savedItem = null;
if (keywordargs.Length > 1)
{
if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability))
{
status_str = "Invalid TAKE probability : " + arglist[1];
return false;
}
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out quantity))
{
status_str = "Invalid TAKE quantity : " + arglist[1];
return false;
}
}
if (keywordargs.Length > 3)
{
if(!bool.TryParse(keywordargs[3], out banksearch))
{
status_str = "Invalid TAKE bankflag : " + arglist[1];
return false;
}
}
if (keywordargs.Length > 4)
{
typestr = keywordargs[4];
}
if (drop_probability == 1 || Utility.RandomDouble() < drop_probability)
{
// search the trigger mob for the named item
Item itemTarget = SearchMobileForItem(triggermob, targetName, typestr, banksearch);
// found the item so get rid of it
if (itemTarget != null)
{
// if a quantity was specified and the item is stackable, then try to take the quantity
if (quantity > 0 && itemTarget.Stackable)
{
// create a copy of the stacked item to be saved
//savedItem = itemTarget.Dupe(0);
savedItem = Mobile.LiftItemDupe(itemTarget, itemTarget.Amount);
if (savedItem != null)
{
savedItem.Internalize();
}
int totaltaken = 0;
int remaining = itemTarget.Amount - quantity;
if (remaining <= 0)
{
int taken = itemTarget.Amount;
totaltaken += taken;
itemTarget.Delete();
while (remaining < 0)
{
quantity -= taken;
// if didnt get the full amount then keep looking for other stacks
itemTarget = SearchMobileForItem(triggermob, targetName, typestr, banksearch);
if (itemTarget == null) break;
remaining = itemTarget.Amount - quantity;
if (remaining <= 0)
{
taken = itemTarget.Amount;
totaltaken += taken;
itemTarget.Delete();
}
else
{
totaltaken += quantity;
itemTarget.Amount = remaining;
}
}
}
else
{
totaltaken = quantity;
itemTarget.Amount = remaining;
}
if (savedItem != null)
{
savedItem.Amount = totaltaken;
}
}
else
{
// dont save quest holders
if (itemTarget is XmlQuestBook || itemTarget is IXmlQuest)
{
itemTarget.Delete();
}
else
savedItem = itemTarget;
}
// if the saved item was being held then release it otherwise the player can take it back
if (triggermob != null && triggermob.Holding == savedItem)
{
triggermob.Holding = null;
}
XmlSaveItem si = (XmlSaveItem)XmlAttach.FindAttachment(invoker, typeof(XmlSaveItem), "Taken");
if (si == null)
{
XmlAttach.AttachTo(invoker, new XmlSaveItem("Taken", savedItem, triggermob));
}
else
{
si.SavedItem = savedItem;
si.WasOwnedBy = triggermob;
}
}
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.TAKEBYTYPE:
{
// syntax TAKEBYTYPE[,prob[,quantity[,true]]]/itemtype
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
string targetName;
if (arglist.Length > 1)
{
targetName = arglist[1];
}
else
{
status_str = "invalid TAKEBYTYPE specification";
return false;
}
string[] keywordargs = ParseString(arglist[0], 4, ",");
double drop_probability = 1;
int quantity = 0;
bool banksearch = false;
Item savedItem = null;
if (keywordargs.Length > 1)
{
if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability))
{
status_str = "Invalid TAKEBYTYPE probability : " + arglist[1];
return false;
}
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out quantity))
{
status_str = "Invalid TAKEBYTYPE quantity : " + arglist[1];
return false;
}
}
if (keywordargs.Length > 3)
{
if(!bool.TryParse(keywordargs[3], out banksearch))
{
status_str = "Invalid TAKEBYTYPE bankflag : " + arglist[1];
return false;
}
}
if (drop_probability == 1 || Utility.RandomDouble() < drop_probability)
{
// search the trigger mob for the named item
Item itemTarget = SearchMobileForItemType(triggermob, targetName, banksearch);
// found the item so get rid of it
if (itemTarget != null)
{
// if a quantity was specified and the item is stackable, then try to take the quantity
if (quantity > 0 && itemTarget.Stackable)
{
// create a copy of the stacked item to be saved
//savedItem = itemTarget.Dupe(0);
savedItem = Mobile.LiftItemDupe(itemTarget, itemTarget.Amount);
if (savedItem != null)
{
savedItem.Internalize();
}
int totaltaken = 0;
int remaining = itemTarget.Amount - quantity;
if (remaining <= 0)
{
int taken = itemTarget.Amount;
totaltaken += taken;
itemTarget.Delete();
while (remaining < 0)
{
quantity -= taken;
// if didnt get the full amount then keep looking for other stacks
itemTarget = SearchMobileForItemType(triggermob, targetName, banksearch);
if (itemTarget == null) break;
remaining = itemTarget.Amount - quantity;
if (remaining <= 0)
{
taken = itemTarget.Amount;
totaltaken += taken;
itemTarget.Delete();
}
else
{
totaltaken += quantity;
itemTarget.Amount = remaining;
}
}
}
else
{
totaltaken = quantity;
itemTarget.Amount = remaining;
}
if (savedItem != null)
{
savedItem.Amount = totaltaken;
}
}
else
{
// dont save quest holders
if (itemTarget is XmlQuestBook || itemTarget is XmlQuestHolder || itemTarget is XmlQuestToken)
{
itemTarget.Delete();
}
else
savedItem = itemTarget;
}
}
// is there an existing xmlsaveitem attachment
XmlSaveItem si = (XmlSaveItem)XmlAttach.FindAttachment(invoker, typeof(XmlSaveItem), "Taken");
if (si == null)
{
XmlAttach.AttachTo(invoker, new XmlSaveItem("Taken", savedItem, triggermob));
}
else
{
si.SavedItem = savedItem;
si.WasOwnedBy = triggermob;
}
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.GUMP:
{
// the syntax is GUMP,title,type/string
// can alternatively accept a gump constructor name
// GUMP,title,type,constructorname/string
string[] arglist = ParseSlashArgs(substitutedtypeName, 2);
string gumpText;
if (arglist.Length > 1)
{
gumpText = arglist[1];
}
else
{
status_str = "invalid GUMP specification";
return false;
}
string[] gumpkeywordargs = ParseString(arglist[0], 4, ",");
string gumpTitle = "";
int gumpNumber = 0; // 0=simple text gump, 1=yes/no gump, 2=reply gump, 3=quest gump, 4=multiple option gump (free)
if (gumpkeywordargs.Length > 2)
{
gumpTitle = gumpkeywordargs[1];
if(!int.TryParse(gumpkeywordargs[2], out gumpNumber))
{
status_str = "Invalid GUMP args";
return false;
}
}
else
{
status_str = "invalid GUMP specification";
return false;
}
string gumptypestr = "XmlSimpleGump"; // default gump constructor
if (gumpkeywordargs.Length > 3)
{
// get the gump constructor type
gumptypestr = gumpkeywordargs[3].Trim();
}
Type type = SpawnerType.GetType(gumptypestr);;
if (type == null)
{
status_str = "invalid GUMP constructor : " + gumptypestr;
return false;
}
// prepare the keyword tag for the gump
KeywordTag newtag = new KeywordTag(substitutedtypeName, spawner, 1);
if (triggermob != null && !triggermob.Deleted && (triggermob is PlayerMobile))
{
object newgump = null;
object[] gumpargs = new object[7];
gumpargs[0] = invoker;
gumpargs[1] = gumpText;
gumpargs[2] = gumpTitle;
gumpargs[3] = gumpNumber;
gumpargs[4] = newtag;
gumpargs[5] = triggermob;
gumpargs[6] = gumpcallback;
//spawner.TriggerMob.SendGump( new XmlSimpleGump(this, gumpText,gumpTitle, gumpType ));
try
{
newgump = Activator.CreateInstance(type, gumpargs);
}
catch { status_str = "Error in creating gump type : " + gumptypestr; newtag.Delete(); return false; }
if (newgump != null)
{
if (newgump is Gump)
{
triggermob.SendGump((Gump)newgump);
}
else if (newgump is Item)
{
((Item)newgump).Delete();
status_str = gumptypestr + " is not a Gump type";
newtag.Delete();
return false;
}
else if (newgump is Mobile)
{
((Mobile)newgump).Delete();
status_str = gumptypestr + " is not a Gump type";
newtag.Delete();
return false;
}
else
{
status_str = gumptypestr + " is not a Gump type";
newtag.Delete();
return false;
}
}
}
TheSpawn.SpawnedObjects.Add(newtag);
break;
}
case typeKeyword.BROWSER:
{
// the syntax is BROWSER/url
string[] arglist = ParseSlashArgs(substitutedtypeName, 2);
string url;
if (arglist.Length > 1)
{
if (arglist[1] != null && arglist[1].Length > 0 && arglist[1][0] == '@')
{
url = arglist[1].Substring(1);
}
else
url = arglist[1];
}
else
{
status_str = "invalid BROWSER specification";
return false;
}
if (triggermob != null && !triggermob.Deleted && (triggermob is PlayerMobile))
{
triggermob.LaunchBrowser(url);
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.SENDMSG:
{
// the syntax is SENDMSG[,hue]/string
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
// check for literal
string msgText;
int hue = 0x3B2;
int font = 3;
if (arglist.Length > 0)
{
string[] keywordargs = ParseString(arglist[0], 3, ",");
if (keywordargs.Length > 1)
{
if(!int.TryParse(keywordargs[1], out hue))
{
hue=0x3B2;
status_str = "invalid hue arg to SENDMSG";
}
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out font))
{
font = 3;
status_str = "invalid font arg to SENDASCIIMSG";
}
}
}
if (arglist.Length > 1)
{
if (arglist[1] != null && arglist[1].Length > 0 && arglist[1][0] == '@')
{
arglist = ParseSlashArgs(substitutedtypeName, 2);
msgText = arglist[1].Substring(1);
}
else
msgText = arglist[1];
}
else
{
status_str = "invalid SENDMSG specification";
return false;
}
if (triggermob != null && !triggermob.Deleted && (triggermob is PlayerMobile))
{
//triggermob.SendMessage(msgText);
triggermob.Send(new UnicodeMessage(Serial.MinusOne, -1, MessageType.Regular, hue, font, "ENU", "System", msgText));
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.SENDASCIIMSG:
{
// the syntax is SENDASCIIMSG[,hue][,font#]/string
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
// check for literal
string msgText;
int hue = 0x3B2;
int font = 3;
if (arglist.Length > 0)
{
string[] keywordargs = ParseString(arglist[0], 3, ",");
if (keywordargs.Length > 1)
{
if(!int.TryParse(keywordargs[1], out hue))
{
hue = 0x3B2;
status_str = "invalid hue arg to SENDASCIIMSG";
}
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out font))
{
font = 3;
status_str = "invalid font arg to SENDASCIIMSG";
}
}
}
if (arglist.Length > 1)
{
if (arglist[1] != null && arglist[1].Length > 0 && arglist[1][0] == '@')
{
arglist = ParseSlashArgs(substitutedtypeName, 2);
msgText = arglist[1].Substring(1);
}
else
msgText = arglist[1];
}
else
{
status_str = "invalid SENDASCIIMSG specification";
return false;
}
if (triggermob != null && !triggermob.Deleted && (triggermob is PlayerMobile))
{
triggermob.Send(new AsciiMessage(Serial.MinusOne, -1, MessageType.Regular, hue, font, "System", msgText));
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.WAITUNTIL:
{
// the syntax is WAITUNTIL[,delay][,timeout][/condition][/thendogroup]
string[] arglist = ParseSlashArgs(substitutedtypeName, 4);
double delay = 0;
double timeout = 0;
string condition = null;
int gotogroup = -1;
if (arglist.Length > 0)
{
string[] keywordargs = ParseString(arglist[0], 3, ",");
if (keywordargs.Length > 1)
{
if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out delay))
status_str = "invalid delay arg to WAITUNTIL";
}
if (keywordargs.Length > 2)
{
if (!double.TryParse(keywordargs[2], NumberStyles.Any, CultureInfo.InvariantCulture, out timeout))
status_str = "invalid timeout arg to WAITUNTIL";
}
}
if (arglist.Length > 1)
{
condition = arglist[1];
}
if (arglist.Length > 2)
{
if(!int.TryParse(arglist[2], out gotogroup))
{
status_str = "invalid goto arg to WAITUNTIL";
gotogroup = -1;
}
}
if (status_str != null)
{
return false;
}
// suppress sequential advancement
//spawner.HoldSequence = true;
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner, TimeSpan.FromMinutes(delay), TimeSpan.FromMinutes(timeout), condition, gotogroup));
break;
}
case typeKeyword.WHILE:
{
// the syntax is WHILE/condition/dogroup
string[] arglist = ParseSlashArgs(substitutedtypeName, 4);
string condition = null;
int gotogroup = -1;
if (arglist.Length < 3)
{
status_str = "insufficient args to WHILE";
}
else
{
condition = arglist[1];
if(!int.TryParse(arglist[2], out gotogroup))
{
status_str = "invalid dogroup arg to WHILE";
gotogroup = -1;
}
}
if (status_str != null)
{
return false;
}
// test the condition
if (TestItemProperty(spawner, spawner, condition, triggermob, out status_str))
{
// try to spawn the dogroup
if (spawner != null && !spawner.Deleted)
{
if(gotogroup >= 0)
{
if(loops>=XmlSpawner.MaxLoops)
{
status_str = "recursive looping stop in WHILE";
return false;
}
// spawn the subgroup
spawner.SpawnSubGroup(gotogroup, (byte)(loops+1));
// advance the sequence to that group
//spawner.SequentialSpawn = gotogroup;
}
// and suppress sequential advancement
spawner.HoldSequence = true;
}
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.IF:
{
// the syntax is IF/condition/thengroup [/elsegroup]
string[] arglist = ParseSlashArgs(substitutedtypeName, 5);
string condition = null;
int thengroup = -1;
int elsegroup = -1;
if (arglist.Length < 3)
{
status_str = "insufficient args to IF";
}
else
{
condition = arglist[1];
if(!int.TryParse(arglist[2], out thengroup))
{
status_str = "invalid thengroup arg to IF";
thengroup=-1;
}
}
if (arglist.Length > 3)
{
if(!int.TryParse(arglist[3], out elsegroup))
{
status_str = "invalid elsegroup arg to IF";
elsegroup = -1;
}
}
if (status_str != null)
{
return false;
}
// test the condition
if (TestItemProperty(spawner, spawner, condition, triggermob, out status_str))
{
// try to spawn the thengroup
if (thengroup >= 0 && spawner != null && !spawner.Deleted)
{
// spawn the subgroup
if(loops>=XmlSpawner.MaxLoops)
{
status_str = "recursive looping stop in IF";
return false;
}
spawner.SpawnSubGroup(thengroup, (byte)(loops+1));
// advance the sequence to that group
//spawner.SequentialSpawn = thengroup;
}
// and suppress sequential advancement
//spawner.HoldSequence = true;
}
else
{
// try to spawn the elsegroup
if (elsegroup >= 0 && spawner != null && !spawner.Deleted)
{
// spawn the subgroup
if(loops>=XmlSpawner.MaxLoops)
{
status_str = "recursive looping stop in IF";
return false;
}
spawner.SpawnSubGroup(elsegroup, (byte)(loops+1));
// advance the sequence to that group
//spawner.SequentialSpawn = elsegroup;
}
// and suppress sequential advancement
//spawner.HoldSequence = true;
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.DESPAWN:
{
// the syntax is DESPAWN[,spawnername],subgroup
// first find the spawner and group
int subgroup = -1;
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
XmlSpawner targetspawner = spawner;
if (arglist.Length > 0)
{
string[] keywordargs = ParseString(arglist[0], 3, ",");
if (keywordargs.Length < 2)
{
status_str = "missing subgroup in DESPAWN";
return false;
}
else
{
string subgroupstr = keywordargs[1];
string spawnerstr = null;
if (keywordargs.Length > 2)
{
spawnerstr = keywordargs[1];
subgroupstr = keywordargs[2];
}
if (spawnerstr != null)
{
targetspawner = FindSpawnerByName(spawner, spawnerstr);
}
if(!int.TryParse(subgroupstr, out subgroup))
subgroup = -1;
}
}
if (subgroup == -1)
{
status_str = "invalid subgroup in DESPAWN";
return false;
}
if (targetspawner != null)
{
targetspawner.ClearSubgroup(subgroup);
}
else
{
status_str = "invalid spawner in DESPAWN";
return false;
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.SPAWN:
{
// the syntax is SPAWN[,spawnername],subgroup
// first find the spawner and group
int subgroup = -1;
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
XmlSpawner targetspawner = spawner;
if (arglist.Length > 0)
{
string[] keywordargs = ParseString(arglist[0], 3, ",");
if (keywordargs.Length < 2)
{
status_str = "missing subgroup in SPAWN";
return false;
}
else
{
string subgroupstr = keywordargs[1];
string spawnerstr = null;
if (keywordargs.Length > 2)
{
spawnerstr = keywordargs[1];
subgroupstr = keywordargs[2];
}
if (spawnerstr != null)
{
targetspawner = FindSpawnerByName(spawner, spawnerstr);
}
if(!int.TryParse(subgroupstr, out subgroup))
subgroup = -1;
}
}
if (subgroup == -1)
{
status_str = "invalid subgroup in SPAWN";
return false;
}
if (targetspawner != null)
{
if (spawner != targetspawner)
{
// allow spawning of other spawners to be forced and ignore the normal loop protection
if(loops>=XmlSpawner.MaxLoops) //preventing looping from spawner to spawner, via recursive linked method calls
{
status_str = "recursive looping stop in SPAWN";
return false;
}
targetspawner.SpawnSubGroup(subgroup, false, true, (byte)(loops+1));
}
else
{
if(loops>=XmlSpawner.MaxLoops)
{
status_str = "recursive looping stop in SPAWN";
return false;
}
targetspawner.SpawnSubGroup(subgroup, (byte)(loops+1));
}
}
else
{
status_str = "invalid spawner in SPAWN";
return false;
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.GOTO:
{
// the syntax is GOTO/subgroup
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
int group=-1;
if (arglist.Length < 2)
{
status_str = "insufficient args to GOTO";
}
else
{
if(!int.TryParse(arglist[1], out group))
{
status_str = "invalid subgroup arg to GOTO";
group=-1;
}
}
if (status_str != null)
{
return false;
}
// move the sequence to the specified subgroup
if (group >= 0 && spawner != null && !spawner.Deleted)
{
// note, this will activate sequential spawning if it wasnt already set
spawner.SequentialSpawn = group;
// and suppress sequential advancement so that the specified group is the next to spawn
spawner.HoldSequence = true;
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner, 2));
break;
}
case typeKeyword.COMMAND:
{
// the syntax is COMMAND/commandstring
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
if (arglist.Length > 0)
{
// mod to use a dummy char to issue commands
if (CommandMobileName != null)
{
Mobile dummy = FindMobileByName(spawner, CommandMobileName, "Mobile");
if (dummy != null)
{
CommandSystem.Handle(dummy, String.Format("{0}{1}", CommandSystem.Prefix, arglist[1]));
}
}
else
if (triggermob != null && !triggermob.Deleted)
{
CommandSystem.Handle(triggermob, String.Format("{0}{1}", CommandSystem.Prefix, arglist[1]));
}
}
else
{
status_str = "insufficient args to COMMAND";
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.MUSIC:
{
// the syntax is MUSIC,name,range
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
if (arglist.Length > 0)
{
SendMusicToPlayers(arglist[0], triggermob, invoker, out status_str);
if (status_str != null)
{
return false;
}
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.SOUND:
{
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
if (arglist.Length > 0)
{
// Syntax is SOUND,soundnumber
string[] keywordargs = ParseString(arglist[0], 3, ",");
int sound=-1;
// try to get the soundnumber argument
if (keywordargs.Length < 2)
{
status_str = "Missing sound number";
}
else
{
if(!int.TryParse(keywordargs[1], out sound))
{
status_str = "Improper sound number format";
sound=-1;
}
}
if (sound >= 0 && invoker is IEntity)
{
Effects.PlaySound(((IEntity)invoker).Location, ((IEntity)invoker).Map, sound);
}
if (status_str != null)
{
return false;
}
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
//
// MEFFECT keyword
//
case typeKeyword.MEFFECT:
{
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
if (arglist.Length > 0)
{
string[] keywordargs = ParseString(arglist[0], 9, ",");
if (keywordargs.Length < 9)
{
status_str = "Missing args";
}
else
{
int effect;
int duration = 0;
int speed;
Point3D eloc1 = new Point3D(0, 0, 0);
Point3D eloc2 = new Point3D(0, 0, 0);
Map emap = Map.Internal;
// syntax is MEFFECT,itemid,speed,x,y,z,x2,y2,z2
// try to get the effect argument
if(!int.TryParse(keywordargs[1], out effect))
{
status_str = "Improper effect number format";
effect=-1;
}
if(!int.TryParse(keywordargs[2], out speed))
{
status_str = "Improper effect speed format";
speed=1;
}
int x=0,y=0,z=0;
if(!int.TryParse(keywordargs[3], out x) || !int.TryParse(keywordargs[4], out y) || !int.TryParse(keywordargs[5], out z))
status_str = "Improper effect location format";
eloc1 = new Point3D(x, y, z);
if(!int.TryParse(keywordargs[6], out x) || !int.TryParse(keywordargs[7], out y) || !int.TryParse(keywordargs[8], out z))
status_str = "Improper effect location format";
eloc2 = new Point3D(x, y, z);
if (effect >= 0 && emap != Map.Internal)
{
Effects.SendPacket(eloc1, emap, new HuedEffect(EffectType.Moving, -1, -1, effect, eloc1, eloc2, speed, duration, false, false, 0, 0));
}
}
if (status_str != null)
{
return false;
}
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.EFFECT:
{
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
if (spawner == null || spawner.Deleted) return false;
if (arglist.Length > 0)
{
string[] keywordargs = ParseString(arglist[0], 6, ",");
int effect = -1;
int duration = 1;
// syntax is EFFECT,itemid,duration[,x,y,z] or EFFECT,itemid,duration[,trigmob]
// try to get the effect argument
// some interesting effects are explosion(14013,15), sparkle(14155,15), explosion2(14000,13)
if (keywordargs.Length < 3)
{
status_str = "Missing effect number and duration";
}
else
{
if(!int.TryParse(keywordargs[1], out effect))
{
status_str = "Improper effect number format";
effect=-1;
}
if(!int.TryParse(keywordargs[2], out duration))
{
status_str = "Improper effect duration format";
duration=1;
}
}
// by default just use the spawner location
Point3D eloc = spawner.Location;
Map emap = spawner.Map;
if (keywordargs.Length > 3)
{
// is this applied to the trig mob or to a location?
if (keywordargs.Length > 5)
{
int x, y, z;
if(!int.TryParse(keywordargs[3], out x) || !int.TryParse(keywordargs[4], out y) || !int.TryParse(keywordargs[5], out z))
{
status_str = "Improper effect location format";
x=spawner.Location.X;
y=spawner.Location.Y;
z=spawner.Location.Z;
}
eloc = new Point3D(x, y, z);
}
}
if (status_str != null)
{
return false;
}
if (effect >= 0)
{
Effects.SendLocationEffect(eloc, emap, effect, duration);
}
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.POISON:
{
// the syntax is POISON,name,range
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
if (arglist.Length > 0)
{
ApplyPoisonToPlayers(arglist[0], triggermob, invoker, out status_str);
if (status_str != null)
{
return false;
}
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.DAMAGE:
{
// the syntax is DAMAGE,damage,phys,fire,cold,pois,energy[,range][,playeronly]
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
if (arglist.Length > 0)
{
ApplyDamageToPlayers(arglist[0], triggermob, invoker, out status_str);
if (status_str != null)
{
return false;
}
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.RESURRECT:
{
// the syntax is RESURRECT[,range][,PETS]
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
if (arglist.Length > 0)
{
ResurrectPlayers(arglist[0], triggermob, invoker, out status_str);
if (status_str != null)
{
return false;
}
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.CAST:
{
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
// Syntax is CAST,spellnumber[,arg] or CAST,spellname[,arg]
string[] keywordargs = ParseString(arglist[0], 3, ",");
int spellnumber = 0;
bool hasnumber = true;
// try it as spellnumber
if (keywordargs.Length > 1)
{
hasnumber=int.TryParse(keywordargs[1], out spellnumber);
}
else
{
status_str = "invalid CAST specification";
// note that returning true means that Spawn will assume that it worked and will not try to recast
return true;
}
// call this with the 3 argument version that includes the bodytype arg
int keywordarg2 = 0;
if (keywordargs.Length > 2)
{
int.TryParse(keywordargs[2], out keywordarg2);
}
Spell spell = null;
// the trigger mob will cast the spells
Mobile caster = triggermob;
if (caster == null)
{
// note that returning true means that Spawn will assume that it worked and will not try to recast
return true;
}
// make the placeholder wand to avoid reagent and mana use
BaseWand cwand = new ClumsyWand();
cwand.Parent = caster;
if (hasnumber)
{
spell = SpellRegistry.NewSpell(spellnumber, caster, cwand);
}
else
{
spell = SpellRegistry.NewSpell(keywordargs[1], caster, cwand);
}
if (spell != null)
{
bool casterror = false;
try
{
// deal with the 3 types of spells, mob targeted, location targeted, and self targeted
// dont go through all of the warm up stuff, get right to the casting
spell.State = SpellState.Sequencing;
Type spelltype = spell.GetType();
// deal with any special cases here
if (spelltype == typeof(Server.Spells.Seventh.PolymorphSpell))
{
if (keywordarg2 == 0)
{
// this is invalid so dont cast
throw (new ArgumentNullException());
}
object[] polyargs = new object[3];
polyargs[0] = caster;
polyargs[1] = cwand;
polyargs[2] = keywordarg2;
spell = (Spell)Activator.CreateInstance(spelltype, polyargs);
if (spell == null)
{
throw (new ArgumentNullException());
}
spell.State = SpellState.Sequencing;
}
MethodInfo spelltargetmethod = null;
// get the targeting method from the spell
// note, the precedence is important as the target call should override oncast if it is present
if (spelltype != null && (spelltargetmethod = spelltype.GetMethod("Target")) != null)
{
}
// if it doesnt have it then check for self targeted types
else if (spelltype != null && (spelltargetmethod = spelltype.GetMethod("OnCast")) != null)
{
}
else
{
throw (new ArgumentNullException());
}
// Get the parameters for the target method.
ParameterInfo[] spelltargetparms = spelltargetmethod.GetParameters();
// target will have one parm
// selftarg will have none
object[] targetargs = null;
// check the parameters
if (spelltargetparms != null && spelltargetparms.Length > 0)
{
if (spelltargetparms[0].ParameterType == typeof(Server.Mobile))
{
// set the target parameter
targetargs = new object[1];
targetargs[0] = triggermob;
}
else if (spelltargetparms[0].ParameterType == typeof(Server.IPoint3D))
{
// set the target parameter
targetargs = new object[1];
// pick a random point around the caster
int range = keywordarg2;
if (range == 0) range = 1;
int randx = Utility.RandomMinMax(-range, range);
int randy = Utility.RandomMinMax(-range, range);
if (randx == 0 && randy == 0) randx = 1;
targetargs[0] = new Point3D(triggermob.Location.X + randx,
triggermob.Location.Y + randy,
triggermob.Location.Z);
}
else
{
// dont handle any other types of args
throw (new ArgumentNullException());
}
}
// set the spell on the caster
caster.Spell = spell;
// invoke the spell method with the appropriate args
spelltargetmethod.Invoke(spell, targetargs);
// get rid of the placeholder wand
if (cwand != null && !cwand.Deleted)
cwand.Delete();
}
catch
{
status_str = "bad spell call : " + spell.Name;
casterror = true;
// get rid of the placeholder wand
if (cwand != null && !cwand.Deleted)
cwand.Delete();
}
if (casterror) return true;
}
else
{
status_str = "spell invalid or disabled : " + keywordargs[1];
//return true;
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
// note that returning true means that Spawn assume that it worked and will not try to recast
break;
}
case typeKeyword.BCAST:
{
// syntax is BCAST[,hue][,font]/message
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
int hue = 0x482;
int font = -1;
if (arglist.Length > 0)
{
string[] keywordargs = ParseString(arglist[0], 3, ",");
if (keywordargs.Length > 1)
{
if(!int.TryParse(keywordargs[1], out hue))
{
status_str = "invalid hue arg to BCAST";
hue = 0x482;
}
}
if (keywordargs.Length > 2)
{
if(!int.TryParse(keywordargs[2], out font))
{
status_str = "invalid font arg to BCAST";
font=-1;
}
}
}
if (arglist.Length > 1)
{
string msg = arglist[1];
if (arglist[1] != null && arglist[1].Length > 0 && arglist[1][0] == '@')
{
arglist = ParseSlashArgs(substitutedtypeName, 2);
msg = arglist[1].Substring(1);
}
if (font >= 0)
{
// broadcast an ascii message to all players
BroadcastAsciiMessage(AccessLevel.Player, hue, font, msg);
}
else
{
// standard unicode message format
CommandHandlers.BroadcastMessage(AccessLevel.Player, hue, msg);
}
}
else
{
status_str = "missing msg arg in BCAST";
return false;
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
case typeKeyword.BSOUND:
{
// syntax is BSOUND,soundid
string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
int soundid = -1;
if (arglist.Length > 0)
{
string[] keywordargs = ParseString(arglist[0], 2, ",");
if (keywordargs.Length > 1)
{
if(!int.TryParse(keywordargs[1], out soundid))
{
status_str = "invalid soundid arg to BSOUND";
soundid=-1;
}
}
if (soundid >= 0)
{
// broadcast a sound to all players
BroadcastSound(AccessLevel.Player, soundid);
}
}
TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
break;
}
default:
{
status_str = "unrecognized keyword";
// should never get here
break;
}
}
// indicate successful keyword spawn
return true;
}
#endregion
#region itemKeyword
else
if (IsSpecialItemKeyword(typeName))
{
// these are special keyword item drops
string[] arglist = ParseSlashArgs(substitutedtypeName, 2);
string itemtypestr = arglist[0];
string baseitemtype = typeName;
// itemtypestr will have the form keyword[,x[,y]]
string[] itemkeywordargs = ParseString(itemtypestr, 6, ",");
itemKeyword kw = itemKeywordHash[typeName];
// deal with the special keywords
switch (kw)
{
case itemKeyword.ARMOR:
{
// syntax is ARMOR,min,max
//get the min,max
if (itemkeywordargs.Length == 3)
{
int min = 0;
int max = 0;
if(!int.TryParse(itemkeywordargs[1], out min) || !int.TryParse(itemkeywordargs[2], out max))
{
status_str = "Invalid ARMOR args : " + itemtypestr;
return false;
}
Item item = MagicArmor(min, max, false, false);
if (item != null)
{
AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
}
else
{
status_str = "ARMOR takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.WEAPON:
{
// syntax is WEAPON,min,max
//get the min,max
if (itemkeywordargs.Length == 3)
{
int min = 0;
int max = 0;
if(!int.TryParse(itemkeywordargs[1], out min) || !int.TryParse(itemkeywordargs[2], out max))
{
status_str = "Invalid WEAPON args : " + itemtypestr;
return false;
}
Item item = MagicWeapon(min, max, false);
if (item != null)
{
AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
}
else
{
status_str = "WEAPON takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.JARMOR:
{
// syntax is JARMOR,min,max
//get the min,max
if (itemkeywordargs.Length == 3)
{
int min = 0;
int max = 0;
if(!int.TryParse(itemkeywordargs[1], out min) || !int.TryParse(itemkeywordargs[2], out max))
{
status_str = "Invalid JARMOR args : " + itemtypestr;
return false;
}
Item item = MagicArmor(min, max, true, true);
if (item != null)
{
AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
}
else
{
status_str = "JARMOR takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.JWEAPON:
{
// syntax is JWEAPON,min,max
//get the min,max
if (itemkeywordargs.Length == 3)
{
int min = 0;
int max = 0;
if(!int.TryParse(itemkeywordargs[1], out min) || !int.TryParse(itemkeywordargs[2], out max))
{
status_str = "Invalid JWEAPON args : " + itemtypestr;
return false;
}
Item item = MagicWeapon(min, max, true);
if (item != null)
{
AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
}
else
{
status_str = "JWEAPON takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.SARMOR:
{
// syntax is SARMOR,min,max
//get the min,max
if (itemkeywordargs.Length == 3)
{
int min = 0;
int max = 0;
if(!int.TryParse(itemkeywordargs[1], out min) || !int.TryParse(itemkeywordargs[2], out max))
{
status_str = "Invalid SARMOR args : " + itemtypestr;
return false;
}
Item item = MagicArmor(min, max, false, true);
if (item != null)
{
AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
}
else
{
status_str = "SARMOR takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.SHIELD:
{
// syntax is SHIELD,min,max
//get the min,max
if (itemkeywordargs.Length == 3)
{
int min = 0;
int max = 0;
if(!int.TryParse(itemkeywordargs[1], out min) || !int.TryParse(itemkeywordargs[2], out max))
{
status_str = "Invalid SHIELD args : " + itemtypestr;
return false;
}
Item item = MagicShield(min, max);
if (item != null)
{
AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
}
else
{
status_str = "SHIELD takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.JEWELRY:
{
// syntax is JEWELRY,min,max
//get the min,max
if (itemkeywordargs.Length == 3)
{
int min = 0;
int max = 0;
if(!int.TryParse(itemkeywordargs[1], out min) || !int.TryParse(itemkeywordargs[2], out max))
{
status_str = "Invalid JEWELRY args : " + itemtypestr;
return false;
}
Item item = MagicJewelry(min, max);
if (item != null)
{
AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
}
else
{
status_str = "JEWELRY takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.ITEM:
{
// syntax is ITEM,serial
if (itemkeywordargs.Length == 2)
{
int serial = -1;
bool converterror = false;
try { serial = Convert.ToInt32(itemkeywordargs[1], 16); }
catch { status_str = "Invalid ITEM args : " + itemtypestr; converterror = true; }
if (converterror) return false;
Item item = World.FindItem(serial);
if (item != null)
{
AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
}
else
{
status_str = "ITEM takes 1 arg : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.SCROLL:
{
// syntax is SCROLL,mincircle,maxcircle
//get the min,max
if (itemkeywordargs.Length == 3)
{
int minCircle = 0;
int maxCircle = 0;
if(!int.TryParse(itemkeywordargs[1], out minCircle) || !int.TryParse(itemkeywordargs[2], out maxCircle))
{
status_str = "Invalid SCROLL args : " + itemtypestr;
return false;
}
int circle = Utility.RandomMinMax(minCircle, maxCircle);
int min = (circle - 1) * 8;
Item item = Loot.RandomScroll(min, min + 7, SpellbookType.Regular);
if (item != null)
{
AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
}
else
{
status_str = "SCROLL takes 2 args : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.LOOT:
{
// syntax is LOOT,methodname
if (itemkeywordargs.Length == 2)
{
Item item = null;
// look up the method
Type ltype = typeof(Loot);
if (ltype != null)
{
MethodInfo method = null;
try
{
// get the zero arg method with the specified name
method = ltype.GetMethod(itemkeywordargs[1], new Type[0]);
}
catch { }
if (method != null && method.IsStatic)
{
ParameterInfo[] pinfo = method.GetParameters();
// check to make sure the method for this object has the right args
if (pinfo.Length == 0)
{
// method must be public static with no arguments returning an Item class object
try
{
item = method.Invoke(null, null) as Item;
}
catch { }
}
else
{
status_str = "LOOT method must be zero arg : " + itemtypestr;
return false;
}
}
else
{
status_str = "LOOT no valid method found : " + itemtypestr;
return false;
}
}
if (item != null)
{
AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
}
else
{
status_str = "LOOT takes 1 arg : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.POTION:
{
// syntax is POTION
Item item = Loot.RandomPotion();
if (item != null)
{
AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
break;
}
case itemKeyword.TAKEN:
{
// syntax is TAKEN
// find the XmlSaveItem attachment
Item item = GetTaken(invoker);
if (item != null)
{
AddSpawnItem(spawner, invoker, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
break;
}
case itemKeyword.GIVEN:
{
// syntax is GIVEN
// find the XmlSaveItem attachment
Item item = GetGiven(invoker);
if (item != null)
{
AddSpawnItem(spawner, invoker, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
break;
}
case itemKeyword.NECROSCROLL:
{
// syntax is NECROSCROLL,index
if (itemkeywordargs.Length == 2)
{
int necroindex = 0;
if(!int.TryParse(itemkeywordargs[1], out necroindex))
{
status_str = "Invalid NECROSCROLL args : " + itemtypestr;
return false;
}
Item item = Loot.Construct(Loot.NecromancyScrollTypes, necroindex);
if (item != null)
{
AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
}
else
{
status_str = "NECROSCROLL takes 1 arg : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.MULTIADDON:
{
// syntax is MULTIADDON,filename
if (itemkeywordargs.Length == 2)
{
string filename = itemkeywordargs[1];
// read in the multi.txt file
Item item = XmlSpawnerAddon.ReadMultiFile(filename, out status_str);
if (item != null)
{
AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
}
else
{
status_str = "MULTIADDON takes 1 arg : " + itemtypestr;
return false;
}
break;
}
case itemKeyword.RANDOMITEM:
{
// syntax is RANDOMITEM,[basebudget,][prefix,][suffix,][rawluck,][artifact]
int basebudget = 0;
ReforgedPrefix prefix = ReforgedPrefix.None;
ReforgedSuffix suffix = ReforgedSuffix.None;
int killersluck = 0;
bool converterror = false;
if (itemkeywordargs.Length > 1)
{
try { basebudget = int.Parse(itemkeywordargs[1]); }
catch { status_str = "Invalid RANDOMITEM args : " + itemtypestr; converterror = true; }
}
else
basebudget = Utility.RandomMinMax(100, 700);
if (converterror) return false;
if (itemkeywordargs.Length > 2)
{
try
{
prefix = (ReforgedPrefix)Enum.Parse(typeof(ReforgedPrefix), itemkeywordargs[2], true);
}
catch { status_str = "Invalid RANDOMITEM args : " + itemtypestr; converterror = true; }
}
if (converterror) return false;
if (itemkeywordargs.Length > 3)
{
try
{
suffix = (ReforgedSuffix)Enum.Parse(typeof(ReforgedSuffix), itemkeywordargs[3], true);
}
catch { status_str = "Invalid RANDOMITEM args : " + itemtypestr; converterror = true; }
}
if (converterror) return false;
int rawluck = triggermob != null ? triggermob is PlayerMobile ? ((PlayerMobile)triggermob).RealLuck : triggermob.Luck : 0;
bool artifact = false;
if (rawluck == 0 && itemkeywordargs.Length > 4)
{
try { rawluck = int.Parse(itemkeywordargs[4]); }
catch { status_str = "Invalid RANDOMITEM args : " + itemtypestr; converterror = true; }
}
if (rawluck > 0)
{
killersluck = LootPack.GetLuckChance(rawluck);
}
if (itemkeywordargs.Length > 5)
{
string arty = itemkeywordargs[5];
if (arty != null && arty.ToLower() == "true")
{
artifact = true;
}
}
if (basebudget < 100) basebudget = 100;
Item root = spawner;
if (spawner != null && spawner.RootParent is Item)
root = spawner.RootParent as Item;
Item item = Loot.RandomArmorOrShieldOrWeaponOrJewelry(LootPackEntry.IsInTokuno(root), LootPackEntry.IsMondain(root), LootPackEntry.IsStygian(root));
if (item != null)
{
if (artifact)
{
RunicReforging.GenerateRandomArtifactItem(item, rawluck, basebudget, prefix, suffix);
}
else
{
RunicReforging.GenerateRandomItem(item, triggermob, basebudget, killersluck, prefix, suffix);
}
AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
}
break;
}
default:
{
status_str = "unrecognized keyword";
// should never get here
break;
}
}
return true;
}
#endregion
else
{
// should never get here
status_str = "unrecognized keyword";
return false;
}
}
#endregion
#region Specials by Fwiffo
public static List<Item> GetItems(Region r)
{
List<Item> list = new List<Item>();
if(r==null) return list;
Sector[] sectors = r.Sectors;
if ( sectors != null )
{
for ( int i = 0; i < sectors.Length; i++ )
{
Sector sector = sectors[i];
foreach ( Item item in sector.Items )
{
if ( Region.Find( item.Location, item.Map).IsPartOf(r) )
list.Add( item );
}
}
}
return list;
}
/// <summary>
/// Converts the string representation of the name value of one or more enumerated constants to an equivalent enumerated object. A parameter specifies whether the operation is case-sensitive (default: false). The return value indicates whether the conversion succeeded.
/// </summary>
/// <param name="tocheck"> The string representation of the enumeration name or underlying value to convert.</param>
/// <param name="result">result: if the method returns true, it's a TEnum whose value is represented by value. Otherwise uninitialized parameter.</param>
/// <returns> true if the value parameter was converted successfully; otherwise, false. </returns>
/// <exception cref="ArgumentException"> TEnum is not an enumeration type. </exception>
public static bool TryParse<TEnum>(string tocheck, out TEnum result) where TEnum : struct, IConvertible
{
return TryParse(tocheck, false, out result);
}
/// <summary>
/// Converts the string representation of the name value of one or more enumerated constants to an equivalent enumerated object. A parameter specifies whether the operation is case-sensitive. The return value indicates whether the conversion succeeded.
/// </summary>
/// <param name="tocheck"> The string representation of the enumeration name or underlying value to convert.</param>
/// <param name="ignorecase"> If this parameter is set to true it will ignore case of string tocheck, otherwise it will check case. </param>
/// <param name="result">result: if the method returns true, it's a TEnum whose value is represented by value. Otherwise uninitialized parameter.</param>
/// <returns> true if the value parameter was converted successfully; otherwise, false. </returns>
/// <exception cref="ArgumentException"> TEnum is not an enumeration type. </exception>
public static bool TryParse<TEnum>(string tocheck, bool ignorecase, out TEnum result) where TEnum : struct, IConvertible
{
bool boolean = (tocheck == null ? false : Enum.IsDefined(typeof(TEnum), tocheck));
result = (boolean ? (TEnum)Enum.Parse(typeof(TEnum), tocheck) : default(TEnum));
return boolean;
}
#endregion
}
}