1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
/*
* 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
*
*/
#include "../StdInc.h"
#include "FuzzyHelper.h"
#include "../Goals/Goals.h"
#include "Nullkiller.h"
#include "../../../lib/mapObjectConstructors/AObjectTypeHandler.h"
#include "../../../lib/mapObjectConstructors/CObjectClassesHandler.h"
#include "../../../lib/mapObjectConstructors/CBankInstanceConstructor.h"
namespace NKAI
{
ui64 FuzzyHelper::evaluateDanger(const int3 & tile, const CGHeroInstance * visitor, bool checkGuards)
{
auto cb = ai->cb.get();
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) -> bool
{
return !objWithID<Obj::HERO>(obj);
});
}
if(const CGObjectInstance * dangerousObject = vstd::backOrNull(visitableObjects))
{
objectDanger = evaluateDanger(dangerousObject); //unguarded objects can also be dangerous or unhandled
if(objWithID<Obj::HERO>(dangerousObject))
{
auto hero = dynamic_cast<const CGHeroInstance *>(dangerousObject);
if(hero->visitedTown && !hero->visitedTown->garrisonHero)
{
objectDanger += evaluateDanger(hero->visitedTown.get());
}
objectDanger *= ai->heroManager->getFightingStrengthCached(hero);
}
if (objWithID<Obj::TOWN>(dangerousObject))
{
auto town = dynamic_cast<const CGTownInstance*>(dangerousObject);
auto hero = town->garrisonHero;
if (hero)
objectDanger *= ai->heroManager->getFightingStrengthCached(hero);
}
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
auto it = ai->memory->knownSubterraneanGates.find(dangerousObject);
if(it != ai->memory->knownSubterraneanGates.end())
{
auto guards = cb->getGuardingCreatures(it->second->visitablePos());
for(auto cre : guards)
{
float tacticalAdvantage = tacticalAdvantageEngine.getTacticalAdvantage(
visitor,
dynamic_cast<const CArmedInstance *>(cre));
vstd::amax(guardDanger, evaluateDanger(cre) * tacticalAdvantage);
}
}
}
}
if(checkGuards)
{
auto guards = cb->getGuardingCreatures(tile);
for(auto cre : guards)
{
float tacticalAdvantage = tacticalAdvantageEngine.getTacticalAdvantage(visitor, dynamic_cast<const CArmedInstance *>(cre));
vstd::amax(guardDanger, evaluateDanger(cre) * tacticalAdvantage); //we are interested in strongest monster around
}
}
//TODO mozna odwiedzic blockvis nie ruszajac straznika
return std::max(objectDanger, guardDanger);
}
ui64 FuzzyHelper::evaluateDanger(const CGObjectInstance * obj)
{
auto cb = ai->cb.get();
if(obj->tempOwner.isValidPlayer() && 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:
{
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 = std::max(danger * 2, danger + 10000);
else if(fortLevel == CGTownInstance::EFortLevel::CITADEL)
danger = std::max(ui64(danger * 1.4), danger + 4000);
}
return danger;
}
case Obj::HERO:
{
const CGHeroInstance * hero = dynamic_cast<const CGHeroInstance *>(obj);
return getHeroArmyStrengthWithCommander(hero, hero);
}
case Obj::ARTIFACT:
case Obj::RESOURCE:
{
if(!vstd::contains(ai->memory->alreadyVisited, obj))
return 0;
[[fallthrough]];
}
default:
{
const CArmedInstance * a = dynamic_cast<const CArmedInstance *>(obj);
if (a)
return a->getArmyStrength();
else
return 0;
}
}
}
}
|