using System.Collections.Generic;\r
using System.Linq;\r
using System.Text;\r
+using System.Reflection;\r
+using System.Diagnostics;\r
\r
namespace CarFire\r
{\r
+ /// <summary>\r
+ /// The Script class handles the parsing and execution of lists\r
+ /// of functions. Scripts are closely related to triggers.\r
+ /// </summary>\r
public class Script\r
{\r
- #region Public Types\r
+ #region Public Properties\r
\r
- public enum Status\r
+ /// <summary>\r
+ /// Determine if the script is in the process of being run.\r
+ /// </summary>\r
+ public bool IsRunning { get { return mIsRunning; } }\r
+\r
+ #endregion\r
+\r
+\r
+ #region Public Methods\r
+\r
+ /// <summary>\r
+ /// Construct a script object with code and a game reference.\r
+ /// </summary>\r
+ /// <param name="code">The script code.</param>\r
+ /// <param name="game">A game reference.</param>\r
+ public Script(string code, Game game)\r
{\r
- Waiting,\r
- Done,\r
+ mImpl = new Impl(game);\r
+\r
+ string[] functions = Parse.List(code);\r
+ if (functions != null)\r
+ {\r
+ foreach (string function in functions)\r
+ {\r
+ string[] parts = Parse.Function(function);\r
+ if (parts != null)\r
+ {\r
+ string[] args = Parse.List(parts[1]);\r
+ if (args != null)\r
+ {\r
+ Function func = new Function(parts[0], args);\r
+ mFunctions.Add(func);\r
+ }\r
+ else throw new Exception("Arguments could not be parsed: " + parts[1]);\r
+ }\r
+ else throw new Exception("Function could not be parsed: " + function);\r
+ }\r
+ }\r
+ else throw new Exception("Script could not be parsed: " + code);\r
}\r
\r
- public enum Function\r
+ /// <summary>\r
+ /// Start execution of the script. If there is no need to break\r
+ /// execution before the script ends, it will finish before this method\r
+ /// call ends. Otherwise, execution will be delayed and will finish sometime\r
+ /// in the future. This will execute each function in sequence as long\r
+ /// as each function evaluates to true. If a function does not evaluate to true,\r
+ /// this method will return and execution will be delayed. In either case,\r
+ /// the evaluation of the last function is returned by this method.\r
+ /// </summary>\r
+ /// <param name="player">The player associated with this script.</param>\r
+ /// <returns>Evaluation of the last function call.</returns>\r
+ public bool Run(Player player)\r
{\r
- Create,\r
- Has,\r
- Play,\r
- Remove,\r
- UseUp,\r
- Wait,\r
+ bool result = false;\r
+\r
+ if (!mIsRunning)\r
+ {\r
+ mIsRunning = true;\r
+ mRunningIndex = 0;\r
+ }\r
+\r
+ for (; mRunningIndex < mFunctions.Count; mRunningIndex++)\r
+ {\r
+ result = Call(mRunningIndex, player);\r
+ if (!result) break;\r
+ }\r
+\r
+ if (mRunningIndex >= mFunctions.Count - 1) mIsRunning = false;\r
+ return result;\r
}\r
\r
#endregion\r
\r
\r
- #region Public Methods\r
+ #region Private Methods\r
\r
- public Script(string code)\r
+ /// <summary>\r
+ /// Call a function in the last at a certain index.\r
+ /// </summary>\r
+ /// <param name="index">The function index.</param>\r
+ /// <param name="player">The associated player object.</param>\r
+ /// <returns>The evaluation of the function.</returns>\r
+ bool Call(int index, Player player)\r
{\r
+ Debug.Assert(0 <= index && index < mFunctions.Count);\r
+ try\r
+ {\r
+ object[] args = new object[2];\r
+ args[0] = player;\r
+ args[1] = mFunctions[index].Arguments;\r
+ return (bool)typeof(Impl).InvokeMember(mFunctions[index].Name, BindingFlags.InvokeMethod, null, null, args);\r
+ }\r
+#pragma warning disable 0168\r
+ catch (System.MissingMethodException ex)\r
+#pragma warning restore 0168\r
+ {\r
+ throw new Exception("Function could not be found: " + mFunctions[index].Name);\r
+ }\r
}\r
\r
- public Status Run()\r
+ #endregion\r
+\r
+\r
+ #region Private Types\r
+\r
+ class Impl\r
{\r
- return Status.Done;\r
+ public static bool True(Player player, string[] args)\r
+ {\r
+ return true;\r
+ }\r
+\r
+ public static bool False(Player player, string[] args)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ public static bool Has(Player player, string[] args)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ public static bool Print(Player player, string[] args)\r
+ {\r
+ foreach (string arg in args)\r
+ {\r
+ string line = Parse.String(arg);\r
+ if (line != null) Console.WriteLine(line);\r
+ }\r
+ return true;\r
+ }\r
+\r
+\r
+ public Impl(Game game)\r
+ {\r
+ mGame = game;\r
+ }\r
+\r
+ Game mGame;\r
}\r
\r
- public Status Evaluate(out bool value)\r
+ class Function\r
{\r
- value = true;\r
- return Status.Done;\r
+ public string Name { get { return mName; } }\r
+ public string[] Arguments { get { return mArgs; } }\r
+\r
+ public Function(string name, string[] args)\r
+ {\r
+ mName = name;\r
+ mArgs = args;\r
+ }\r
+\r
+ string mName;\r
+ string[] mArgs;\r
}\r
\r
#endregion\r
+\r
+\r
+ #region Private Variables\r
+\r
+ Impl mImpl;\r
+ List<Function> mFunctions = new List<Function>();\r
+ bool mIsRunning;\r
+ int mRunningIndex;\r
+\r
+ #endregion\r
}\r
}\r