public List<LocationOfInterest> GetInterestingLocations(Avatar observer)
		{
			List<LocationOfInterest> locationsOfInterest = new List<LocationOfInterest>();

			MapTile observerTile = _quest.GetAvatarMapTile(observer);
			Point observerLocation = _quest.Map.GetMapTileLocation(observerTile);
			PointList visibleLocations = _quest.Map.GetPointsWithinLineOfSightOf(observerLocation);

			//// Get a list of all actionable map tiles
			PointList interestingLocations = _quest.Map.GetActionableMapPoints(observer.Faction);
			
			// Filter out interesting locations that are not in the visible set
			PointList visibleInterestingLocations = interestingLocations.Intersects(visibleLocations);

			// Create paths to each of these points
			PathfindingNode observerNode = _quest.Map.GetPathfindingNodeForTile(observerTile);
			foreach (Point point in visibleInterestingLocations)
			{
				PathfindingNode pointNode = _quest.Map.GetPathfindingNodeForLocation(point.X, point.Y);
				List<PathfindingNode> path = _quest.Map.PathfindingGraph.FindRoute(observerNode, pointNode);
				if (path != null)
				{
					PointList pathSteps = new PointList();
					for (int i = 1; i < path.Count; i++)
					{ pathSteps.Add(_quest.Map.GetPointForPathfindingNode(path[i])); }

					LocationOfInterest interest = new LocationOfInterest(pathSteps);
					locationsOfInterest.Add(interest);
				}
			}

			return locationsOfInterest;
		}
		public MovementTurnStepAction(Avatar actor, PointList stepsToLocation, MapTile interestingLocation=null)
			: base(false)
		{
			_avatar = actor;
			_stepsToLocation = stepsToLocation;
			RequiresMovement = true;

			HasMoreTurns = (_stepsToLocation.Count > 1) ? true : false; // If there are more steps, then we can be used in subsequent turns!
			AcceptsAvatarFocus = HasMoreTurns;
		}
		override public TurnStepAction FindAction(Avatar currentAvatar, AvatarTurnState avatarTurnState, QuestAnalyzer mapAnalyzer, ChanceProvider chanceProvider)
		{
			List<AbstractTileAction> actionsForCurrentLocation = mapAnalyzer.GetActionsAtObserverLocation(currentAvatar);
			if (actionsForCurrentLocation.Count <= 0)
			{ return null; }

			AbstractTileAction tileAction = actionsForCurrentLocation[0];
			TurnStepAction action = new ActionableTurnStepAction(tileAction, currentAvatar);

			return action;
		}
		override public TurnStepAction FindAction(Avatar currentAvatar, AvatarTurnState avatarTurnState, QuestAnalyzer mapAnalyzer, ChanceProvider chanceProvider)
		{
			List<LocationOfInterest> interestingDestinations = mapAnalyzer.GetInterestingLocationsCheating(currentAvatar);
			if (interestingDestinations.Count <= 0)
			{ return null; }

			interestingDestinations = interestingDestinations.OrderBy(item => item.StepsToLocation).ToList();

			MovementTurnStepAction action = new MovementTurnStepAction(currentAvatar, interestingDestinations[0].StepsToLocation);
			return action;
		}
		override public TurnStepAction FindAction(Avatar currentAvatar, AvatarTurnState avatarTurnState, QuestAnalyzer mapAnalyzer, ChanceProvider chanceProvider)
		{
			PointList unwalkedTiles = mapAnalyzer.GetAdjacentUnvisitedLocations(currentAvatar);
			if (unwalkedTiles.Count <= 0)
			{ return null; }

			// Just pick the first tile, and see if that opens up any other actions...
			PointList path = new PointList() { unwalkedTiles[0] };

			MovementTurnStepAction action = new MovementTurnStepAction(currentAvatar, path);
			return action;
		}
		public QuestView(AbstractQuest quest, ChanceProvider chanceProvider, StoryTeller storyTeller)
		{
			InitializeComponent();

			_quest = quest;
			_chanceProvider = chanceProvider;
			_storyTeller = storyTeller;

			_turnTakers = new List<Avatar>();
			_currentTurnTaker = null;
			_currentTurnTakerIndex = -1;

			_turnTimer = new DispatcherTimer();
			_turnTimer.Interval = TimeSpan.FromMilliseconds(500);
			_turnTimer.Tick += OnTurnTimerTick;

			Loaded += OnLoaded;
		}
		public List<LocationOfInterest> GetInterestingLocationsCheating(Avatar observer)
		{
			List<LocationOfInterest> locationsOfInterest = new List<LocationOfInterest>();

			MapTile observerTile = _quest.GetAvatarMapTile(observer);
			Point observerLocation = _quest.Map.GetMapTileLocation(observerTile);
			PointList visibleLocations = _quest.Map.GetPointsWithinLineOfSightOf(observerLocation);

			//// Get a list of all actionable map tiles
			PointList interestingLocations = _quest.Map.GetActionableMapPoints(observer.Faction);

			// Find the closest location by straight-line distance.  It was too expensive to calculate Pathfinding distance.
			PathfindingNode observerNode = _quest.Map.GetPathfindingNodeForTile(observerTile);
			Point closestDistanceInterestingLocation = null;
			double closestDistance = float.MaxValue;
			foreach (Point point in interestingLocations)
			{
				double distance = Math.Sqrt(Math.Pow(observerLocation.X - point.X, 2) + Math.Pow(observerLocation.Y - point.Y, 2));
				if (distance < closestDistance)
				{
					closestDistanceInterestingLocation = point;
					closestDistance = distance;
				}
			}

			if (closestDistanceInterestingLocation != null)
			{
				PathfindingNode pointNode = _quest.Map.GetPathfindingNodeForLocation(closestDistanceInterestingLocation.X, closestDistanceInterestingLocation.Y);
				List<PathfindingNode> path = _quest.Map.PathfindingGraph.FindRoute(observerNode, pointNode);
				if (path != null)
				{
					PointList pathSteps = new PointList();
					for (int i = 1; i < path.Count; i++)
					{ pathSteps.Add(_quest.Map.GetPointForPathfindingNode(path[i])); }

					LocationOfInterest interest = new LocationOfInterest(pathSteps);
					locationsOfInterest.Add(interest);
					return locationsOfInterest;
				}
			}

			return locationsOfInterest;
		}
		public List<AbstractTileAction> GetActionsAtObserverLocation(Avatar observer)
		{
			MapTile observerTile = _quest.GetAvatarMapTile(observer);
			Point observerLocation = _quest.Map.GetMapTileLocation(observerTile);

			//// Get a list of all actionable map tiles
			PointList interestingLocations = _quest.Map.GetActionableMapPoints(observer.Faction);

			// Filter out interesting locations that are not in the visible set
			PointList observerLocations = new PointList();
			observerLocations.Add(observerLocation);
			PointList visibleInterestingLocations = interestingLocations.Intersects(observerLocations);

			List<AbstractTileAction> actions = new List<AbstractTileAction>();
			for (int i = 0; i < visibleInterestingLocations.Count; i++)
			{
				List<AbstractTileAction> actionsAtInterestingLocation = _quest.Map.GetActionsForPoint(observerLocation);
				foreach (AbstractTileAction actionAtInterestingLocation in actionsAtInterestingLocation)
				{ actions.Add(actionAtInterestingLocation); }
			}

			return actions;
		}
		public void SetAvatar(Avatar avatar)
		{ _avatar = avatar; }
		public List<Avatar> GetVisibleEnemies(Avatar observer)
		{
			List<Avatar> visibleEnemies = new List<Avatar>();

			MapTile observerMapTile = _quest.GetAvatarMapTile(observer);
			Point observerLocation = _quest.Map.GetMapTileLocation(observerMapTile);
			PointList visibleLocations = _quest.Map.GetPointsWithinLineOfSightOf(observerLocation);

			List<Avatar> allEnemies = _quest.GetEnemiesOfAvatar(observer);
			foreach (Avatar enemy in allEnemies)
			{
				MapTile enemyMapTile = _quest.GetAvatarMapTile(enemy);
				Point enemyPoint = _quest.Map.GetMapTileLocation(enemyMapTile);
				if (visibleLocations.ContainsLocation(enemyPoint.X, enemyPoint.Y))
				{ visibleEnemies.Add(enemy); }
			}
			return visibleEnemies;
		}
		public Boolean CouldBeEquipedBy(Avatar avatar)
		{ return true; }
		private void PerformNextTurnCycle()
		{
			_turnTimer.Stop();

			// Check to make sure there is a living hero left.  If not, stop the timer, and end the game.  
			// This has to be above all of the turn loops to make sure that the "Hero is dead" action comes up for each one.
			if (!_quest.AreAnyHeroesAlive)
			{
				if (HeroesLose != null)
				{ HeroesLose(this, new EventArgs()); }
			}
			else
			{
				TurnStepAction action = _currentTurnTaker.DoTakeTurnStep(_questAnalyzer, _chanceProvider);

				if (action == null) // The current player has no more steps to take
				{
					_currentTurnTakerIndex++;
					if (_currentTurnTakerIndex > _turnTakers.Count - 1)
					{ _currentTurnTakerIndex = 0; }
					_currentTurnTaker = _turnTakers[_currentTurnTakerIndex];
					_currentTurnTaker.StartTurn();
					PerformNextTurnCycle();
				}
				else
				{
					action.Complete += OnCurrentActionCommitComplete;
					action.Commit(_quest, _storyTeller);
				}

				RenderQuestBoard();
			}
		}
		private void BeginTurnCycle()
		{
			_storyTeller.StoryComplete -= OnQuestIntroductionStoryComplete;

			_turnTakers.Clear();
			foreach (Hero hero in _quest.Heroes)
			{ _turnTakers.Add(hero); }
			foreach (Monster monster in _quest.Monsters)
			{ _turnTakers.Add(monster); }

			// Make the first person in the list the current player
			_currentTurnTakerIndex = 0;
			_currentTurnTaker = _turnTakers[_currentTurnTakerIndex];
			_currentTurnTaker.StartTurn();

			_questAnalyzer = new QuestAnalyzer(_quest);
			PerformNextTurnCycle(); // Immediately take one turn
		}
		public List<Avatar> GetAdjacentEnemies(Avatar observer, Boolean includeDiagonalTiles)
		{
			List<Avatar> adjacentEnemies = new List<Avatar>();

			MapTile observerMapTile = _quest.GetAvatarMapTile(observer);
			Point observerLocation = _quest.Map.GetMapTileLocation(observerMapTile);

			double minimumDistance = includeDiagonalTiles ? Math.Sqrt(2) : 1;
			List<Avatar> allEnemies = _quest.GetEnemiesOfAvatar(observer);
			foreach (Avatar enemy in allEnemies)
			{
				MapTile enemyMapTile = _quest.GetAvatarMapTile(enemy);
				Point enemyPoint = _quest.Map.GetMapTileLocation(enemyMapTile);
				double distance = Math.Sqrt(Math.Pow(enemyPoint.X - observerLocation.X, 2) + Math.Pow(enemyPoint.Y - observerLocation.Y, 2));
				if (distance <= minimumDistance)
				{ adjacentEnemies.Add(enemy); }
			}

			return adjacentEnemies;
		}
		public ConfusedTurnStepAction(Avatar actor)
			: base(false)
		{
			_actor = actor;
		}
		public virtual TurnStepAction FindAction(Avatar currentAvatar, AvatarTurnState avatarTurnState, QuestAnalyzer mapAnalyzer, ChanceProvider chanceProvider)
		{ return null; } // Override in subclasses
		public ActionableTurnStepAction(AbstractTileAction tileAction, Avatar avatar):base(false)
		{
			_tileAction = tileAction;
			_avatar = avatar;
		}
		override public TurnStepAction FindAction(Avatar currentAvatar, AvatarTurnState avatarTurnState, QuestAnalyzer mapAnalyzer, ChanceProvider chanceProvider)
		{
			List<Avatar> enemies = mapAnalyzer.GetAdjacentEnemies(currentAvatar, currentAvatar.CanAttackAdjacent);

			return null;
		}
		public DeadTurnStepAction(Avatar actor)
			: base(false)
		{
			_actor = actor;
		}
		public PointList GetAdjacentUnvisitedLocations(Avatar observer)
		{
			MapTile observerTile = _quest.GetAvatarMapTile(observer);
			Point observerLocation = _quest.Map.GetMapTileLocation(observerTile);
			PointList points = _quest.Map.GetAdjacentUnwalkedTiles(observerLocation, observer.Faction);

			// Favor points in the direction of the Avatars' movement vector
			Point desiredPoint = new Point(
				observerLocation.X + observer.movementVector.X,
				observerLocation.Y + observer.movementVector.Y
			);

			if (!points.ContainsLocation(desiredPoint.X, desiredPoint.Y))
			{ return points; }

			PointList match = new PointList() { desiredPoint };
			points = points.Intersects(match);

			return points;
		}