/// <summary> /// Recalculate the players FOV. Subsequent accesses to the TCODMap of the player's level will have his FOV /// Note that the maps may get hijacked by other creatures /// </summary> internal void CalculatePlayerFOV() { //Get TCOD to calculate the player's FOV Map currentMap = levels[Player.LocationLevel]; TCODFov tcodFOV = levelTCODMaps[Player.LocationLevel]; tcodFOV.CalculateFOV(Player.LocationMap.x, Player.LocationMap.y, Player.SightRadius); //Set the FOV flags on the map //Process the whole level, which effectively resets out-of-FOV areas for (int i = 0; i < currentMap.width; i++) { for (int j = 0; j < currentMap.height; j++) { MapSquare thisSquare = currentMap.mapSquares[i, j]; thisSquare.InPlayerFOV = tcodFOV.CheckTileFOV(i, j); //Set 'has ever been seen flag' if appropriate if (thisSquare.InPlayerFOV == true) { thisSquare.SeenByPlayer = true; } } } }
private static void PaintFOVTest(RootConsole console, int x, int y, TCODFov fov) { fov.CalculateFOV(x, y, 3, false, FovAlgorithm.Basic); for (int i = 0; i < 5; ++i) //width { for (int j = 0; j < 5; ++j) //height { if (room[j, i] == '.') { if (fov.CheckTileFOV(i, j)) { console.PutChar(i, j, '.'); } else { console.PutChar(i, j, '~'); } } else { console.PutChar(i, j, '#'); } } } console.PutChar(x, y, '@'); console.Flush(); }
/// <summary> /// Run the Simple AI actions /// </summary> public override void ProcessTurn() { //If in pursuit state, continue to pursue enemy until it is dead (or creature itself is killed) [no FOV used after initial target selected] //If in randomWalk state, look for new enemies in FOV. //Closest enemy becomes new target //If no targets, move randomly Random rand = Game.Random; if (AIState == SimpleAIStates.Pursuit) { //Pursuit state, continue chasing and attacking target //Is target yet living? if (currentTarget.Alive == false) { //If not, go to non-chase state AIState = SimpleAIStates.RandomWalk; } //Is target on another level (i.e. has escaped down the stairs) else if (currentTarget.LocationLevel != this.LocationLevel) { AIState = SimpleAIStates.RandomWalk; } else { //Otherwise continue to chase ChaseCreature(currentTarget); } } if (AIState == SimpleAIStates.RandomWalk) { //RandomWalk state //Search an area of sightRadius on either side for creatures and check they are in the FOV Map currentMap = Game.Dungeon.Levels[LocationLevel]; //Get the FOV from Dungeon (this also updates the map creature FOV state) TCODFov currentFOV = Game.Dungeon.CalculateCreatureFOV(this); //currentFOV.CalculateFOV(LocationMap.x, LocationMap.y, SightRadius); //Check for other creatures within this creature's FOV int xl = LocationMap.x - SightRadius; int xr = LocationMap.x + SightRadius; int yt = LocationMap.y - SightRadius; int yb = LocationMap.y + SightRadius; //If sight is infinite, check all the map if (SightRadius == 0) { xl = 0; xr = currentMap.width; yt = 0; yb = currentMap.height; } if (xl < 0) { xl = 0; } if (xr >= currentMap.width) { xr = currentMap.width - 1; } if (yt < 0) { yt = 0; } if (yb >= currentMap.height) { yb = currentMap.height - 1; } //List will contain monsters & player List <Creature> creaturesInFOV = new List <Creature>(); foreach (Monster monster in Game.Dungeon.Monsters) { //Same monster if (monster == this) { continue; } //Not on the same level if (monster.LocationLevel != this.LocationLevel) { continue; } //Not in FOV if (!currentFOV.CheckTileFOV(monster.LocationMap.x, monster.LocationMap.y)) { continue; } //Otherwise add to list of possible targets creaturesInFOV.Add(monster); LogFile.Log.LogEntryDebug(this.Representation + " spots " + monster.Representation, LogDebugLevel.Medium); } //Check PC if (Game.Dungeon.Player.LocationLevel == this.LocationLevel) { if (currentFOV.CheckTileFOV(Game.Dungeon.Player.LocationMap.x, Game.Dungeon.Player.LocationMap.y)) { creaturesInFOV.Add(Game.Dungeon.Player); LogFile.Log.LogEntryDebug(this.Representation + " spots " + Game.Dungeon.Player.Representation, LogDebugLevel.Medium); } } //If there are possible targets, find the closest and chase it //Otherwise continue to move randomly if (creaturesInFOV.Count > 0) { //Find the closest creature Creature closestCreature = null; double closestDistance = Double.MaxValue; //a long way foreach (Creature creature in creaturesInFOV) { double distanceSq = Math.Pow(creature.LocationMap.x - this.LocationMap.x, 2) + Math.Pow(creature.LocationMap.y - this.LocationMap.y, 2); double distance = Math.Sqrt(distanceSq); if (distance < closestDistance) { closestDistance = distance; closestCreature = creature; } } //Start chasing this creature LogFile.Log.LogEntryDebug(this.Representation + " chases " + closestCreature.Representation, LogDebugLevel.Medium); ChaseCreature(closestCreature); } else { //Move randomly. If we walk into something attack it, but it does not become a new target int direction = rand.Next(9); int moveX = 0; int moveY = 0; moveX = direction / 3 - 1; moveY = direction % 3 - 1; //If we're not moving quit at this point, otherwise the target square will be the one we're in if (moveX == 0 && moveY == 0) { return; } //Check this is a valid move bool validMove = false; Point newLocation = new Point(LocationMap.x + moveX, LocationMap.y + moveY); validMove = Game.Dungeon.MapSquareCanBeEntered(LocationLevel, newLocation); //Give up if this is not a valid move if (!validMove) { return; } //Check if the square is occupied by a PC or monster SquareContents contents = Game.Dungeon.MapSquareContents(LocationLevel, newLocation); bool okToMoveIntoSquare = false; if (contents.empty) { okToMoveIntoSquare = true; } if (contents.player != null) { //Attack the player CombatResults result = AttackPlayer(contents.player); if (result == CombatResults.DefenderDied) { //Bad news for the player here! okToMoveIntoSquare = true; } } if (contents.monster != null) { //Attack the monster CombatResults result = AttackMonster(contents.monster); if (result == CombatResults.DefenderDied) { okToMoveIntoSquare = true; } } //Move if allowed if (okToMoveIntoSquare) { LocationMap = newLocation; } } } }
/// <summary> /// Displays the creature FOV on the map. Note that this clobbers the FOV map /// </summary> /// <param name="creature"></param> public void ShowCreatureFOVOnMap(Creature creature) { //Only do this if the creature is on a visible level if (creature.LocationLevel != Player.LocationLevel) { return; } Map currentMap = levels[creature.LocationLevel]; TCODFov tcodFOV = levelTCODMaps[creature.LocationLevel]; //Calculate FOV tcodFOV.CalculateFOV(creature.LocationMap.x, creature.LocationMap.y, creature.SightRadius); //Only check sightRadius around the creature int xl = creature.LocationMap.x - creature.SightRadius; int xr = creature.LocationMap.x + creature.SightRadius; int yt = creature.LocationMap.y - creature.SightRadius; int yb = creature.LocationMap.y + creature.SightRadius; //If sight is infinite, check all the map if (creature.SightRadius == 0) { xl = 0; xr = currentMap.width; yt = 0; yb = currentMap.height; } if (xl < 0) { xl = 0; } if (xr >= currentMap.width) { xr = currentMap.width - 1; } if (yt < 0) { yt = 0; } if (yb >= currentMap.height) { yb = currentMap.height - 1; } for (int i = xl; i <= xr; i++) { for (int j = yt; j <= yb; j++) { MapSquare thisSquare = currentMap.mapSquares[i, j]; bool inFOV = tcodFOV.CheckTileFOV(i, j); if (inFOV) { thisSquare.InMonsterFOV = true; } } } }