public void IsWalkableReturnsTrueForWalkableTiles() { File.WriteAllText("data/config.json", "{ 'PuzzlePushProbability': 0 }"); new Config("data/config.json"); var floor = new CaveFloorMap(MapWidth, MapHeight); var foundFloor = false; var foundWall = false; // There must be at least one walkable tile and one non-walkable tile, based on the current generation strategy for (var x = 0; x < MapWidth; x++) { for (var y = 0; y < MapHeight; y++) { var walkable = floor.IsWalkable(x, y); if (walkable) { foundFloor = true; } else { foundWall = true; } } } Assert.That(foundFloor, Is.EqualTo(true)); Assert.That(foundWall, Is.EqualTo(true)); }
private void MoveTowardsGoal() { if (this.X == this.goal.X && this.Y == this.goal.Y) { this.goal = map.FindEmptyPosition(); this.goalMap = this.CreateGoalMap(); } var path = goalMap.FindPath(this.X, this.Y); if (path != null) { var now = path.Steps.First(); var nextStep = path.Steps.Skip(1).FirstOrDefault(); if (nextStep != null && map.IsWalkable(nextStep.X, nextStep.Y)) { this.Move(nextStep.X, nextStep.Y); } else { // Pick a new goal next time this.goal = new Point(this.X, this.Y); } } else { // No path to goal... Pick a new goal next time this.goal = new Point(this.X, this.Y); } }
private void MovePlayerBy(Point amount, KeyboardInfo info = null) { var stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); var currentFieldOfView = new RogueSharp.FieldOfView(this.currentMap.GetIMap()); var playerView = this.objects.Single(g => g.Name == "Player"); var fovTiles = currentFieldOfView.ComputeFov(playerView.Position.X, playerView.Position.Y, Config.Instance.Get <int>("PlayerLightRadius"), true); this.MarkCurrentFovAsDiscovered(fovTiles); foreach (var obj in this.objects) { obj.IsVisible = false; } // Undo monster vision tile effect foreach (var monsterView in this.objects.Where(o => o.Data is Monster)) { var data = monsterView.Data as Monster; var monsterFov = currentFieldOfView.ComputeFov(data.X, data.Y, data.VisionSize, true); // If we can see them, they're discovered foreach (var cell in monsterFov) { if (this.discoveredTiles.ContainsKey($"{cell.X}, {cell.Y}")) { this[cell.X, cell.Y].ApplyEffect(DiscoveredEffect); } else { this[cell.X, cell.Y].ApplyEffect(HiddenEffect); } } } // Get the position the player will be at Point newPosition = playerView.Position + amount; // Is there a block there? if (currentMap.GetObjectsAt(newPosition.X, newPosition.Y).Any(e => e is Pushable)) { // Is there an empty space behind it? var behindBlock = newPosition + amount; if (currentMap.IsWalkable(behindBlock.X, behindBlock.Y)) { // Push it (update data) var obj = currentMap.GetObjectsAt(newPosition.X, newPosition.Y).Single(e => e is Pushable); obj.Move(behindBlock.X, behindBlock.Y); // Push it (move view object) this.objects.Single(g => g.Data == obj).Move(behindBlock.X, behindBlock.Y); this.CheckIfBlockPuzzleIsComplete(); } } // Check to see if the position is within the map and walkable if (new Rectangle(0, 0, Width, Height).Contains(newPosition) && currentMap.IsWalkable(newPosition.X, newPosition.Y)) { // Pull a block along if specified if (info.KeysDown.Contains(AsciiKey.Get(Keys.Space))) { // Are you holding space? Did you move in a direction (eg. left) and there's a push block on the other side (eg. right)? // If so, and if the target block position is walkable, pull it along. But this only works if you're pulling // in the direction you're moving (eg. standing on top and pulling a block upward), NOT standing beside a block // and pulling it upward or standing above a block and pulling to the left/right var currentBlockPos = playerView.Position + new Point(amount.X * -1, amount.Y * -1); if (currentMap.GetObjectsAt(currentBlockPos.X, currentBlockPos.Y).Any(e => e is Pullable)) { // Given constraints above, target position is current player position var obj = currentMap.GetObjectsAt(currentBlockPos.X, currentBlockPos.Y).Single(e => e is Pullable); obj.Move(playerView.Position.X, playerView.Position.Y); this.objects.Single(g => g.Data == obj).Move(playerView.Position.X, playerView.Position.Y); this.CheckIfBlockPuzzleIsComplete(); } } // Move the player playerView.Position += amount; playerView.Data.Move(playerView.Position.X, playerView.Position.Y); CenterViewToPlayer(); } var key = this.currentMap.GetObjectsAt(playerView.Position.X, playerView.Position.Y).Where(s => s is Key).SingleOrDefault(); if (key != null) { // Not sure why two keys are spawned here var keys = this.objects.Where(s => s.Data == key).ToList(); foreach (var k in keys) { this.objects.Remove(k); this.currentMap.Remove(key); } (this.objects.Single(o => o.Data is Player).Data as Player).Keys += 1; this.showMessageCallback("Got a key."); } // Door there, and we have a key? Unlock it! if ((playerView.Data as Player).Keys > 0 && this.currentMap.GetObjectsAt(newPosition.X, newPosition.Y).Any(o => o is LockedDoor)) { var doorData = this.currentMap.GetObjectsAt(newPosition.X, newPosition.Y).Where(o => o is LockedDoor).ToList(); var doors = this.objects.Where(o => doorData.Contains(o.Data)).ToList(); // Why, why WHY are there multiple copies? foreach (var door in doors) { this.objects.Remove(door); this.currentMap.Remove(door.Data); } showMessageCallback("You unlock the door."); (playerView.Data as Player).Keys -= 1; } fovTiles = currentFieldOfView.ComputeFov(playerView.Position.X, playerView.Position.Y, Config.Instance.Get <int>("PlayerLightRadius"), true); this.MarkCurrentFovAsVisible(fovTiles); // Monsters turn. Also, draw their field-of-view. Keep queuing turns until it's the player's turn again. var monstersToMove = new List <IHasAgility>(); IHasAgility next = null; while (next != playerView.Data) { if (next != null) { monstersToMove.Add(next); } next = turnCalculator.NextTurn(); } while (monstersToMove.Any()) { var m = monstersToMove[0]; monstersToMove.RemoveAt(0); var monsterView = this.objects.Single(o => o.Data is Monster && o.Data == m); var data = monsterView.Data as Monster; var hurtPlayer = data.MoveWithAi(playerView.Data as Player); if (hurtPlayer) { if ((playerView.Data as Player).IsDead) { showMessageCallback("The monster hits you! You die ..."); this.gameOver = true; } else { showMessageCallback("Monster hits you!"); } } else { monsterView.Position = new Point(data.X, data.Y); bool sawPlayer = false; var monsterFov = currentFieldOfView.ComputeFov(data.X, data.Y, data.VisionSize, true); foreach (var cell in monsterFov) { if (fovTiles.Any(f => f.X == data.X && f.Y == data.Y)) { this[cell.X, cell.Y].ApplyEffect(MonsterVisionEffect); if (playerView.Position.X == cell.X && playerView.Position.Y == cell.Y) { data.HuntPlayer(); monsterView.RenderCells.First().ActualForeground = new Color(255, 0, 0); sawPlayer = true; } } else { if (this.discoveredTiles.ContainsKey($"{data.X}, {data.Y}")) { this[cell.X, cell.Y].ApplyEffect(DiscoveredEffect); } else { this[cell.X, cell.Y].ApplyEffect(HiddenEffect); } } } if (!sawPlayer && monsterView.RenderCells.First().ActualForeground.R == 255) { monsterView.RenderCells.First().ActualForeground = new Color(data.Colour.R, data.Colour.G, data.Colour.B); } } } stopwatch.Stop(); var elapsed = stopwatch.Elapsed.TotalSeconds; Console.WriteLine($"Moving took {elapsed}s"); }