mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
- Restored correct specialty serialization (#1599 and all its children)
- Fixed rare AI crash - Fixed AI visiting some objects many times - Some cleanup and refactoring
This commit is contained in:
parent
6ee823298a
commit
a3cad2883f
@ -347,7 +347,7 @@ int3 whereToExplore(HeroPtr h)
|
||||
catch(cannotFulfillGoalException &e)
|
||||
{
|
||||
//perform exhaustive search
|
||||
return ai->explorationNewPoint(radius, h);
|
||||
return ai->explorationNewPoint(h);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -467,6 +467,8 @@ float FuzzyHelper::evaluate (Goals::VisitTile & g)
|
||||
float FuzzyHelper::evaluate (Goals::VisitHero & g)
|
||||
{
|
||||
auto obj = cb->getObj(ObjectInstanceID(g.objid)); //we assume for now that these goals are similiar
|
||||
if (!obj)
|
||||
return -100; //hero died in the meantime
|
||||
//TODO: consider direct copy (constructor?)
|
||||
g.setpriority(Goals::VisitTile(obj->visitablePos()).sethero(g.hero).setisAbstract(g.isAbstract).accept(this));
|
||||
return g.priority;
|
||||
|
@ -418,7 +418,7 @@ TGoalVec ClearWayTo::getAllPossibleSubgoals()
|
||||
ret.push_back (sptr (Goals::FindObj (Obj::KEYMASTER, cb->getTile(tileToHit)->visitableObjects.back()->subID)));
|
||||
}
|
||||
|
||||
auto topObj = backOrNull(cb->getVisitableObjs(tileToHit));
|
||||
auto topObj = cb->getTopObj(tileToHit);
|
||||
if(topObj)
|
||||
{
|
||||
if (topObj->ID == Obj::HERO && cb->getPlayerRelations(h->tempOwner, topObj->tempOwner) != PlayerRelations::ENEMIES)
|
||||
@ -516,18 +516,7 @@ TGoalVec Explore::getAllPossibleSubgoals()
|
||||
for (auto obj : objs) //double loop, performance risk?
|
||||
{
|
||||
auto t = sm.firstTileToGet(h, obj->visitablePos()); //we assume that no more than one tile on the way is guarded
|
||||
if (t.valid())
|
||||
{
|
||||
if (isSafeToVisit(h, t))
|
||||
{
|
||||
ret.push_back (sptr (Goals::VisitTile(t).sethero(h)));
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.push_back (sptr (Goals::GatherArmy(evaluateDanger(t, h)*SAFE_ATTACK_CONSTANT).
|
||||
sethero(h).setisAbstract(true)));
|
||||
}
|
||||
}
|
||||
ai->whatToDoToReachTile(h, t, ret);
|
||||
}
|
||||
|
||||
int3 t = whereToExplore(h);
|
||||
@ -537,19 +526,8 @@ TGoalVec Explore::getAllPossibleSubgoals()
|
||||
}
|
||||
else if (hero.h == h || (!hero && h == ai->primaryHero().h)) //check this only ONCE, high cost
|
||||
{
|
||||
t = ai->explorationDesperate(h->getSightRadious(), h);
|
||||
if (t.valid())
|
||||
{
|
||||
if (isSafeToVisit(h, t))
|
||||
{
|
||||
ret.push_back (sptr (Goals::VisitTile(t).sethero(h)));
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.push_back (sptr (Goals::GatherArmy(evaluateDanger(t, h)*SAFE_ATTACK_CONSTANT).
|
||||
sethero(h).setisAbstract(true)));
|
||||
}
|
||||
}
|
||||
t = ai->explorationDesperate(h);
|
||||
ai->whatToDoToReachTile(h, t, ret);
|
||||
}
|
||||
}
|
||||
//we either don't have hero yet or none of heroes can explore
|
||||
@ -560,7 +538,7 @@ TGoalVec Explore::getAllPossibleSubgoals()
|
||||
//{
|
||||
// for (auto h : heroes) //this is costly function, use only when there is no other way
|
||||
// {
|
||||
// auto t = ai->explorationDesperate (h->getSightRadious(), h); //we assume that no more than one tile on the way is guarded
|
||||
// auto t = ai->explorationDesperate (h); //we assume that no more than one tile on the way is guarded
|
||||
// if (t.valid())
|
||||
// {
|
||||
// if (isSafeToVisit(h, t))
|
||||
@ -744,7 +722,7 @@ TSubgoal CollectRes::whatToDoToAchieve()
|
||||
|
||||
if(howManyCanWeBuy + cb->getResourceAmount(static_cast<Res::ERes>(resID)) >= value)
|
||||
{
|
||||
auto backObj = backOrNull(cb->getVisitableObjs(m->o->visitablePos())); //it'll be a hero if we have one there; otherwise marketplace
|
||||
auto backObj = cb->getTopObj(m->o->visitablePos()); //it'll be a hero if we have one there; otherwise marketplace
|
||||
assert(backObj);
|
||||
if (backObj->tempOwner != ai->playerID)
|
||||
{
|
||||
@ -858,21 +836,7 @@ TGoalVec Conquer::getAllPossibleSubgoals()
|
||||
for (auto obj : ourObjs) //double loop, performance risk?
|
||||
{
|
||||
auto t = sm.firstTileToGet(h, obj->visitablePos()); //we assume that no more than one tile on the way is guarded
|
||||
if (t.valid())
|
||||
{
|
||||
if (isSafeToVisit(h, t))
|
||||
{
|
||||
if (obj->ID == Obj::HERO)
|
||||
ret.push_back (sptr (Goals::VisitHero(obj->id.getNum()).sethero(h).setisAbstract(true)));
|
||||
//track enemy hero
|
||||
else
|
||||
ret.push_back (sptr (Goals::VisitTile(t).sethero(h)));
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.push_back (sptr (Goals::GatherArmy(evaluateDanger(t,h)*SAFE_ATTACK_CONSTANT).sethero(h).setisAbstract(true)));
|
||||
}
|
||||
}
|
||||
ai->whatToDoToReachTile (h, t, ret);
|
||||
}
|
||||
}
|
||||
if (!objs.empty() && ai->canRecruitAnyHero()) //probably no point to recruit hero if we see no objects to capture
|
||||
@ -978,6 +942,9 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
|
||||
ret.push_back (sptr (Goals::VisitTile(pos).sethero(h)));
|
||||
}
|
||||
}
|
||||
if (ai->canRecruitAnyHero()) //this is not stupid in early phase of game
|
||||
ret.push_back (sptr(Goals::RecruitHero()));
|
||||
|
||||
if (ret.empty())
|
||||
{
|
||||
if (hero == ai->primaryHero() || value >= 1.1f)
|
||||
|
@ -742,7 +742,6 @@ void VCAI::makeTurnInternal()
|
||||
std::vector<std::pair<HeroPtr, Goals::TSubgoal> > safeCopy;
|
||||
for (auto mission : lockedHeroes)
|
||||
{
|
||||
//FIXME: for some reason when called here, priority is always the same
|
||||
fh->setPriority (mission.second); //re-evaluate
|
||||
if (canAct(mission.first))
|
||||
{
|
||||
@ -1241,6 +1240,26 @@ std::vector<const CGObjectInstance *> VCAI::getPossibleDestinations(HeroPtr h)
|
||||
return possibleDestinations;
|
||||
}
|
||||
|
||||
void VCAI::whatToDoToReachTile (const CGHeroInstance * h, int3 t, Goals::TGoalVec& vec)
|
||||
///TODO: possibly merge with Goals::ClearWayTo
|
||||
{
|
||||
if (t.valid())
|
||||
{
|
||||
auto obj = cb->getTopObj(t);
|
||||
if (obj && vstd::contains(ai->reservedObjs, obj) && !vstd::contains(reservedHeroesMap[h], obj))
|
||||
return; //do not capture object reserved by another hero
|
||||
if (isSafeToVisit(h, t))
|
||||
{
|
||||
vec.push_back (sptr (Goals::VisitTile(t).sethero(h)));
|
||||
}
|
||||
else
|
||||
{
|
||||
vec.push_back (sptr (Goals::GatherArmy(evaluateDanger(t, h)*SAFE_ATTACK_CONSTANT).
|
||||
sethero(h).setisAbstract(true)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool VCAI::canRecruitAnyHero (const CGTownInstance * t) const
|
||||
{
|
||||
//TODO: make gathering gold, building tavern or conquering town (?) possible subgoals
|
||||
@ -2205,10 +2224,11 @@ int3 VCAI::explorationBestNeighbour(int3 hpos, int radius, HeroPtr h)
|
||||
throw cannotFulfillGoalException("No neighbour will bring new discoveries!");
|
||||
}
|
||||
|
||||
int3 VCAI::explorationNewPoint(int radius, HeroPtr h)
|
||||
int3 VCAI::explorationNewPoint(HeroPtr h)
|
||||
{
|
||||
//logAi->debugStream() << "Looking for an another place for exploration...";
|
||||
cb->setSelection(h.h);
|
||||
int radius = h->getSightRadious();
|
||||
|
||||
std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow]
|
||||
tiles.resize(radius);
|
||||
@ -2288,10 +2308,11 @@ int3 VCAI::explorationNewPoint(int radius, HeroPtr h)
|
||||
return bestTile;
|
||||
}
|
||||
|
||||
int3 VCAI::explorationDesperate(int radius, HeroPtr h)
|
||||
int3 VCAI::explorationDesperate(HeroPtr h)
|
||||
{
|
||||
//logAi->debugStream() << "Looking for an another place for exploration...";
|
||||
SectorMap sm(h);
|
||||
int radius = h->getSightRadious();
|
||||
|
||||
std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow]
|
||||
tiles.resize(radius);
|
||||
@ -3049,7 +3070,7 @@ For ship construction etc, another function (goal?) is needed
|
||||
int3 curtile = dst;
|
||||
while(curtile != h->visitablePos())
|
||||
{
|
||||
auto topObj = backOrNull(cb->getVisitableObjs(curtile));
|
||||
auto topObj = cb->getTopObj(curtile);
|
||||
if (topObj && topObj->ID == Obj::HERO && topObj != h.h)
|
||||
{
|
||||
logAi->warnStream() << ("Another allied hero stands in our way");
|
||||
@ -3095,8 +3116,7 @@ void SectorMap::makeParentBFS(crint3 source)
|
||||
ui8 &sec = retreiveTile(curPos);
|
||||
assert(sec == mySector); //consider only tiles from the same sector
|
||||
UNUSED(sec);
|
||||
|
||||
//const TerrainTile *t = cb->getTile(curPos);
|
||||
|
||||
foreach_neighbour(curPos, [&](crint3 neighPos)
|
||||
{
|
||||
if(retreiveTile(neighPos) == mySector && !vstd::contains(parent, neighPos))
|
||||
@ -3107,7 +3127,20 @@ void SectorMap::makeParentBFS(crint3 source)
|
||||
parent[neighPos] = curPos;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
//this code is unused, as tiles on both sides of game are different sectors
|
||||
|
||||
//const TerrainTile *t = cb->getTile(curPos);
|
||||
//if(t->topVisitableId() == Obj::SUBTERRANEAN_GATE)
|
||||
//{
|
||||
// //try finding the exit gate
|
||||
// auto it = ai->knownSubterraneanGates.find(t->topVisitableObj());
|
||||
// if (it != ai->knownSubterraneanGates.end())
|
||||
// {
|
||||
// const int3 outPos = it->second->visitablePos();
|
||||
// parent[outPos] = curPos; //TODO: is it only one tile?
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,8 +178,9 @@ public:
|
||||
void tryRealize(Goals::AbstractGoal & g);
|
||||
|
||||
int3 explorationBestNeighbour(int3 hpos, int radius, HeroPtr h);
|
||||
int3 explorationNewPoint(int radius, HeroPtr h);
|
||||
int3 explorationDesperate(int radius, HeroPtr h);
|
||||
int3 explorationNewPoint(HeroPtr h);
|
||||
int3 explorationDesperate(HeroPtr h);
|
||||
void whatToDoToReachTile (const CGHeroInstance * h, int3 t, Goals::TGoalVec& vec);
|
||||
void recruitHero();
|
||||
|
||||
virtual std::string getBattleAIName() const override;
|
||||
|
@ -1567,10 +1567,10 @@ void CGHeroInstance::deserializationFix()
|
||||
{
|
||||
artDeserializationFix(this);
|
||||
|
||||
//for (auto hs : specialty)
|
||||
//{
|
||||
// attachTo (hs);
|
||||
//}
|
||||
for (auto hs : specialty)
|
||||
{
|
||||
attachTo (hs);
|
||||
}
|
||||
}
|
||||
|
||||
CBonusSystemNode * CGHeroInstance::whereShouldBeAttached(CGameState *gs)
|
||||
|
@ -521,6 +521,10 @@ std::vector <const CGObjectInstance * > CGameInfoCallback::getVisitableObjs(int3
|
||||
|
||||
return ret;
|
||||
}
|
||||
const CGObjectInstance * CGameInfoCallback::getTopObj (int3 pos) const
|
||||
{
|
||||
return vstd::backOrNull(getVisitableObjs(pos));
|
||||
}
|
||||
|
||||
std::vector < const CGObjectInstance * > CGameInfoCallback::getFlaggableObjects(int3 pos) const
|
||||
{
|
||||
|
@ -111,6 +111,7 @@ public:
|
||||
std::vector <const CGObjectInstance * > getBlockingObjs(int3 pos)const;
|
||||
std::vector <const CGObjectInstance * > getVisitableObjs(int3 pos, bool verbose = true)const;
|
||||
std::vector <const CGObjectInstance * > getFlaggableObjects(int3 pos) const;
|
||||
const CGObjectInstance * getTopObj (int3 pos) const;
|
||||
std::vector <std::string > getObjDescriptions(int3 pos)const; //returns descriptions of objects at pos in order from the lowest to the highest
|
||||
PlayerColor getOwner(ObjectInstanceID heroID) const;
|
||||
const CGObjectInstance *getObjByQuestIdentifier(int identifier) const; //nullptr if object has been removed (eg. killed)
|
||||
|
@ -132,6 +132,11 @@ int TerrainTile::topVisitableId() const
|
||||
return visitableObjects.size() ? visitableObjects.back()->ID : -1;
|
||||
}
|
||||
|
||||
CGObjectInstance * TerrainTile::topVisitableObj() const
|
||||
{
|
||||
return visitableObjects.size() ? visitableObjects.back() : nullptr;
|
||||
}
|
||||
|
||||
bool TerrainTile::isCoastal() const
|
||||
{
|
||||
return extTileFlags & 64;
|
||||
|
@ -288,6 +288,7 @@ struct DLL_LINKAGE TerrainTile
|
||||
bool isClear(const TerrainTile * from = nullptr) const;
|
||||
/// Gets the ID of the top visitable object or -1 if there is none.
|
||||
int topVisitableId() const;
|
||||
CGObjectInstance * topVisitableObj() const;
|
||||
bool isWater() const;
|
||||
bool isCoastal() const;
|
||||
bool hasFavourableWinds() const;
|
||||
|
Loading…
Reference in New Issue
Block a user