Skip to content

Commit

Permalink
Check map composition for pathfinding skills
Browse files Browse the repository at this point in the history
  • Loading branch information
idshibanov committed Apr 25, 2024
1 parent 278e43f commit 906ceeb
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 12 deletions.
1 change: 1 addition & 0 deletions src/fheroes2/ai/normal/ai_normal.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "mp2.h"
#include "pairs.h"
#include "resource.h"
#include "skill.h"
#include "world_pathfinding.h"

class Castle;
Expand Down
27 changes: 17 additions & 10 deletions src/fheroes2/ai/normal/ai_normal_hero.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -916,14 +916,21 @@ namespace
}
return 1000.0;
}
case Skill::Secondary::PATHFINDING:
// TODO: check map composition
return 250.0;
case Skill::Secondary::NAVIGATION:
// TODO: check map composition
return 0.0;
case Skill::Secondary::SCOUTING:
return hero.getAIRole() == Heroes::Role::SCOUT ? 1250.0 : 0.0;
case Skill::Secondary::PATHFINDING: {
const double roughness = world.getLandRoughness();
return ( roughness > 1.25 ) ? 1000.0 : ( roughness > 1.1 ) ? 250.0 : 100.0;
}
case Skill::Secondary::NAVIGATION: {
const double waterPercentage = world.getWaterPercentage();
return ( waterPercentage > 0.6 ) ? 1000.0 : ( waterPercentage > 0.25 ) ? 100.0 : 0.0;
}
case Skill::Secondary::SCOUTING: {
const Heroes::Role role = hero.getAIRole();
if ( role == Heroes::Role::CHAMPION || role == Heroes::Role::FIGHTER ) {
return 0.0;
}
return hero.getAIRole() == Heroes::Role::SCOUT ? 1250.0 : 100.0;
}
case Skill::Secondary::MYSTICISM:
return hero.HaveSpellBook() ? 500.0 : 100.0;
case Skill::Secondary::EAGLE_EYE:
Expand Down Expand Up @@ -2553,14 +2560,14 @@ namespace AI
}
}

Skill::Secondary AI::Normal::pickSecondarySkill( const Heroes & hero, const Skill::Secondary & left, const Skill::Secondary & right )
Skill::Secondary Normal::pickSecondarySkill( const Heroes & hero, const Skill::Secondary & left, const Skill::Secondary & right )
{
// heroes can get 1 or 0 skill choices depending on a level
if ( !right.isValid() ) {
// if both left and right are invalid returning either is fine
return left;
}
DEBUG_LOG( DBG_AI, DBG_WARN,
DEBUG_LOG( DBG_AI, DBG_TRACE,
hero.GetName() << " picking a skill: " << getSecondarySkillValue( hero, left ) << " for " << left.String( left.first ) << " and "
<< getSecondarySkillValue( hero, right ) << " for " << right.String( right.first ) )

Expand Down
10 changes: 10 additions & 0 deletions src/fheroes2/world/world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1278,6 +1278,16 @@ uint32_t World::CheckKingdomLoss( const Kingdom & kingdom ) const
return GameOver::COND_NONE;
}

double World::getWaterPercentage() const
{
return waterPercentage;
}

double World::getLandRoughness() const
{
return mapRoughness;
}

uint32_t World::getDistance( const Heroes & hero, int targetIndex )
{
_pathfinder.reEvaluateIfNeeded( hero );
Expand Down
4 changes: 4 additions & 0 deletions src/fheroes2/world/world.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,8 @@ class World : protected fheroes2::Size
void RemoveMapObject( const MapObjectSimple * );
const MapRegion & getRegion( size_t id ) const;
size_t getRegionCount() const;
double getWaterPercentage() const;
double getLandRoughness() const;

uint32_t getDistance( const Heroes & hero, int targetIndex );
std::list<Route::Step> getPath( const Heroes & hero, int targetIndex );
Expand Down Expand Up @@ -410,6 +412,8 @@ class World : protected fheroes2::Size
std::map<uint8_t, Maps::Indexes> _allTeleports; // All indexes of tiles that contain stone liths of a certain type (sprite index)
std::map<uint8_t, Maps::Indexes> _allWhirlpools; // All indexes of tiles that contain a certain part (sprite index) of the whirlpool

double waterPercentage = 0.0;
double mapRoughness = 0.0;
std::vector<MapRegion> _regions;
PlayerWorldPathfinder _pathfinder;
};
Expand Down
18 changes: 16 additions & 2 deletions src/fheroes2/world/world_regions.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/***************************************************************************
* fheroes2: https://github.com/ihhub/fheroes2 *
* Copyright (C) 2020 - 2023 *
* Copyright (C) 2020 - 2024 *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
Expand All @@ -18,6 +18,8 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/

#include "world_regions.h"

#include <algorithm>
#include <cstddef>
#include <cstdint>
Expand All @@ -27,12 +29,12 @@
#include <vector>

#include "castle.h"
#include "ground.h"
#include "maps.h"
#include "maps_tiles.h"
#include "math_base.h"
#include "mp2.h"
#include "world.h"
#include "world_regions.h"

namespace
{
Expand Down Expand Up @@ -200,6 +202,10 @@ void World::ComputeStaticAnalysis()
obstacles[3].emplace_back( y, 0 ); // ground, rows
}

int obstacleCount = 0;
int waterCount = 0;
double terrainPenalty = 0;

// Find the terrain
for ( int y = 0; y < height; ++y ) {
const int rowIndex = y * width;
Expand All @@ -208,24 +214,32 @@ void World::ComputeStaticAnalysis()
const Maps::Tiles & tile = vec_tiles[index];
// If tile is blocked (mountain, trees, etc) then it's applied to both
if ( tile.GetPassable() == 0 ) {
++obstacleCount;
++obstacles[0][x].second;
++obstacles[1][y].second;
++obstacles[2][x].second;
++obstacles[3][y].second;
}
else if ( tile.isWater() ) {
++waterCount;
// if it's water then ground tiles consider it an obstacle
++obstacles[2][x].second;
++obstacles[3][y].second;
}
else {
// > Maps::Ground::defaultGroundPenalty
terrainPenalty += Maps::Ground::GetPenalty( tile, 0 );
// else then ground is an obstacle for water navigation
++obstacles[0][x].second;
++obstacles[1][y].second;
}
}
}

const double passableTileCount = ( width * height ) - obstacleCount;
waterPercentage = waterCount / passableTileCount;
mapRoughness = terrainPenalty / ( ( passableTileCount - waterCount ) * Maps::Ground::defaultGroundPenalty );

// sort the map rows and columns based on amount of obstacles
for ( int i = 0; i < 4; ++i )
std::sort( obstacles[i].begin(), obstacles[i].end(), []( const TileData & left, const TileData & right ) { return left.second < right.second; } );
Expand Down

0 comments on commit 906ceeb

Please sign in to comment.