11414 lines
318 KiB
C#
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
|
|
}
|
|
} |