using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
namespace CarFire
{
///
/// Trigger options modify trigger behavior.
///
[Flags]
public enum TriggerOptions
{
Default = 0x00,
Reset = 0x01, // The script will be reset each time.
Once = 0x02, // Trigger can only be fired once.
Continuous = 0x04, // Trigger is always checked each update.
}
///
/// A trigger is an invisible entity whose only purpose is
/// to check for a player to step on it and then run a script.
///
public class Trigger : IEntity
{
#region Public Methods
///
/// Construct a trigger entity.
///
/// The entity identifier.
/// The position.
/// The key-value pairs.
/// The game reference.
public Trigger(char identifier, Point position, Dictionary info, Game game)
{
mId = identifier;
mGame = game;
mCoordinates = position;
Functions functions = new Functions(this, game);
string script;
if (info.TryGetValue("script", out script))
{
mScript = new Script(script, functions);
}
else throw new Exception("Triggers must define a script.");
string options;
if (info.TryGetValue("options", out options))
{
string[] list = Parse.List(options);
if (list != null)
{
foreach (string option in list)
{
TriggerOptions? flag = Parse.Constant(option);
if (flag != null) mFlags |= flag.Value;
}
}
}
}
///
/// Check for a player and execute the trigger script if
/// there is a player on this cell.
///
public void Call()
{
if (!mIsExpired)
{
Player player = mGame.GetPlayerAtCoordinates(mCoordinates);
if (player != null)
{
if (!mIsFinished || (mFlags & TriggerOptions.Continuous) == TriggerOptions.Continuous)
{
mIsFinished = mScript.Run(player);
if (mIsFinished && (mFlags & TriggerOptions.Once) == TriggerOptions.Once) mIsExpired = true;
else if ((mFlags & TriggerOptions.Reset) == TriggerOptions.Reset) mScript.Reset();
}
}
else mIsFinished = false;
}
}
///
/// Calls the trigger.
///
/// Unused.
public virtual void Update(TimeSpan timeSpan)
{
Call();
}
public virtual void LoadContent(ContentManager contentManager)
{
// No implementation needed.
}
public virtual void Draw(SpriteBatch spriteBatch)
{
// No implementation needed.
}
public bool IsCollidable
{
get { return false; }
}
public Vector2 Position
{
get { return new Vector2(mCoordinates.X, mCoordinates.Y); }
}
public Point Coordinates
{
get { return mCoordinates; }
set { mCoordinates = value; }
}
public char Identifier
{
get { return mId; }
}
public Game Game
{
get { return mGame; }
}
#endregion
#region Private Types
///
/// The script bindings.
///
class Functions
{
// Always evaluates to true.
public bool True(Player player, string[] args)
{
return true;
}
// Always evaluates to false.
public bool False(Player player, string[] args)
{
return false;
}
// Check the player's inventory for an entity.
// Arg1: Entity identifier.
public bool Has(Player player, string[] args)
{
if (args.Length == 0) return false;
char? entity = Parse.Char(args[0]);
if (entity != null)
{
foreach (IEntity item in player.Inventory)
{
if (entity == item.Identifier) return true;
}
}
return false;
}
// Put the trigger in the player's inventory.
public bool PickUp(Player player, string[] args)
{
IEntity entity = mGame.RemoveEntity(mTrigger);
if (entity != null)
{
player.Inventory.Add(entity);
return true;
}
return false;
}
// Drop an entity from the player's inventory here.
// Arg1: Entity identifier.
public bool Drop(Player player, string[] args)
{
if (args.Length == 0) return false;
char? entity = Parse.Char(args[0]);
if (entity != null)
{
foreach (IEntity item in player.Inventory)
{
if (entity == item.Identifier)
{
player.Inventory.Remove(item);
mGame.State.Entities.Add(item);
item.Coordinates = mTrigger.Coordinates;
return true;
}
}
}
return false;
}
// Use an entity in the player's inventory, disposing it.
// Arg1: Entity identifier.
public bool Use(Player player, string[] args)
{
if (args.Length == 0) return false;
char? entity = Parse.Char(args[0]);
if (entity != null)
{
foreach (IEntity item in player.Inventory)
{
if (entity == item.Identifier)
{
player.Inventory.Remove(item);
return true;
}
}
}
return false;
}
// Wait for a ceretain number of ticks.
// Arg1: Number of ticks.
public bool Wait(Player player, string[] args)
{
if (args.Length == 0) return false;
if (mTicks == 0)
{
int? timer = Parse.Integer(args[0]);
if (timer != null)
{
mTicks = 1;
mTimerTicks = timer.Value;
}
}
else if (++mTicks >= mTimerTicks)
{
mTicks = 0;
return true;
}
return false;
}
// Print each argument to the console as a string.
public bool Print(Player player, string[] args)
{
foreach (string arg in args)
{
string line = Parse.String(arg);
if (line != null) Console.WriteLine(line);
}
return true;
}
// Change a cell's tile on the map.
// Arg1: The coordinates.
// Arg2: The character representing the tile.
public bool Set(Player player, string[] args)
{
if (args.Length < 2) return false;
Point? coord = Parse.Coordinates(args[0]);
if (coord != null)
{
char? tile = Parse.Char(args[1]);
if (tile != null)
{
mGame.State.Map.SetCell(coord.Value, tile.Value);
return true;
}
}
return false;
}
// Move on to the next level.
public bool Next(Player player, string[] args)
{
mGame.AdvanceLevel();
return true;
}
// Restart the current level.
public bool Reset(Player player, string[] args)
{
mGame.Reset();
return true;
}
public Functions(IEntity trigger, Game game)
{
mTrigger = trigger;
mGame = game;
}
IEntity mTrigger;
Game mGame;
int mTicks;
int mTimerTicks;
}
#endregion
#region Private Variables
Script mScript;
TriggerOptions mFlags;
bool mIsFinished;
bool mIsExpired;
char mId;
Game mGame;
Point mCoordinates;
#endregion
}
}