Exemple #1
0
        // These functions are borrowed heavily from ArteGordon's BaseXmlSpawner class

        // set property values with support for nested attributes
        public static void SetPropertyValue(TriggerObject trigObj, object o, string name, object value)
        {
            if (o == null)
            {
                throw new UberScriptException("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
            List <string> arglist = PropertyGetters.PropSplitter(name);

            string propname = arglist[0];

            if (propname.Length == 0)
            {
                throw new UberScriptException("Empty string property!");
            }

            // Check whether they are trying to set an xml attachment through the
            // shortcut e.g. TRIGMOB().xmlints.score = TRIGMOB().xmlints.score + 1

            if (arglist.Count > 1 && (propname[0] == 'x' || propname[0] == 'X'))
            {
                // NEED TO HANDLE SETTING PROPERTIES ON THE ATTACHMENTS!
                string lowerPropName = propname.ToLower();
                if (lowerPropName == "xmlints")
                {
                    IEntity entity = o as IEntity;
                    if (entity == null)
                    {
                        throw new UberScriptException("Can't set xmlints on anything but Mobile or Item");
                    }
                    // check for existing xmlValue attachment or create a new one
                    XmlValue xmlValue = XmlAttach.GetValueAttachment(entity, arglist[1]);
                    if (xmlValue == null)
                    {
                        // arglist should only have [xmlints, name], nothing more
                        if (arglist.Count > 2)
                        {
                            throw new UberScriptException("Attempted to set property on a not-yet-existant attachment!:" + name);
                        }
                        xmlValue = new XmlValue(arglist[1], (int)value);
                        XmlAttach.AttachTo(null, entity, xmlValue);
                    }
                    else if (arglist.Count == 2)
                    {
                        if (value == null)
                        {
                            xmlValue.Delete();
                        }
                        else
                        {
                            xmlValue.Value = (int)value;
                        }
                    }
                    else if (arglist.Count > 2)
                    {
                        // could be setting a property on an existing XmlAttachment!
                        // e.g. xmlints.test.expiration = 0:0:1
                        SetPropertyValue(trigObj, xmlValue, arglist[2], value);
                    }
                    return;
                }
                else if (lowerPropName == "xmlstrings")
                {
                    IEntity entity = o as IEntity;
                    if (entity == null)
                    {
                        throw new UberScriptException("Can't set xmlstrings on anything but Mobile or Item");
                    }
                    XmlLocalVariable xmlLocalVariable = XmlAttach.GetStringAttachment(entity, arglist[1]);
                    if (xmlLocalVariable == null)
                    {
                        // arglist should only have [xmlints, name], nothing more
                        if (arglist.Count > 2)
                        {
                            throw new UberScriptException("Attempted to set property on a not-yet-existant attachment!:" + name);
                        }
                        xmlLocalVariable = new XmlLocalVariable(arglist[1], (string)value);
                        XmlAttach.AttachTo(null, entity, xmlLocalVariable);
                    }
                    else if (arglist.Count == 2)
                    {
                        if (value == null)
                        {
                            xmlLocalVariable.Delete();
                        }
                        else
                        {
                            xmlLocalVariable.Data = (string)value;
                        }
                    }
                    else if (arglist.Count > 2)
                    {
                        // could be setting a property on an existing XmlAttachment!
                        // e.g. xmlints.test.expiration = 0:0:1
                        SetPropertyValue(trigObj, xmlLocalVariable, arglist[2], value);
                    }
                    return;
                }
                else if (lowerPropName == "xmldoubles")
                {
                    IEntity entity = o as IEntity;
                    if (entity == null)
                    {
                        throw new UberScriptException("Can't set xmldoubles on anything but Mobile or Item");
                    }
                    XmlDouble xmlDouble = XmlAttach.GetDoubleAttachment(entity, arglist[1]);
                    if (xmlDouble == null)
                    {
                        // arglist should only have [xmlints, name], nothing more
                        if (arglist.Count > 2)
                        {
                            throw new UberScriptException("Attempted to set property on a not-yet-existant attachment!:" + name);
                        }
                        xmlDouble = new XmlDouble(arglist[1], (double)value);
                        XmlAttach.AttachTo(null, entity, xmlDouble);
                    }
                    else if (arglist.Count == 2)
                    {
                        if (value == null)
                        {
                            xmlDouble.Delete();
                        }
                        else
                        {
                            xmlDouble.Value = (double)value;
                        }
                    }
                    else if (arglist.Count > 2)
                    {
                        // could be setting a property on an existing XmlAttachment!
                        // e.g. xmlints.test.expiration = 0:0:1
                        SetPropertyValue(trigObj, xmlDouble, arglist[2], value);
                    }
                    return;
                }
                else if (lowerPropName == "xmlobjs")
                {
                    IEntity entity = o as IEntity;
                    if (entity == null)
                    {
                        throw new UberScriptException("Can't set xmlobjs on anything but Mobile or Item");
                    }
                    XmlObject xmlObject = XmlAttach.GetObjectAttachment(entity, arglist[1]);
                    if (xmlObject == null)
                    {
                        // arglist should only have [xmlints, name], nothing more
                        if (arglist.Count > 2)
                        {
                            throw new UberScriptException("Attempted to set property on a not-yet-existant attachment!:" + name);
                        }
                        xmlObject = new XmlObject(arglist[1], value);
                        XmlAttach.AttachTo(null, entity, xmlObject);
                    }
                    else if (arglist.Count == 2)
                    {
                        if (value == null)
                        {
                            xmlObject.Delete();
                        }
                        else
                        {
                            xmlObject.Value = value;
                        }
                    }
                    else if (arglist.Count > 2)
                    {
                        // XmlObject only contains a few properties that
                        // can be accessed through statements like THIS().xmlobjs.test._____
                        // since there is a potential conflict between the developer wanting access
                        // to the properties on the object contained in the XmlObject.Value (most likely)
                        // or the properties on the XmlObject itself (far less likely)
                        string testPropName = arglist[2].ToLower();
                        // to access properties on the xmlobject itself (e.g. expiration), one must do this:
                        //  THIS().xmlobjs.test.xmlobject.expiration
                        if (testPropName == "xmlobject")
                        {
                            if (arglist.Count < 4)
                            {
                                throw new UberScriptException("Can't set an xmlobject directly, use ATTACH function!");
                            }
                            else
                            {
                                string propLookup = arglist[3]; // add this first so later additions all prepended with '.'
                                for (int i = 4; i < arglist.Count; i++)
                                {
                                    propLookup += "." + arglist[i];
                                }
                                SetPropertyValue(trigObj, xmlObject, propLookup, value);
                            }
                        }
                        else
                        {
                            string propLookup = arglist[2]; // add this first so later additions all prepended with '.'
                            for (int i = 3; i < arglist.Count; i++)
                            {
                                propLookup += "." + arglist[i];
                            }
                            SetPropertyValue(trigObj, xmlObject.Value, propLookup, value);
                        }
                    }

                    //else if (arglist.Count > 2)
                    //{
                    // could be setting a property on an existing XmlAttachment!
                    // e.g. xmlints.test.expiration = 0:0:1
                    //    SetPropertyValue(trigObject, xmlObject, arglist[2], value);
                    //}
                    return;
                }
            }

            /*
             * 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;
             *
             *  ArrayList 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";
             *  }
             *  bool found = true;
             *  try
             *  {
             *      SkillName skillname = (SkillName)Enum.Parse(typeof(SkillName), keywordargs[1], true);
             *      if (o is Mobile)
             *      {
             *
             *          Skill skill = ((Mobile)o).Skills[skillname];
             *
             *          skill.Base = double.Parse(value);
             *
             *          return "Property has been set.";
             *      }
             *      else
             *          return "Object is not mobile";
             *  }
             *  catch { found = false; }
             *
             *  if (!found)
             *      return "Invalid SKILL reference.";
             * }
             * else if (keywordargs[0] == "STEALABLE")
             * {
             *
             *  bool found = true;
             *  try
             *  {
             *      if (o is Item)
             *      {
             *
             *          ItemFlags.SetStealable(o as Item, bool.Parse(value));
             *
             *          return "Property has been set.";
             *      }
             *      else
             *          return "Object is not an item";
             *  }
             *  catch { found = false; }
             *
             *  if (!found)
             *      return "Invalid Stealable assignment.";
             * }
             * */

            // 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)
                {
                    try
                    {
                        index = int.Parse(arrayvalue[0]);
                    }
                    catch
                    {
                        try
                        {
                            index = (int)(new MathTree(null, arrayvalue[0])).Calculate(trigObj);
                        }
                        catch
                        {
                            throw new UberScriptException("Could not get int array value from: " + arrayvalue[0] + " for prop of " + name + " on object " + o);
                        }
                    }
                }
            }
            PropertyInfo propInfoToSet     = null;
            string       lowerCasePropName = propname.ToLower();

            // optimization to find propertyInfo without looping through
            if (o is BaseCreature)
            {
                if (BaseCreatureProperties.ContainsKey(lowerCasePropName))
                {
                    propInfoToSet = BaseCreatureProperties[lowerCasePropName];
                }
            }
            else if (o is PlayerMobile)
            {
                if (PlayerMobileProperties.ContainsKey(lowerCasePropName))
                {
                    propInfoToSet = PlayerMobileProperties[lowerCasePropName];
                }
            }
            else if (o is Item)
            {
                if (ItemProperties.ContainsKey(lowerCasePropName))
                {
                    propInfoToSet = ItemProperties[lowerCasePropName];
                }
            }
            // is a nested property with attributes so first get the property
            if (propInfoToSet == null)
            {
                foreach (PropertyInfo p in props)
                {
                    if (Insensitive.Equals(p.Name, propname))
                    {
                        propInfoToSet = p;
                        break;
                    }
                }
            }
            if (propInfoToSet != null)
            {
                //if (IsProtected(type, propname))
                //    return "Property is protected.";

                if (arglist.Count > 1)
                {
                    //ptype = propInfoToSet.PropertyType;
                    po = propInfoToSet.GetValue(o, null);
                    // now set the nested attribute using the new property list
                    string propLookup = arglist[1];
                    for (int i = 2; i < arglist.Count; i++)
                    {
                        propLookup += "." + arglist[i];
                    }
                    SetPropertyValue(trigObj, po, propLookup, value);
                    return;
                    // otherwise let it roll through and throw an exception
                }
                else // arglist.Count == 1
                {
                    //if (IsProtected(type, propname))
                    //    return "Property is protected.";
                    if (!propInfoToSet.CanWrite)
                    {
                        throw new UberScriptException("Property is read only.");
                    }

                    InternalSetValue(o, propInfoToSet, value, false, index);
                    return;
                }
            }

            throw new UberScriptException("Property " + name + " not found on " + o + ".");
        }
        public Object Execute(TriggerObject trigObject, bool tryReturnObject = false)
        {
            if (trigObject == null)
            {
                throw new UberScriptException("Execute: trigObject reference is null");
            }

            var args = new List <Object> {
                trigObject
            };

            // the args of the function are actually
            // stored in nodes--either function or argument... e.g.
            // EFFECT(14000,25, THIS().x, THIS().y, THIS().z)
            // has 2 argument nodes and 3 function nodes

            // each child of a FunctionNode is an argument represented by a MathTree
            foreach (UberNode child in Children)
            {
                if (!(child is MathTree))
                {
                    throw new UberScriptException(
                              String.Format("Execute: MathTree child expected at line {0}:\n{1}", LineNumber, OriginalString));
                }

                MathTree mathTree = child as MathTree;

                if (!mathTree.IsEmpty())
                {
                    args.Add(mathTree.Calculate(trigObject));
                }
            }

            Object obj;

            try
            {
                // FunctionNode scriptstring contains function name
                obj = UberScriptFunctions.Invoke(ScriptString, args.ToArray());
            }
            catch (Exception x)
            {
                throw new UberScriptException(
                          String.Format("Execute: an exception was thrown during invocation at line {0}:\n{1}", LineNumber, OriginalString),
                          x);
            }

            if (Property == null || tryReturnObject)
            {
                return(obj);
            }

            Type ptype;

            try
            {
                obj = PropertyGetters.GetObject(trigObject, obj, Property, out ptype);

                if (obj == null)
                {
                    return(null);                    // it's ok to be null here
                }
            }
            catch (Exception x)
            {
                throw new UberScriptException(
                          String.Format(
                              "Execute: value could not be set on function '{0}' output object at line {1}:\n{2}",
                              ScriptString,
                              LineNumber,
                              OriginalString),
                          x);
            }

            if (ptype == null)
            {
                throw new UberScriptException(
                          String.Format(
                              "Execute: property '{0}' does not exist on function '{1}' output object at line {2}:\n{3}",
                              Property,
                              ScriptString,
                              LineNumber,
                              OriginalString));
            }

            if (NegateOutput)
            {
                if (obj is sbyte)
                {
                    obj = -(sbyte)obj;
                }
                else if (obj is short)
                {
                    obj = -(short)obj;
                }
                else if (obj is int)
                {
                    obj = -(int)obj;
                }
                else if (obj is long)
                {
                    obj = -(long)obj;
                }
                else
                {
                    throw new UberScriptException(
                              String.Format(
                                  "Execute: output negation failed on function '{0}' output object type '{1}' at line {2}:\n{3}",
                                  ScriptString,
                                  obj.GetType(),
                                  LineNumber,
                                  OriginalString));
                }
            }

            return(obj);
        }
Exemple #3
0
        public Object Execute(TriggerObject trigObject, bool tryReturnObject = false)
        {
            List <Object> args = new List <Object>();

            args.Add(trigObject); // every function takes this as a parameter
            // the args of the function are actually
            // stored in nodes--either function or argument... e.g.
            // EFFECT(14000,25, THIS().x, THIS().y, THIS().z)
            // has 2 argument nodes and 3 function nodes

            // each child of a ListAccessNode is an argument represented by a MathTree
            foreach (UberNode child in Children)
            {
                if (child is MathTree)
                {
                    MathTree mathTree = child as MathTree;
                    if (!mathTree.IsEmpty())
                    {
                        args.Add(mathTree.Calculate(trigObject));
                    }

                    //Execute(trigObject, tryReturnObject = false));
                }
                else
                {
                    throw new UberScriptException("Line " + LineNumber + ": " + OriginalString + "\nListAccessNode had children other than MathTree... something is broken!");
                }
            }
            object[] reflectionArgs = new object[args.Count];
            int      count          = 0;

            foreach (Object arg in args)
            {
                reflectionArgs[count] = arg;
                count++;
            }
            Object outputObject;

            /*
             * if (ScriptString == "THIS") { outputObject = trigObject.This; }
             * else if (ScriptString == "TRIGMOB") { outputObject = trigObject.TrigMob; }
             * else if (ScriptString == "GIVENTOTHIS") { outputObject = trigObject.DroppedOnThis; }
             * else if (ScriptString == "GIVENBYTHIS") { outputObject = trigObject.DroppedOnThis; }
             * else if (ScriptString == "TARGETTEDBY") { outputObject = trigObject.TargettedBy; }
             * else if (ScriptString == "TARGETTED") { outputObject = trigObject.Targetted; }
             * else if (ScriptString == "DAMAGE") { outputObject = trigObject.Damage; }
             * else*/
            try
            {
                outputObject = UberScriptFunctions.Invoke(this.ScriptString, reflectionArgs); // ListAccessNode scriptstring contains function name
            }
            catch (Exception e)
            {
                throw new UberScriptException("Line " + LineNumber + ": " + OriginalString + "\nError invoking function:", e);
            }

            if (Property == null || tryReturnObject)
            {
                return(outputObject);
            }
            Type ptype;

            try
            {
                outputObject = PropertyGetters.GetObject(trigObject, outputObject, Property, out ptype);
                if (outputObject == null)
                {
                    return(null);                      // it's ok to be null here
                }
            }
            catch (Exception e)
            {
                throw new UberScriptException("Line " + LineNumber + ": " + OriginalString + "\nError setting value:", e);
            }
            if (ptype == null)
            {
                throw new UberScriptException("Line " + LineNumber + ": " + OriginalString + "\nListAccessNode function " + ScriptString + " output object did not have property: " + Property);
            }
            if (NegateOutput)
            {
                Type outputType = outputObject.GetType();
                if (outputType == typeof(SByte))
                {
                    outputObject = -((SByte)outputObject);
                }
                else if (outputType == typeof(Int16))
                {
                    outputObject = -((Int16)outputObject);
                }
                else if (outputType == typeof(Int32))
                {
                    outputObject = -((Int32)outputObject);
                }
                else if (outputType == typeof(Int64))
                {
                    outputObject = -((Int64)outputObject);
                }
                else
                {
                    throw new UberScriptException("Line " + LineNumber + ": " + OriginalString + "\nCould not negate output of " + this.ScriptString + " output object of type: " + outputType);
                }
            }
            return(outputObject);
        }
        public static object GetObject(TriggerObject trigObj, object o, string name, out Type ptype) // used for all comparisons
        {
            // ALL EXCEPTIONS CAUGHT OUTSIDE OF THIS FUNCTION (so that a useful error can be displayed)
            // trigobject used in case there are array indeces with a function [THIS().x]
            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 (Exception e)
            {
                throw new UberScriptException("GetProperties Error!", e);
            }

            // parse the strings of the form property.attribute into two parts
            // first get the property
            List <string> arglist  = PropSplitter(name);
            string        propname = arglist[0];

            if (propname.Length == 0)
            {
                throw new UberScriptException("Empty string property!");
            }
            if (arglist.Count > 1 && (propname[0] == 'x' || propname[0] == 'X'))
            {
                if (propname.ToLower() == "xmlints")
                {
                    IEntity entity = o as IEntity;
                    if (entity == null)
                    {
                        throw new UberScriptException("Can't set xmlints on anything but Mobile or Item");
                    }
                    // check for existing xmlValue attachment or create a new one
                    XmlValue xmlValue = XmlAttach.GetValueAttachment(o as IEntity, arglist[1]);
                    if (xmlValue == null)
                    {
                        return(null);      //throw new UberScriptException("Could not find XmlValue named " + name + " on " + o);
                    }
                    if (arglist.Count > 2) // must be trying to get a property on the xmlValue (e.g. xmlints.test.expiration)
                    {
                        return(GetObject(trigObj, xmlValue, arglist[2], out ptype));
                    }
                    ptype = typeof(int);
                    return(xmlValue.Value);
                }
                else if (propname.ToLower() == "xmlstrings")
                {
                    IEntity entity = o as IEntity;
                    if (entity == null)
                    {
                        throw new UberScriptException("Can't set xmlstrings on anything but Mobile or Item");
                    }
                    XmlLocalVariable xmlLocalVariable = XmlAttach.GetStringAttachment(o as IEntity, arglist[1]);
                    if (xmlLocalVariable == null)
                    {
                        return(null);      // throw new UberScriptException("Could not find XmlLocalVariable named " + name + " on " + o);
                    }
                    if (arglist.Count > 2) // must be trying to get a property on the xmlValue (e.g. xmlints.test.expiration)
                    {
                        return(GetObject(trigObj, xmlLocalVariable, arglist[2], out ptype));
                    }
                    ptype = typeof(string);
                    return(xmlLocalVariable.Data);
                }
                else if (propname.ToLower() == "xmldoubles")
                {
                    IEntity entity = o as IEntity;
                    if (entity == null)
                    {
                        throw new UberScriptException("Can't set xmldoubles on anything but Mobile or Item");
                    }
                    XmlDouble xmlDouble = XmlAttach.GetDoubleAttachment(entity, arglist[1]);
                    if (xmlDouble == null)
                    {
                        return(null);      //  throw new UberScriptException("Could not find XmlDouble named " + name + " on " + o);
                    }
                    if (arglist.Count > 2) // must be trying to get a property on the xmlValue (e.g. xmlints.test.expiration)
                    {
                        return(GetObject(trigObj, xmlDouble, arglist[2], out ptype));
                    }
                    ptype = typeof(double);
                    return(xmlDouble.Value);
                }
                else if (propname.ToLower() == "xmlobjs")
                {
                    IEntity entity = o as IEntity;
                    if (entity == null)
                    {
                        throw new UberScriptException("Can't set xmlobjs on anything but Mobile or Item");
                    }
                    // since the object might be a list of some kind, need to check for the [] indexing first
                    string objName          = arglist[1];
                    int    openBracketIndex = objName.IndexOf('[');
                    int    listindex        = -1; // for lists / arrays
                    if (openBracketIndex > 0)
                    {
                        int closingBracketIndex = objName.IndexOf(']');
                        if (closingBracketIndex < openBracketIndex + 1)
                        {
                            throw new UberScriptException("xmlobjs." + objName + " [] indexing error: must have at least 1 character between the []");
                        }

                        listindex = (int)(new MathTree(null, objName.Substring(openBracketIndex + 1, closingBracketIndex - openBracketIndex - 1))).Calculate(trigObj);
                        objName   = objName.Substring(0, openBracketIndex);
                    }

                    XmlObject xmlObject = XmlAttach.GetObjectAttachment(entity, objName);
                    if (xmlObject == null)
                    {
                        return(null);                   // throw new UberScriptException("Could not find XmlObject named " + name + " on " + o);
                    }
                    //if (arglist.Count > 2) // must be trying to get a property on the xmlValue (e.g. xmlints.test.expiration)
                    //    return GetObject(trigObject, xmlObject, arglist[2], out ptype);


                    //=====
                    if (arglist.Count > 2)
                    {
                        // XmlObject only contains a few properties that
                        // can be accessed through statements like THIS().xmlobjs.test._____
                        // since there is a potential conflict between the developer wanting access
                        // to the properties on the object contained in the XmlObject.Value (most likely)
                        // or the properties on the XmlObject itself (far less likely)
                        string testPropName = arglist[2].ToLower();
                        // to access properties on the xmlobject itself (e.g. expiration), one must do this:
                        //  THIS().xmlobjs.test.xmlobject.expiration
                        if (testPropName == "xmlobject")
                        {
                            if (arglist.Count < 4)
                            {
                                return(xmlObject);
                            }

                            string propLookup = arglist[3]; // add this first so later additions all prepended with '.'
                            for (int i = 4; i < arglist.Count; i++)
                            {
                                propLookup += "." + arglist[i];
                            }
                            return(PropertyGetters.GetObject(trigObj, xmlObject, propLookup, out ptype));
                        }
                        else
                        {
                            if (xmlObject.Value == null)
                            {
                                return(null);
                            }
                            string propLookup = arglist[2]; // add this first so later additions all prepended with '.'
                            for (int i = 3; i < arglist.Count; i++)
                            {
                                propLookup += "." + arglist[i];
                            }

                            if (listindex >= 0)
                            {
                                ptype = xmlObject.Value.GetType();
                                if (ptype.GetInterface("IList") != null)
                                {
                                    try
                                    {
                                        return(PropertyGetters.GetObject(trigObj, ((IList)xmlObject.Value)[listindex], propLookup, out ptype));
                                        //return ((IList)xmlObject.Value)[listindex];
                                    }
                                    catch (Exception e)
                                    {
                                        throw new UberScriptException("Get Array value error!", e);
                                    }
                                }
                                else
                                {
                                    throw new UberScriptException("xmlobj." + objName + " was indexed with [] indexer, but did not contain a list!");
                                }
                            }

                            return(PropertyGetters.GetObject(trigObj, xmlObject.Value, propLookup, out ptype));
                        }
                    }
                    else if (listindex >= 0)
                    {
                        // no properties afterward but has a list index (e.g. xmlobjs.spawnedPlatforms[0])
                        ptype = xmlObject.Value.GetType();
                        if (ptype.GetInterface("IList") != null)
                        {
                            try
                            {
                                return(((IList)xmlObject.Value)[listindex]);
                            }
                            catch (Exception e)
                            {
                                throw new UberScriptException("Get Array value error!", e);
                            }
                        }
                        else
                        {
                            throw new UberScriptException("xmlobj." + objName + " was indexed with [] indexer, but did not contain a list!");
                        }
                    }
                    //====


                    ptype = typeof(object);
                    return(xmlObject.Value);
                }
            }
            // 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;
             *
             *  ArrayList 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";
             * }
             * */

            // I REALLY OUGHT TO IMPLEMENT GETTING TYPE SOME TIME
            // 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)
                {
                    try
                    {
                        index = int.Parse(arrayvalue[0]);
                    }
                    catch
                    {
                        try
                        {
                            index = (int)(new MathTree(null, arrayvalue[0])).Calculate(trigObj);
                        }
                        catch
                        {
                            throw new UberScriptException("Could not get int array value from: " + arrayvalue[0] + " for prop of " + name + " on object " + o);
                        }
                    }
                }
            }

            PropertyInfo propInfoToGet     = null;
            string       lowerCasePropName = propname.ToLower();

            // optimization to find propertyInfo without looping through
            if (o is BaseCreature)
            {
                if (PropertySetters.BaseCreatureProperties.ContainsKey(lowerCasePropName))
                {
                    propInfoToGet = PropertySetters.BaseCreatureProperties[lowerCasePropName];
                }
            }
            else if (o is PlayerMobile)
            {
                if (PropertySetters.PlayerMobileProperties.ContainsKey(lowerCasePropName))
                {
                    propInfoToGet = PropertySetters.PlayerMobileProperties[lowerCasePropName];
                }
            }
            else if (o is Item)
            {
                if (PropertySetters.ItemProperties.ContainsKey(lowerCasePropName))
                {
                    propInfoToGet = PropertySetters.ItemProperties[lowerCasePropName];
                }
            }
            // is a nested property with attributes so first get the property
            if (propInfoToGet == null)
            {
                foreach (PropertyInfo p in props)
                {
                    if (Insensitive.Equals(p.Name, propname))
                    {
                        propInfoToGet = p;
                        break;
                    }
                }
            }
            if (propInfoToGet != null)
            {
                if (!propInfoToGet.CanRead)
                {
                    throw new UberScriptException("Property " + propname + " is write only.");
                }
                //if (IsProtected(type, propname))
                //    return "Property is protected.";
                ptype = propInfoToGet.PropertyType;
                if (arglist.Count > 1)
                {
                    if (ptype.IsPrimitive)
                    {
                        po = propInfoToGet.GetValue(o, null);
                    }
                    else if ((ptype.GetInterface("IList") != null) && index >= 0)
                    {
                        try
                        {
                            object arrayvalue = propInfoToGet.GetValue(o, null);
                            po = ((IList)arrayvalue)[index];
                        }
                        catch (Exception e)
                        {
                            throw new UberScriptException("Get Array value error!", e);
                        }
                    }
                    else
                    {
                        po = propInfoToGet.GetValue(o, null);
                    }
                    // now set the nested attribute using the new property list
                    string propLookup = arglist[1];
                    for (int i = 2; i < arglist.Count; i++)
                    {
                        propLookup += "." + arglist[i];
                    }
                    return(GetObject(trigObj, po, propLookup, out ptype));
                }
                else
                {
                    // its just a simple single property
                    return(InternalGetValue(o, propInfoToGet, index));
                }
            }

            throw new UberScriptException("Could not find property on " + o + ": " + name);
        }
        public override ProcessResult Process(ProcessResult lastSiblingResult, TriggerObject trigObject)
        {
            // will always have 2 children, either function nodes or MathTree nodes
            Object o        = null;
            string propname = null;
            Object value;
            string globalObjsString;
            string localObjsString;

            // 1st child is the property that will be set
            if (Children[0] is FunctionNode)
            {
                // this presumes that it is a function like THIS() or TRIGMOB()
                FunctionNode fn = Children[0] as FunctionNode;
                o        = fn.Execute(trigObject, true);
                propname = fn.Property;
            }
            else             // Children[0] is argument node
            {
                string scriptString = Children[0].ScriptString;
                int    dotIndex     = scriptString.IndexOf('.');

                if (dotIndex > -1)
                {
                    if (scriptString.StartsWith("global_"))
                    {
                        if (scriptString.StartsWith("global_ints."))
                        {
                            UberTreeParser.global_ints[scriptString.Substring(12)] = (int)((MathTree)Children[1]).Calculate(trigObject);

                            value = ((MathTree)Children[1]).Calculate(trigObject);

                            switch (AssignType)
                            {
                            case AssignmentType.Plus:
                                UberTreeParser.global_ints[scriptString.Substring(12)] =
                                    UberTreeParser.global_ints[scriptString.Substring(12)] + Convert.ToInt32(value);
                                break;

                            case AssignmentType.Minus:
                                UberTreeParser.global_ints[scriptString.Substring(12)] =
                                    UberTreeParser.global_ints[scriptString.Substring(12)] - Convert.ToInt32(value);
                                break;

                            case AssignmentType.Mult:
                                UberTreeParser.global_ints[scriptString.Substring(12)] =
                                    UberTreeParser.global_ints[scriptString.Substring(12)] * Convert.ToInt32(value);
                                break;

                            case AssignmentType.Divide:
                                UberTreeParser.global_ints[scriptString.Substring(12)] =
                                    Convert.ToInt32(UberTreeParser.global_ints[scriptString.Substring(12)] / Convert.ToDouble(value));
                                break;

                            default:
                                UberTreeParser.global_ints[scriptString.Substring(12)] = Convert.ToInt32(value);
                                break;
                            }

                            return(ProcessResult.None);
                        }

                        if (scriptString.StartsWith("global_strings."))
                        {
                            value = GetReturnObject(Children[1], trigObject);

                            if (value != null)
                            {
                                value = value.ToString();

                                switch (AssignType)
                                {
                                case AssignmentType.Plus:
                                    UberTreeParser.global_strings[scriptString.Substring(15)] =
                                        UberTreeParser.global_strings[scriptString.Substring(15)] + (string)value;
                                    break;

                                case AssignmentType.Regular:
                                    UberTreeParser.global_strings[scriptString.Substring(15)] = (string)value;
                                    break;
                                }

                                throw new UberScriptException(
                                          "Line " + LineNumber + ": " + ScriptString + "\nTried to use +=, -=, *=, or /= but this is only supported for " +
                                          value.GetType() + "! It is only supported for int, double, and UInt64");
                                //return ProcessResult.None;
                            }

                            throw new UberScriptException(
                                      "Line " + LineNumber + ": " + ScriptString +
                                      "\nTried to add null value to strings dictionary... this is not allowed!");
                        }

                        if (scriptString.StartsWith("global_doubles."))
                        {
                            value = ((MathTree)Children[1]).Calculate(trigObject);

                            switch (AssignType)
                            {
                            case AssignmentType.Plus:
                                UberTreeParser.global_doubles[scriptString.Substring(15)] =
                                    UberTreeParser.global_doubles[scriptString.Substring(15)] + Convert.ToDouble(value);
                                break;

                            case AssignmentType.Minus:
                                UberTreeParser.global_doubles[scriptString.Substring(15)] =
                                    UberTreeParser.global_doubles[scriptString.Substring(15)] - Convert.ToDouble(value);
                                break;

                            case AssignmentType.Mult:
                                UberTreeParser.global_doubles[scriptString.Substring(15)] =
                                    UberTreeParser.global_doubles[scriptString.Substring(15)] * Convert.ToDouble(value);
                                break;

                            case AssignmentType.Divide:
                                UberTreeParser.global_doubles[scriptString.Substring(15)] =
                                    UberTreeParser.global_doubles[scriptString.Substring(15)] / Convert.ToDouble(value);
                                break;

                            default:
                                UberTreeParser.global_doubles[scriptString.Substring(15)] = Convert.ToDouble(value);
                                break;
                            }

                            return(ProcessResult.None);
                        }

                        if (scriptString.StartsWith("global_objs."))
                        {
                            globalObjsString = scriptString.Substring(12);

                            int secondDotIndex = globalObjsString.IndexOf('.');

                            if (secondDotIndex > -1)                             // we are trying to set a property on an existing object
                            {
                                // will throw error if it doesn't exist yet
                                o        = UberTreeParser.global_objs[globalObjsString.Substring(0, secondDotIndex)];
                                propname = globalObjsString.Substring(secondDotIndex + 1);
                            }
                            else
                            {
                                UberTreeParser.global_objs[globalObjsString] = GetReturnObject(Children[1], trigObject);
                                return(ProcessResult.None);
                            }
                        }
                    }
                    else if (scriptString.StartsWith("ints."))
                    {
                        value = ((MathTree)Children[1]).Calculate(trigObject);

                        switch (AssignType)
                        {
                        case AssignmentType.Plus:
                            trigObject.ints[scriptString.Substring(5)] = trigObject.ints[scriptString.Substring(5)] + Convert.ToInt32(value);
                            break;

                        case AssignmentType.Minus:
                            trigObject.ints[scriptString.Substring(5)] = trigObject.ints[scriptString.Substring(5)] - Convert.ToInt32(value);
                            break;

                        case AssignmentType.Mult:
                            trigObject.ints[scriptString.Substring(5)] = trigObject.ints[scriptString.Substring(5)] * Convert.ToInt32(value);
                            break;

                        case AssignmentType.Divide:
                            trigObject.ints[scriptString.Substring(5)] =
                                Convert.ToInt32(trigObject.ints[scriptString.Substring(5)] / Convert.ToDouble(value));
                            break;

                        default:
                            trigObject.ints[scriptString.Substring(5)] = Convert.ToInt32(value);
                            break;
                        }

                        return(ProcessResult.None);
                    }
                    else if (scriptString.StartsWith("strings."))
                    {
                        value = GetReturnObject(Children[1], trigObject);

                        if (value != null)
                        {
                            value = value.ToString();

                            switch (AssignType)
                            {
                            case AssignmentType.Plus:
                                trigObject.strings[scriptString.Substring(8)] = trigObject.strings[scriptString.Substring(8)] + (string)value;
                                break;

                            case AssignmentType.Regular:
                                trigObject.strings[scriptString.Substring(8)] = (string)value;
                                break;

                            default:
                                throw new UberScriptException(
                                          "Line " + LineNumber + ": " + ScriptString +
                                          "\nTried to use +=, -=, *=, or /= but this is only supported for " + value.GetType() +
                                          "! It is only supported for int, double, and UInt64");
                            }
                            return(ProcessResult.None);
                        }

                        throw new UberScriptException(
                                  "Line " + LineNumber + ": " + ScriptString +
                                  "\nTried to add null value to strings dictionary... this is not allowed!");
                    }
                    else if (scriptString.StartsWith("doubles."))
                    {
                        value = ((MathTree)Children[1]).Calculate(trigObject);

                        switch (AssignType)
                        {
                        case AssignmentType.Plus:
                            trigObject.doubles[scriptString.Substring(8)] = trigObject.doubles[scriptString.Substring(8)] +
                                                                            Convert.ToDouble(value);
                            break;

                        case AssignmentType.Minus:
                            trigObject.doubles[scriptString.Substring(8)] = trigObject.doubles[scriptString.Substring(8)] -
                                                                            Convert.ToDouble(value);
                            break;

                        case AssignmentType.Mult:
                            trigObject.doubles[scriptString.Substring(8)] = trigObject.doubles[scriptString.Substring(8)] *
                                                                            Convert.ToDouble(value);
                            break;

                        case AssignmentType.Divide:
                            trigObject.doubles[scriptString.Substring(8)] = trigObject.doubles[scriptString.Substring(8)] /
                                                                            Convert.ToDouble(value);
                            break;

                        default:
                            trigObject.doubles[scriptString.Substring(8)] = Convert.ToDouble(value);
                            break;
                        }

                        return(ProcessResult.None);
                    }
                    else if (scriptString.StartsWith("objs."))
                    {
                        localObjsString = scriptString.Substring(5);

                        int secondDotIndex = localObjsString.IndexOf('.');

                        if (secondDotIndex > -1)                         // we are trying to set a property on an existing object
                        {
                            if (!trigObject.objs.TryGetValue(localObjsString.Substring(0, secondDotIndex), out o))
                            {
                                // will throw error if it doesn't exist yet
                                throw new UberScriptException(
                                          "local objs dictionary did not have entry: " + localObjsString.Substring(0, secondDotIndex));
                            }

                            propname = localObjsString.Substring(secondDotIndex + 1);
                        }
                        else
                        {
                            trigObject.objs[localObjsString] = GetReturnObject(Children[1], trigObject);
                            return(ProcessResult.None);
                        }
                    }
                }

                // only makes it here if we aren't editing global variables directly
                // (or if the we are returning a global object, e.g. global_objs.goober.hits
                if (o == null)
                {
                    o        = trigObject.Spawn ?? trigObject.This;
                    propname = scriptString;
                }
            }

            // 2nd child is the value, but could have an operation in it and needs to be parsed
            try
            {
                if (AssignType == AssignmentType.Regular)
                {
                    value = GetReturnObject(Children[1], trigObject);
                }
                else
                {
                    Type ptype;

                    value = PropertyGetters.GetObject(trigObject, o, propname, out ptype);

                    if (value is int)
                    {
                        switch (AssignType)
                        {
                        case AssignmentType.Plus:
                            value = (int)value + Convert.ToInt32(GetReturnObject(Children[1], trigObject));
                            break;

                        case AssignmentType.Minus:
                            value = (int)value - Convert.ToInt32(GetReturnObject(Children[1], trigObject));
                            break;

                        case AssignmentType.Mult:
                            value = Convert.ToInt32((int)value * Convert.ToDouble(GetReturnObject(Children[1], trigObject)));
                            break;

                        case AssignmentType.Divide:
                            value = Convert.ToInt32((int)value / Convert.ToDouble(GetReturnObject(Children[1], trigObject)));
                            break;
                        }
                    }
                    else if (value is double)
                    {
                        switch (AssignType)
                        {
                        case AssignmentType.Plus:
                            value = (double)value + Convert.ToDouble(GetReturnObject(Children[1], trigObject));
                            break;

                        case AssignmentType.Minus:
                            value = (double)value - Convert.ToDouble(GetReturnObject(Children[1], trigObject));
                            break;

                        case AssignmentType.Mult:
                            value = (double)value * Convert.ToDouble(GetReturnObject(Children[1], trigObject));
                            break;

                        case AssignmentType.Divide:
                            value = (double)value / Convert.ToDouble(GetReturnObject(Children[1], trigObject));
                            break;
                        }
                    }
                    else if (value is UInt64)
                    {
                        switch (AssignType)
                        {
                        case AssignmentType.Plus:
                            value = (UInt64)value + Convert.ToUInt64(GetReturnObject(Children[1], trigObject));
                            break;

                        case AssignmentType.Minus:
                            value = (UInt64)value - Convert.ToUInt64(GetReturnObject(Children[1], trigObject));
                            break;

                        case AssignmentType.Mult:
                            value = Convert.ToUInt64((UInt64)value * Convert.ToDouble(GetReturnObject(Children[1], trigObject)));
                            break;

                        case AssignmentType.Divide:
                            value = Convert.ToUInt64((UInt64)value / Convert.ToDouble(GetReturnObject(Children[1], trigObject)));
                            break;
                        }
                    }
                    else if (value is string)
                    {
                        if (AssignType == AssignmentType.Plus)
                        {
                            value = (string)value + GetReturnObject(Children[1], trigObject);
                        }
                        else
                        {
                            throw new UberScriptException(
                                      "Tried to use +=, -=, *=, or /= but this is only supported for " + value.GetType() +
                                      "! It is only supported for int, double, and UInt64");
                        }
                    }
                    else
                    {
                        //throw new UberScriptException("Tried to use +=, -=, *=, or /= on a non-numeric left-hand side!");
                        throw new UberScriptException(
                                  "Tried to use +=, -=, *=, or /= but this is only supported for " + value.GetType() +
                                  "! It is only supported for int, double, and UInt64");
                    }
                }
            }
            catch (Exception e)
            {
                throw new UberScriptException("Line " + LineNumber + ": " + ScriptString + "\nGetReturnObject Error:", e);
            }

            try
            {
                PropertySetters.SetPropertyValue(trigObject, o, propname, value);
            }
            catch (Exception e)
            {
                throw new UberScriptException("Line " + LineNumber + ": " + ScriptString + "\nError setting value:", e);
            }

            return(ProcessResult.None);
        }