dimensions = [80,21]\r
tileset = Warehouse\r
numplayers = <1,4>\r
+ next = maze\r
\r
[M]\r
type = SaberMonster\r
\r
[k]\r
type = Key\r
- condition = True()\r
- event = PickUp()\r
+ script = PickUp()\r
+ options = Once\r
\r
-[T]\r
+[L]\r
type = Trigger\r
- condition = Print("Trigger tested.") False()\r
- event = Print("Trigger fired!")\r
+ script = Print("Checking for key...") Has(k) Drop(k) Print("KEY DROPPED") Wait(15) Set([9,3] %) Set([10,3] %) Set([11,3] %) Set([9,4] %) Set([11,4] %) Set([9,5] %) Set([10,5] %) Set([11,5] %) Print("Haha you're trapped.") Wait(200) Set([9,3] >) Set([10,3] >) Set([11,3] >) Set([9,4] >) Set([11,4] >) Set([9,5] >) Set([10,5] >) Set([11,5] >) Print("Just kidding.") Wait(500) Next()\r
+ options = Once\r
\r
[maptable]\r
+------------------------------------------------------------------------------+\r
| |\r
| 1 2 |\r
-| T |\r
-| 3 4 +---- |\r
-| | M |\r
-| k | |\r
+| ... |\r
+| 3 4 .L. +---- |\r
+| ... | M |\r
+| k | |\r
| |------------------------------------------ |\r
| | | |\r
| | | |\r
; event = wait(2) remove([2,6]) remove([2,7])\r
\r
; Function ideas:\r
-; has(entity) Player has given entity in his inventory.\r
-; wait(seconds) Pause for some number of seconds.\r
-; remove(entity) Remove entities of a certain type from the game.\r
; remove(coord) Remove whatever is at the given coordinates.\r
; create(entity, coord) Create an entity at some location.\r
; play(soundname) Play a sound.\r
\r
#region Public Methods\r
\r
+ /// <summary>\r
+ /// Get an entity at a certain place on the map.\r
+ /// </summary>\r
+ /// <param name="point">The coordinates.</param>\r
+ /// <returns>The entity, or null if none is at that location.</returns>\r
public IEntity GetEntityAtCoordinates(Point point)\r
{\r
foreach (IEntity entity in State.Entities)\r
return null;\r
}\r
\r
+ /// <summary>\r
+ /// Get a player at a certain place on the map.\r
+ /// </summary>\r
+ /// <param name="point">The coordinates.</param>\r
+ /// <returns>The player, or null if none is at that location.</returns>\r
public Player GetPlayerAtCoordinates(Point point)\r
{\r
foreach (Player player in State.mCharacters)\r
return null;\r
}\r
\r
+ /// <summary>\r
+ /// Determine if a cell is open, depending on the static scenery\r
+ /// of the map and if there are any collidable entities.\r
+ /// </summary>\r
+ /// <param name="point">The coordinates.</param>\r
+ /// <returns>True if the cell is open; false otherwise.</returns>\r
public bool IsCellOpen(Point point)\r
{\r
if (!State.Map.IsCellOpen(point)) return false;\r
return true;\r
}\r
\r
+ /// <summary>\r
+ /// Remove a specific entity from the game. The entity can still\r
+ /// be tracked some other way, but it won't included when the game is\r
+ /// updating and drawing stuff.\r
+ /// </summary>\r
+ /// <param name="entity">The entity.</param>\r
+ /// <returns>The entity that was removed, or null if no entity was removed.</returns>\r
+ public IEntity RemoveEntity(IEntity entity)\r
+ {\r
+ if (State.Entities.Remove(entity)) return entity;\r
+ return null;\r
+ }\r
+\r
+ /// <summary>\r
+ /// Move on to the next map, and advance the level.\r
+ /// </summary>\r
+ public void AdvanceLevel()\r
+ {\r
+ // TODO: Load the next map, etc...\r
+ }\r
+\r
+ /// <summary>\r
+ /// Restart the current level.\r
+ /// </summary>\r
+ public void Reset()\r
+ {\r
+ State.Map.Reset();\r
+ // TODO: Do other stuff to reset everything.\r
+ }\r
+\r
+\r
public Game()\r
{\r
\r
/// <summary>\r
/// Get the coordinates on the grid.\r
/// </summary>\r
- Point Coordinates { get; }\r
+ Point Coordinates { get; set; }\r
+\r
+ /// <summary>\r
+ /// Get the entity's identifier.\r
+ /// </summary>\r
+ char Identifier { get; }\r
}\r
}\r
{\r
/// <summary>\r
/// A key entity. Keys can be used to unlock doors... what a surprise.\r
+ /// All that stuff is handled by the trigger, though.\r
/// </summary>\r
public class Key : Trigger\r
{\r
#region Public Methods\r
-\r
+ \r
/// <summary>\r
/// Construct a key entity.\r
/// </summary>\r
public Key(char identifier, Point position, Dictionary<string, string> info, Game game) :\r
base(identifier, position, info, game)\r
{\r
- mPosition = new Vector2(position.X, position.Y);\r
- mGame = game;\r
+ // No implementation needed.\r
}\r
-\r
+ \r
public override void LoadContent(ContentManager contentManager)\r
{\r
mTexture = contentManager.Load<Texture2D>("default");\r
\r
public override void Draw(SpriteBatch spriteBatch)\r
{\r
- Rectangle position = mGame.State.Map.GetRectangleFromCoordinates(mPosition);\r
+ Rectangle position = Game.State.Map.GetRectangleFromCoordinates(Position);\r
spriteBatch.Draw(mTexture, position, Color.White);\r
}\r
\r
#region Private Variables\r
\r
Texture2D mTexture;\r
- Game mGame;\r
- Vector2 mPosition;\r
\r
#endregion\r
}\r
public string Name;\r
public Mode Type;\r
public string Author;\r
+ public string Next;\r
public HashSet<int> NumPlayers = new HashSet<int>();\r
public string Tileset;\r
public int GridWidth;\r
/// </summary>\r
public string Author { get { return mData.Metadata.Author; } }\r
\r
+ /// <summary>\r
+ /// Get the name of the next map to load after this one.\r
+ /// </summary>\r
+ public string Next { get { return mData.Metadata.Next; } }\r
+\r
/// <summary>\r
/// Get a set of integers containing each allowable number of players.\r
/// </summary>\r
else throw new Exception("Unexpected value on line " + mInput.LineNumber + ": " + atom);\r
}\r
\r
+ public void set_next(string atom)\r
+ {\r
+ string value = Parse.String(atom);\r
+ if (value != null) mMetadata.Next = value;\r
+ else throw new Exception("Unexpected value on line " + mInput.LineNumber + ": " + atom);\r
+ }\r
+\r
public void set_type(string atom)\r
{\r
- Map.Mode value = Parse.Constant<Map.Mode>(atom);\r
- if (value != default(Map.Mode)) mMetadata.Type = value;\r
+ Map.Mode? value = Parse.Constant<Map.Mode>(atom);\r
+ if (value != null) mMetadata.Type = value.Value;\r
else throw new Exception("Unexpected type on line " + mInput.LineNumber + ": " + atom);\r
}\r
\r
/// </summary>\r
/// <typeparam name="T">An enumeration.</typeparam>\r
/// <param name="atom">Text.</param>\r
- /// <returns>The constant, or default(T) if parsing failed.</returns>\r
- public static T Constant<T>(string atom)\r
+ /// <returns>The constant, or null if parsing failed.</returns>\r
+ public static T? Constant<T>(string atom) where T : struct\r
{\r
try\r
{\r
catch (System.Exception ex)\r
#pragma warning restore 0168\r
{\r
- return default(T);\r
+ return null;\r
}\r
}\r
\r
public int PlayerIndex { get { return mPlayerIndex; } }\r
public bool IsCollidable { get { return true; } }\r
public Vector2 Position { get { return mMotion.Position; } }\r
- public Point Coordinates { get { return mMotion.Coordinates; } \r
+ public Point Coordinates { get { return mMotion.Coordinates; }\r
set\r
{\r
Coordinates = value;\r
mMotion = new MovementManager(value, basePlayerSpeed);\r
} }\r
+ public char Identifier { get { return mPlayerIndex.ToString()[0]; } }\r
public int Damage { get { return playerDamage; } set { playerDamage = value; } }\r
public List<IEntity> Inventory { get { return mInventory; } }\r
#endregion\r
/// <summary>\r
/// Get the grid coordinates.\r
/// </summary>\r
- public Point Coordinates { get { return mMotion.Coordinates; } }\r
+ public Point Coordinates {\r
+ get { return mMotion.Coordinates; }\r
+ set { mMotion = new MovementManager(value, mMotion.Speed); }\r
+ }\r
+\r
+ /// <summary>\r
+ /// Get the entity identifier.\r
+ /// </summary>\r
+ public char Identifier { get { return mId; } }\r
\r
#endregion\r
\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
+ public Script(string code, object bindings)\r
{\r
- mImpl = new Impl(game);\r
+ mBindings = bindings;\r
\r
string[] functions = Parse.List(code);\r
if (functions != null)\r
return result;\r
}\r
\r
+ public void Reset()\r
+ {\r
+ mIsRunning = false;\r
+\r
+ }\r
+\r
#endregion\r
\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
+ return (bool)mBindings.GetType().InvokeMember(mFunctions[index].Name, BindingFlags.InvokeMethod, null, mBindings, args);\r
}\r
#pragma warning disable 0168\r
catch (System.MissingMethodException ex)\r
\r
#region Private Types\r
\r
- class Impl\r
- {\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
class Function\r
{\r
public string Name { get { return mName; } }\r
\r
#region Private Variables\r
\r
- Impl mImpl;\r
+ object mBindings;\r
List<Function> mFunctions = new List<Function>();\r
bool mIsRunning;\r
int mRunningIndex;\r
\r
namespace CarFire\r
{\r
+ /// <summary>\r
+ /// Trigger options modify trigger behavior.\r
+ /// </summary>\r
+ [Flags]\r
+ public enum TriggerOptions\r
+ {\r
+ Default = 0x00,\r
+ Reset = 0x01, // The script will be reset each time.\r
+ Once = 0x02, // Trigger can only be fired once.\r
+ Continuous = 0x04, // Trigger is always checked each update.\r
+ }\r
+\r
+\r
/// <summary>\r
/// A trigger is an invisible entity whose only purpose is\r
- /// to check a condition and run a script when the condition\r
- /// is right.\r
+ /// to check for a player to step on it and then run a script.\r
/// </summary>\r
public class Trigger : IEntity\r
{\r
/// <param name="game">The game reference.</param>\r
public Trigger(char identifier, Point position, Dictionary<string, string> info, Game game)\r
{\r
+ mId = identifier; \r
mGame = game;\r
- mPrevCondition = false;\r
mCoordinates = position;\r
\r
- string condition;\r
- if (info.TryGetValue("condition", out condition))\r
+ Functions functions = new Functions(this, game);\r
+\r
+ string script;\r
+ if (info.TryGetValue("script", out script))\r
{\r
- mCondition = new Script(condition, game);\r
+ mScript = new Script(script, functions);\r
}\r
- else throw new Exception("Triggers must define a condition script.");\r
+ else throw new Exception("Triggers must define a script.");\r
\r
- string eventt;\r
- if (info.TryGetValue("event", out eventt))\r
+ string options;\r
+ if (info.TryGetValue("options", out options))\r
{\r
- mEvent = new Script(eventt, game);\r
+ string[] list = Parse.List(options);\r
+ if (list != null)\r
+ {\r
+ foreach (string option in list)\r
+ {\r
+ TriggerOptions? flag = Parse.Constant<TriggerOptions>(option);\r
+ if (flag != null) mFlags |= flag.Value;\r
+ }\r
+ }\r
}\r
- else throw new Exception("Triggers must define an event script.");\r
}\r
\r
/// <summary>\r
- /// Check the trigger condition and execute the event if the\r
- /// condition evaluates to true.\r
+ /// Check for a player and execute the trigger script if\r
+ /// there is a player on this cell.\r
/// </summary>\r
public void Call()\r
{\r
- Player player = mGame.GetPlayerAtCoordinates(mCoordinates);\r
- if (player != null)\r
+ if (!mIsExpired)\r
{\r
- bool condition = mCondition.Run(player);\r
- if (condition && condition != mPrevCondition)\r
+ Player player = mGame.GetPlayerAtCoordinates(mCoordinates);\r
+ if (player != null)\r
{\r
- mEvent.Run(player);\r
+ if (!mIsFinished || (mFlags & TriggerOptions.Continuous) == TriggerOptions.Continuous)\r
+ {\r
+ mIsFinished = mScript.Run(player);\r
+ if (mIsFinished && (mFlags & TriggerOptions.Once) == TriggerOptions.Once) mIsExpired = true;\r
+ else if ((mFlags & TriggerOptions.Reset) == TriggerOptions.Reset) mScript.Reset();\r
+ }\r
}\r
- mPrevCondition = condition;\r
- }\r
- else\r
- {\r
- mPrevCondition = false;\r
+ else mIsFinished = false;\r
}\r
}\r
\r
\r
public Vector2 Position\r
{\r
- get { return Vector2.Zero; }\r
+ get { return new Vector2(mCoordinates.X, mCoordinates.Y); }\r
}\r
\r
public Point Coordinates\r
{\r
get { return mCoordinates; }\r
+ set { mCoordinates = value; }\r
+ }\r
+\r
+ public char Identifier\r
+ {\r
+ get { return mId; }\r
+ }\r
+\r
+ public Game Game\r
+ {\r
+ get { return mGame; }\r
+ }\r
+\r
+ #endregion\r
+\r
+\r
+ #region Private Types\r
+\r
+ /// <summary>\r
+ /// The script bindings.\r
+ /// </summary>\r
+ class Functions\r
+ {\r
+ // Always evaluates to true.\r
+ public bool True(Player player, string[] args)\r
+ {\r
+ return true;\r
+ }\r
+\r
+ // Always evaluates to false.\r
+ public bool False(Player player, string[] args)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ // Check the player's inventory for an entity.\r
+ // Arg1: Entity identifier.\r
+ public bool Has(Player player, string[] args)\r
+ {\r
+ if (args.Length == 0) return false;\r
+\r
+ char? entity = Parse.Char(args[0]);\r
+ if (entity != null)\r
+ {\r
+ foreach (IEntity item in player.Inventory)\r
+ {\r
+ if (entity == item.Identifier) return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+\r
+ // Put the trigger in the player's inventory.\r
+ public bool PickUp(Player player, string[] args)\r
+ {\r
+ IEntity entity = mGame.RemoveEntity(mTrigger);\r
+ if (entity != null)\r
+ {\r
+ player.Inventory.Add(entity);\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ // Drop an entity from the player's inventory here.\r
+ // Arg1: Entity identifier.\r
+ public bool Drop(Player player, string[] args)\r
+ {\r
+ if (args.Length == 0) return false;\r
+\r
+ char? entity = Parse.Char(args[0]);\r
+ if (entity != null)\r
+ {\r
+ foreach (IEntity item in player.Inventory)\r
+ {\r
+ if (entity == item.Identifier)\r
+ {\r
+ player.Inventory.Remove(item);\r
+ mGame.State.Entities.Add(item);\r
+ item.Coordinates = mTrigger.Coordinates;\r
+ return true;\r
+ }\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+\r
+ // Use an entity in the player's inventory, disposing it.\r
+ // Arg1: Entity identifier.\r
+ public bool Use(Player player, string[] args)\r
+ {\r
+ if (args.Length == 0) return false;\r
+\r
+ char? entity = Parse.Char(args[0]);\r
+ if (entity != null)\r
+ {\r
+ foreach (IEntity item in player.Inventory)\r
+ {\r
+ if (entity == item.Identifier)\r
+ {\r
+ player.Inventory.Remove(item);\r
+ return true;\r
+ }\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+\r
+ // Wait for a ceretain number of ticks.\r
+ // Arg1: Number of ticks.\r
+ public bool Wait(Player player, string[] args)\r
+ {\r
+ if (args.Length == 0) return false;\r
+\r
+ if (mTicks == 0)\r
+ {\r
+ int? timer = Parse.Integer(args[0]);\r
+ if (timer != null)\r
+ {\r
+ mTicks = 1;\r
+ mTimerTicks = timer.Value;\r
+ }\r
+ }\r
+ else if (++mTicks >= mTimerTicks)\r
+ {\r
+ mTicks = 0;\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ // Print each argument to the console as a string.\r
+ public 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
+ // Change a cell's tile on the map.\r
+ // Arg1: The coordinates.\r
+ // Arg2: The character representing the tile.\r
+ public bool Set(Player player, string[] args)\r
+ {\r
+ if (args.Length < 2) return false;\r
+\r
+ Point? coord = Parse.Coordinates(args[0]);\r
+ if (coord != null)\r
+ {\r
+ char? tile = Parse.Char(args[1]);\r
+ if (tile != null)\r
+ {\r
+ mGame.State.Map.SetCell(coord.Value, tile.Value);\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+\r
+ // Move on to the next level.\r
+ public bool Next(Player player, string[] args)\r
+ {\r
+ mGame.AdvanceLevel();\r
+ return true;\r
+ }\r
+\r
+ // Restart the current level.\r
+ public bool Reset(Player player, string[] args)\r
+ {\r
+ mGame.Reset();\r
+ return true;\r
+ }\r
+\r
+\r
+ public Functions(IEntity trigger, Game game)\r
+ {\r
+ mTrigger = trigger;\r
+ mGame = game;\r
+ }\r
+\r
+ IEntity mTrigger;\r
+ Game mGame;\r
+ int mTicks;\r
+ int mTimerTicks;\r
}\r
\r
#endregion\r
\r
#region Private Variables\r
\r
- Script mCondition;\r
- Script mEvent;\r
+ Script mScript;\r
+\r
+ TriggerOptions mFlags;\r
+ bool mIsFinished;\r
+ bool mIsExpired;\r
+\r
+ char mId;\r
Game mGame;\r
- bool mPrevCondition;\r
Point mCoordinates;\r
\r
#endregion\r