New IEntity properties: Coordinates (set), Identifier. Loadable entities should...
authorCharles <Charles@92bb83a3-7c8f-8a45-bc97-515c4e399668>
Mon, 26 Apr 2010 22:07:09 +0000 (22:07 +0000)
committerCharles <Charles@92bb83a3-7c8f-8a45-bc97-515c4e399668>
Mon, 26 Apr 2010 22:07:09 +0000 (22:07 +0000)
Documented Game methods and added new ones: AdvanceLevel, Reset, RemoveEntity.
New Map property: Map.Next gets the name of the next map to load.
Parse.Constant change: return type is now nullable and will return null if parsing fails.
Refined triggers/scripts: added trigger options, more consistent behavior, many more functions.
Added key/lock design concept to level1, using Player.Inventory.

git-svn-id: https://bd85.net/svn/cs3505_group@154 92bb83a3-7c8f-8a45-bc97-515c4e399668

12 files changed:
CarFire/CarFire/CarFire/Content/Maps/level1.cfmap
CarFire/CarFire/CarFire/Content/Maps/sandbox.cfmap
CarFire/CarFire/CarFire/Game.cs
CarFire/CarFire/CarFire/IEntity.cs
CarFire/CarFire/CarFire/Key.cs
CarFire/CarFire/CarFire/Map.cs
CarFire/CarFire/CarFire/MapReader.cs
CarFire/CarFire/CarFire/Parse.cs
CarFire/CarFire/CarFire/Player.cs
CarFire/CarFire/CarFire/SaberMonster.cs
CarFire/CarFire/CarFire/Script.cs
CarFire/CarFire/CarFire/Trigger.cs

index 7431e08..20e1da9 100644 (file)
@@ -5,6 +5,7 @@
        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
-|                |                                                           |\r
+|        ...                                                                   |\r
+| 3 4    .L.       +----                                                       |\r
+|        ...       |                                  M                        |\r
+|    k             |                                                           |\r
 |                  |------------------------------------------                 |\r
 |                  |                                       |                   |\r
 |                  |                                       |                   |\r
index 28050cf..0481034 100644 (file)
@@ -21,9 +21,6 @@
 ;      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
index 1486e65..f78945b 100644 (file)
@@ -240,6 +240,11 @@ namespace CarFire
 \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
@@ -249,6 +254,11 @@ namespace CarFire
             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
@@ -258,6 +268,12 @@ namespace CarFire
             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
@@ -266,6 +282,37 @@ namespace CarFire
             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
index e916f2a..76dcc19 100644 (file)
@@ -45,6 +45,11 @@ namespace CarFire
         /// <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
index 0fab663..cebad87 100644 (file)
@@ -10,11 +10,12 @@ namespace CarFire
 {\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
@@ -25,10 +26,9 @@ namespace CarFire
         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
@@ -36,7 +36,7 @@ namespace CarFire
 \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
@@ -46,8 +46,6 @@ namespace CarFire
         #region Private Variables\r
 \r
         Texture2D mTexture;\r
-        Game mGame;\r
-        Vector2 mPosition;\r
 \r
         #endregion\r
     }\r
index 0178e2b..504a68c 100644 (file)
@@ -46,6 +46,7 @@ namespace CarFire
             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
@@ -82,6 +83,11 @@ namespace CarFire
         /// </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
index 9c58cb3..347f6bd 100644 (file)
@@ -321,10 +321,17 @@ namespace CarFire
                 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
index 4c2abcc..ca98353 100644 (file)
@@ -126,8 +126,8 @@ namespace CarFire
         /// </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
@@ -137,7 +137,7 @@ namespace CarFire
             catch (System.Exception ex)\r
 #pragma warning restore 0168\r
             {\r
-                return default(T);\r
+                return null;\r
             }\r
         }\r
 \r
index 9d6c6b4..b84b048 100644 (file)
@@ -35,12 +35,13 @@ namespace CarFire
         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
index a3507c8..f417d52 100644 (file)
@@ -221,7 +221,15 @@ namespace CarFire
         /// <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
index 9676bbb..0cf9dbd 100644 (file)
@@ -30,9 +30,9 @@ namespace CarFire
         /// </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
@@ -87,6 +87,12 @@ namespace CarFire
             return result;\r
         }\r
 \r
+        public void Reset()\r
+        {\r
+            mIsRunning = false;\r
+\r
+        }\r
+\r
         #endregion\r
 \r
 \r
@@ -106,7 +112,7 @@ namespace CarFire
                 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
@@ -121,42 +127,6 @@ namespace CarFire
 \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
@@ -177,7 +147,7 @@ namespace CarFire
 \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
index e405aa9..6c92b03 100644 (file)
@@ -8,10 +8,22 @@ using Microsoft.Xna.Framework.Content;
 \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
@@ -26,44 +38,53 @@ namespace CarFire
         /// <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
@@ -94,12 +115,199 @@ namespace CarFire
 \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
@@ -107,10 +315,14 @@ namespace CarFire
 \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
This page took 0.058554 seconds and 4 git commands to generate.