2021-05-15 18:22:44 +02:00
/*
* FuzzyHelper . cpp , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
2021-05-16 13:55:57 +02:00
# include "../StdInc.h"
2021-05-15 18:22:44 +02:00
# include "FuzzyHelper.h"
2021-05-16 13:55:57 +02:00
# include "../Goals/Goals.h"
2020-05-04 17:58:43 +02:00
# include "Nullkiller.h"
2021-05-15 18:22:44 +02:00
2023-06-02 20:47:37 +02:00
# include "../../../lib/mapObjectConstructors/AObjectTypeHandler.h"
# include "../../../lib/mapObjectConstructors/CObjectClassesHandler.h"
2023-06-06 17:32:53 +02:00
# include "../../../lib/mapObjectConstructors/CBankInstanceConstructor.h"
2023-06-02 20:47:37 +02:00
2022-09-26 20:01:07 +02:00
namespace NKAI
{
2021-05-15 18:22:44 +02:00
ui64 FuzzyHelper : : estimateBankDanger ( const CBank * bank )
{
//this one is not fuzzy anymore, just calculate weighted average
auto objectInfo = VLC - > objtypeh - > getHandlerFor ( bank - > ID , bank - > subID ) - > getObjectInfo ( bank - > appearance ) ;
CBankInfo * bankInfo = dynamic_cast < CBankInfo * > ( objectInfo . get ( ) ) ;
ui64 totalStrength = 0 ;
ui8 totalChance = 0 ;
for ( auto config : bankInfo - > getPossibleGuards ( ) )
{
totalStrength + = config . second . totalStrength * config . first ;
totalChance + = config . first ;
}
return totalStrength / std : : max < ui8 > ( totalChance , 1 ) ; //avoid division by zero
}
2022-09-26 20:01:07 +02:00
ui64 FuzzyHelper : : evaluateDanger ( const int3 & tile , const CGHeroInstance * visitor , bool checkGuards )
2021-05-15 18:22:44 +02:00
{
2020-05-04 17:58:43 +02:00
auto cb = ai - > cb . get ( ) ;
2021-05-15 18:22:44 +02:00
const TerrainTile * t = cb - > getTile ( tile , false ) ;
if ( ! t ) //we can know about guard but can't check its tile (the edge of fow)
return 190000000 ; //MUCH
ui64 objectDanger = 0 ;
ui64 guardDanger = 0 ;
auto visitableObjects = cb - > getVisitableObjs ( tile ) ;
// in some scenarios hero happens to be "under" the object (eg town). Then we consider ONLY the hero.
if ( vstd : : contains_if ( visitableObjects , objWithID < Obj : : HERO > ) )
{
vstd : : erase_if ( visitableObjects , [ ] ( const CGObjectInstance * obj )
{
return ! objWithID < Obj : : HERO > ( obj ) ;
} ) ;
}
if ( const CGObjectInstance * dangerousObject = vstd : : backOrNull ( visitableObjects ) )
{
2020-05-04 17:58:43 +02:00
objectDanger = evaluateDanger ( dangerousObject ) ; //unguarded objects can also be dangerous or unhandled
2021-05-15 18:22:44 +02:00
if ( objectDanger )
{
//TODO: don't downcast objects AI shouldn't know about!
auto armedObj = dynamic_cast < const CArmedInstance * > ( dangerousObject ) ;
if ( armedObj )
{
float tacticalAdvantage = tacticalAdvantageEngine . getTacticalAdvantage ( visitor , armedObj ) ;
objectDanger * = tacticalAdvantage ; //this line tends to go infinite for allied towns (?)
}
}
if ( dangerousObject - > ID = = Obj : : SUBTERRANEAN_GATE )
{
//check guard on the other side of the gate
2020-05-04 17:58:43 +02:00
auto it = ai - > memory - > knownSubterraneanGates . find ( dangerousObject ) ;
if ( it ! = ai - > memory - > knownSubterraneanGates . end ( ) )
2021-05-15 18:22:44 +02:00
{
auto guards = cb - > getGuardingCreatures ( it - > second - > visitablePos ( ) ) ;
2020-05-04 17:58:43 +02:00
2021-05-15 18:22:44 +02:00
for ( auto cre : guards )
{
2020-05-04 17:58:43 +02:00
float tacticalAdvantage = tacticalAdvantageEngine . getTacticalAdvantage (
visitor ,
dynamic_cast < const CArmedInstance * > ( cre ) ) ;
2021-05-15 18:22:44 +02:00
2020-05-04 17:58:43 +02:00
vstd : : amax ( guardDanger , evaluateDanger ( cre ) * tacticalAdvantage ) ;
2021-05-15 18:22:44 +02:00
}
}
}
}
2021-05-16 13:19:00 +02:00
if ( checkGuards )
2021-05-15 18:22:44 +02:00
{
2021-05-16 13:19:00 +02:00
auto guards = cb - > getGuardingCreatures ( tile ) ;
for ( auto cre : guards )
{
float tacticalAdvantage = tacticalAdvantageEngine . getTacticalAdvantage ( visitor , dynamic_cast < const CArmedInstance * > ( cre ) ) ;
2021-05-15 18:22:44 +02:00
2020-05-04 17:58:43 +02:00
vstd : : amax ( guardDanger , evaluateDanger ( cre ) * tacticalAdvantage ) ; //we are interested in strongest monster around
2021-05-16 13:19:00 +02:00
}
2021-05-15 18:22:44 +02:00
}
//TODO mozna odwiedzic blockvis nie ruszajac straznika
return std : : max ( objectDanger , guardDanger ) ;
}
2020-05-04 17:58:43 +02:00
ui64 FuzzyHelper : : evaluateDanger ( const CGObjectInstance * obj )
2021-05-15 18:22:44 +02:00
{
2020-05-04 17:58:43 +02:00
auto cb = ai - > cb . get ( ) ;
2021-05-15 18:22:44 +02:00
if ( obj - > tempOwner < PlayerColor : : PLAYER_LIMIT & & cb - > getPlayerRelations ( obj - > tempOwner , ai - > playerID ) ! = PlayerRelations : : ENEMIES ) //owned or allied objects don't pose any threat
return 0 ;
switch ( obj - > ID )
{
case Obj : : TOWN :
{
2023-03-05 15:42:15 +02:00
const CGTownInstance * town = dynamic_cast < const CGTownInstance * > ( obj ) ;
auto danger = town - > getUpperArmy ( ) - > getArmyStrength ( ) ;
if ( danger | | town - > visitingHero )
{
auto fortLevel = town - > fortLevel ( ) ;
if ( fortLevel = = CGTownInstance : : EFortLevel : : CASTLE )
danger + = 10000 ;
else if ( fortLevel = = CGTownInstance : : EFortLevel : : CITADEL )
danger + = 4000 ;
}
return danger ;
2021-05-15 18:22:44 +02:00
}
2023-03-11 11:42:44 +02:00
2021-05-16 13:22:41 +02:00
case Obj : : ARTIFACT :
case Obj : : RESOURCE :
{
2020-05-04 17:58:43 +02:00
if ( ! vstd : : contains ( ai - > memory - > alreadyVisited , obj ) )
2021-05-16 13:22:41 +02:00
return 0 ;
2023-04-10 16:44:41 +02:00
[[fallthrough]] ;
2021-05-16 13:22:41 +02:00
}
2021-05-15 18:22:44 +02:00
case Obj : : MONSTER :
2021-05-16 13:15:12 +02:00
case Obj : : HERO :
case Obj : : GARRISON :
case Obj : : GARRISON2 :
2021-05-15 18:22:44 +02:00
case Obj : : CREATURE_GENERATOR1 :
case Obj : : CREATURE_GENERATOR4 :
case Obj : : MINE :
case Obj : : ABANDONED_MINE :
2023-03-13 19:58:44 +02:00
case Obj : : PANDORAS_BOX :
2021-05-15 18:22:44 +02:00
case Obj : : CRYPT : //crypt
case Obj : : CREATURE_BANK : //crebank
case Obj : : DRAGON_UTOPIA :
case Obj : : SHIPWRECK : //shipwreck
case Obj : : DERELICT_SHIP : //derelict ship
2023-07-30 10:33:52 +02:00
{
const CArmedInstance * a = dynamic_cast < const CArmedInstance * > ( obj ) ;
return a - > getArmyStrength ( ) ;
}
2021-05-15 18:22:44 +02:00
case Obj : : PYRAMID :
{
if ( obj - > subID = = 0 )
return estimateBankDanger ( dynamic_cast < const CBank * > ( obj ) ) ;
else
return 0 ;
}
default :
return 0 ;
}
2022-09-26 20:01:07 +02:00
}
}