1
0
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:
DjWarmonger 2014-02-17 17:28:39 +00:00
parent 6ee823298a
commit a3cad2883f
10 changed files with 71 additions and 57 deletions

View File

@ -347,7 +347,7 @@ int3 whereToExplore(HeroPtr h)
catch(cannotFulfillGoalException &e)
{
//perform exhaustive search
return ai->explorationNewPoint(radius, h);
return ai->explorationNewPoint(h);
}
}

View File

@ -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;

View File

@ -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)

View File

@ -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?
// }
//}
}
}

View File

@ -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;

View File

@ -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)

View File

@ -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
{

View File

@ -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)

View File

@ -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;

View File

@ -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;