mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
AI won't access enemy heroes' objects that went under FoW. Fixes #1235.
This commit is contained in:
@@ -200,7 +200,7 @@ struct ObjInfo
|
|||||||
std::map<const CGObjectInstance *, ObjInfo> helperObjInfo;
|
std::map<const CGObjectInstance *, ObjInfo> helperObjInfo;
|
||||||
|
|
||||||
template <typename Container, typename Item>
|
template <typename Container, typename Item>
|
||||||
bool remove_if_present(Container &c, const Item &item)
|
bool erase_if_present(Container &c, const Item &item)
|
||||||
{
|
{
|
||||||
auto i = std::find(c.begin(), c.end(), item);
|
auto i = std::find(c.begin(), c.end(), item);
|
||||||
if (i != c.end())
|
if (i != c.end())
|
||||||
@@ -214,7 +214,7 @@ bool remove_if_present(Container &c, const Item &item)
|
|||||||
|
|
||||||
|
|
||||||
template <typename V, typename Item, typename Item2>
|
template <typename V, typename Item, typename Item2>
|
||||||
bool remove_if_present(std::map<Item,V> & c, const Item2 &item)
|
bool erase_if_present(std::map<Item,V> & c, const Item2 &item)
|
||||||
{
|
{
|
||||||
auto i = c.find(item);
|
auto i = c.find(item);
|
||||||
if (i != c.end())
|
if (i != c.end())
|
||||||
@@ -430,6 +430,9 @@ void VCAI::heroMoved(const TryMoveHero & details)
|
|||||||
{
|
{
|
||||||
LOG_TRACE(logAi);
|
LOG_TRACE(logAi);
|
||||||
NET_EVENT_HANDLER;
|
NET_EVENT_HANDLER;
|
||||||
|
|
||||||
|
validateObject(details.id); //enemy hero may have left visible area
|
||||||
|
|
||||||
if(details.result == TryMoveHero::TELEPORTATION)
|
if(details.result == TryMoveHero::TELEPORTATION)
|
||||||
{
|
{
|
||||||
const int3 from = CGHeroInstance::convertPosition(details.start, false),
|
const int3 from = CGHeroInstance::convertPosition(details.start, false),
|
||||||
@@ -572,8 +575,8 @@ void VCAI::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visi
|
|||||||
{
|
{
|
||||||
visitedObject = const_cast<CGObjectInstance *>(visitedObj); // remember the object and wait for return
|
visitedObject = const_cast<CGObjectInstance *>(visitedObj); // remember the object and wait for return
|
||||||
markObjectVisited (visitedObj);
|
markObjectVisited (visitedObj);
|
||||||
remove_if_present(reservedObjs, visitedObj); //unreserve objects
|
erase_if_present(reservedObjs, visitedObj); //unreserve objects
|
||||||
remove_if_present(reservedHeroesMap[visitor], visitedObj);
|
erase_if_present(reservedHeroesMap[visitor], visitedObj);
|
||||||
completeGoal (CGoal(GET_OBJ).sethero(visitor)); //we don't need to visit in anymore
|
completeGoal (CGoal(GET_OBJ).sethero(visitor)); //we don't need to visit in anymore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -596,10 +599,8 @@ void VCAI::tileHidden(const boost::unordered_set<int3, ShashInt3> &pos)
|
|||||||
{
|
{
|
||||||
LOG_TRACE(logAi);
|
LOG_TRACE(logAi);
|
||||||
NET_EVENT_HANDLER;
|
NET_EVENT_HANDLER;
|
||||||
// BOOST_FOREACH(int3 tile, pos)
|
|
||||||
// BOOST_FOREACH(const CGObjectInstance *obj, cb->getVisitableObjs(tile))
|
validateVisitableObjs();
|
||||||
// remove_if_present(visitableObjs, obj);
|
|
||||||
visitableObjs.erase(boost::remove_if(visitableObjs, [&](const CGObjectInstance *obj){return !myCb->getObj(obj->id);}), visitableObjs.end());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCAI::tileRevealed(const boost::unordered_set<int3, ShashInt3> &pos)
|
void VCAI::tileRevealed(const boost::unordered_set<int3, ShashInt3> &pos)
|
||||||
@@ -675,11 +676,9 @@ void VCAI::objectRemoved(const CGObjectInstance *obj)
|
|||||||
LOG_TRACE(logAi);
|
LOG_TRACE(logAi);
|
||||||
NET_EVENT_HANDLER;
|
NET_EVENT_HANDLER;
|
||||||
|
|
||||||
if(remove_if_present(visitableObjs, obj))
|
erase_if_present(visitableObjs, obj);
|
||||||
assert(obj->isVisitable());
|
|
||||||
|
|
||||||
BOOST_FOREACH(auto &p, reservedHeroesMap)
|
BOOST_FOREACH(auto &p, reservedHeroesMap)
|
||||||
remove_if_present(p.second, obj);
|
erase_if_present(p.second, obj);
|
||||||
|
|
||||||
//TODO
|
//TODO
|
||||||
//there are other places where CGObjectinstance ptrs are stored...
|
//there are other places where CGObjectinstance ptrs are stored...
|
||||||
@@ -687,7 +686,7 @@ void VCAI::objectRemoved(const CGObjectInstance *obj)
|
|||||||
|
|
||||||
if(obj->ID == Obj::HERO && obj->tempOwner == playerID)
|
if(obj->ID == Obj::HERO && obj->tempOwner == playerID)
|
||||||
{
|
{
|
||||||
lostHero(cb->getHero(obj->id)); //we can promote, since objectRemoved is killed just before actual deletion
|
lostHero(cb->getHero(obj->id)); //we can promote, since objectRemoved is called just before actual deletion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -794,7 +793,7 @@ void VCAI::objectPropertyChanged(const SetObjectProperty * sop)
|
|||||||
if(sop->what == ObjProperty::OWNER)
|
if(sop->what == ObjProperty::OWNER)
|
||||||
{
|
{
|
||||||
if(sop->val == playerID.getNum())
|
if(sop->val == playerID.getNum())
|
||||||
remove_if_present(visitableObjs, myCb->getObj(sop->id));
|
erase_if_present(visitableObjs, myCb->getObj(sop->id));
|
||||||
//TODO restore lost obj
|
//TODO restore lost obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1491,6 +1490,7 @@ void VCAI::wander(HeroPtr h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const ObjectIdRef&dest = dests.front();
|
const ObjectIdRef&dest = dests.front();
|
||||||
|
logAi->debugStream() << "Of all %d destinations, object oid=%d seems nice", dests.size() % dest.id.getNum();
|
||||||
if(!goVisitObj(dest, h))
|
if(!goVisitObj(dest, h))
|
||||||
{
|
{
|
||||||
if(!dest)
|
if(!dest)
|
||||||
@@ -1520,7 +1520,7 @@ void VCAI::wander(HeroPtr h)
|
|||||||
void VCAI::setGoal(HeroPtr h, const CGoal goal)
|
void VCAI::setGoal(HeroPtr h, const CGoal goal)
|
||||||
{ //TODO: check for presence?
|
{ //TODO: check for presence?
|
||||||
if (goal.goalType == EGoals::INVALID)
|
if (goal.goalType == EGoals::INVALID)
|
||||||
remove_if_present(lockedHeroes, h);
|
erase_if_present(lockedHeroes, h);
|
||||||
else
|
else
|
||||||
lockedHeroes[h] = CGoal(goal).setisElementar(false); //always evaluate goals before realizing
|
lockedHeroes[h] = CGoal(goal).setisElementar(false); //always evaluate goals before realizing
|
||||||
}
|
}
|
||||||
@@ -1528,7 +1528,7 @@ void VCAI::setGoal(HeroPtr h, const CGoal goal)
|
|||||||
void VCAI::setGoal(HeroPtr h, EGoals goalType)
|
void VCAI::setGoal(HeroPtr h, EGoals goalType)
|
||||||
{
|
{
|
||||||
if (goalType == EGoals::INVALID)
|
if (goalType == EGoals::INVALID)
|
||||||
remove_if_present(lockedHeroes, h);
|
erase_if_present(lockedHeroes, h);
|
||||||
else
|
else
|
||||||
lockedHeroes[h] = CGoal(goalType).setisElementar(false); //always evaluate goals before realizing;
|
lockedHeroes[h] = CGoal(goalType).setisElementar(false); //always evaluate goals before realizing;
|
||||||
}
|
}
|
||||||
@@ -1590,15 +1590,14 @@ void VCAI::validateVisitableObjs()
|
|||||||
{
|
{
|
||||||
std::vector<const CGObjectInstance *> hlp;
|
std::vector<const CGObjectInstance *> hlp;
|
||||||
retreiveVisitableObjs(hlp, true);
|
retreiveVisitableObjs(hlp, true);
|
||||||
|
erase_if(visitableObjs, [&](const CGObjectInstance *obj) -> bool
|
||||||
start:
|
{
|
||||||
BOOST_FOREACH(const CGObjectInstance *obj, visitableObjs)
|
|
||||||
if(!vstd::contains(hlp, obj))
|
if(!vstd::contains(hlp, obj))
|
||||||
{
|
{
|
||||||
logAi->errorStream() << helperObjInfo[obj].name << " at " << helperObjInfo[obj].pos << " shouldn't be on list!";
|
logAi->errorStream() << helperObjInfo[obj].name << " at " << helperObjInfo[obj].pos << " shouldn't be on list!";
|
||||||
remove_if_present(visitableObjs, obj);
|
return true;
|
||||||
goto start;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCAI::retreiveVisitableObjs(std::vector<const CGObjectInstance *> &out, bool includeOwned /*= false*/) const
|
void VCAI::retreiveVisitableObjs(std::vector<const CGObjectInstance *> &out, bool includeOwned /*= false*/) const
|
||||||
@@ -1691,6 +1690,7 @@ bool VCAI::isAccessibleForHero(const int3 & pos, HeroPtr h, bool includeAllies /
|
|||||||
|
|
||||||
bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
||||||
{
|
{
|
||||||
|
logAi->debugStream() << boost::format("Moving hero %s to tile %s") % h->name % dst;
|
||||||
visitedObject = NULL;
|
visitedObject = NULL;
|
||||||
int3 startHpos = h->visitablePos();
|
int3 startHpos = h->visitablePos();
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
@@ -1764,7 +1764,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
|||||||
throw cannotFulfillGoalException("Invalid path found!");
|
throw cannotFulfillGoalException("Invalid path found!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logAi->debugStream() << boost::format("Hero %s moved from %s to %s") % h->name % startHpos % h->visitablePos();
|
logAi->debugStream() << boost::format("Hero %s moved from %s to %s. Returning %d.") % h->name % startHpos % h->visitablePos() % ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1987,7 +1987,7 @@ std::vector<HeroPtr> VCAI::getUnblockedHeroes() const
|
|||||||
{
|
{
|
||||||
//if (!h.second.invalid()) //we can use heroes without valid goal
|
//if (!h.second.invalid()) //we can use heroes without valid goal
|
||||||
if (h.second.goalType == DIG_AT_TILE || !h.first->movement) //experiment: use all heroes that have movement left, TODO: unlock heroes that couldn't realize their goals
|
if (h.second.goalType == DIG_AT_TILE || !h.first->movement) //experiment: use all heroes that have movement left, TODO: unlock heroes that couldn't realize their goals
|
||||||
remove_if_present(ret, h.first);
|
erase_if_present(ret, h.first);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -2508,12 +2508,12 @@ void VCAI::lostHero(HeroPtr h)
|
|||||||
{
|
{
|
||||||
logAi->debugStream() << boost::format("I lost my hero %s. It's best to forget and move on.") % h.name;
|
logAi->debugStream() << boost::format("I lost my hero %s. It's best to forget and move on.") % h.name;
|
||||||
|
|
||||||
remove_if_present(lockedHeroes, h);
|
erase_if_present(lockedHeroes, h);
|
||||||
BOOST_FOREACH(auto obj, reservedHeroesMap[h])
|
BOOST_FOREACH(auto obj, reservedHeroesMap[h])
|
||||||
{
|
{
|
||||||
remove_if_present(reservedObjs, obj); //unreserve all objects for that hero
|
erase_if_present(reservedObjs, obj); //unreserve all objects for that hero
|
||||||
}
|
}
|
||||||
remove_if_present(reservedHeroesMap, h);
|
erase_if_present(reservedHeroesMap, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCAI::answerQuery(int queryID, int selection)
|
void VCAI::answerQuery(int queryID, int selection)
|
||||||
@@ -2547,6 +2547,23 @@ std::string VCAI::getBattleAIName() const
|
|||||||
return "StupidAI";
|
return "StupidAI";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VCAI::validateObject(const CGObjectInstance *obj)
|
||||||
|
{
|
||||||
|
validateObject(obj->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VCAI::validateObject(ObjectIdRef obj)
|
||||||
|
{
|
||||||
|
auto matchesId = [&] (const CGObjectInstance *hlpObj) -> bool { return hlpObj->id == obj.id; };
|
||||||
|
if(!obj)
|
||||||
|
{
|
||||||
|
erase_if(visitableObjs, matchesId);
|
||||||
|
|
||||||
|
BOOST_FOREACH(auto &p, reservedHeroesMap)
|
||||||
|
erase_if(p.second, matchesId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AIStatus::AIStatus()
|
AIStatus::AIStatus()
|
||||||
{
|
{
|
||||||
battle = NO_BATTLE;
|
battle = NO_BATTLE;
|
||||||
|
@@ -250,7 +250,7 @@ public:
|
|||||||
friend class FuzzyHelper;
|
friend class FuzzyHelper;
|
||||||
|
|
||||||
std::map<const CGObjectInstance *, const CGObjectInstance *> knownSubterraneanGates;
|
std::map<const CGObjectInstance *, const CGObjectInstance *> knownSubterraneanGates;
|
||||||
std::vector<const CGObjectInstance *> visitedThisWeek; //only OPWs
|
//std::vector<const CGObjectInstance *> visitedThisWeek; //only OPWs
|
||||||
std::map<HeroPtr, std::vector<const CGTownInstance *> > townVisitsThisWeek;
|
std::map<HeroPtr, std::vector<const CGTownInstance *> > townVisitsThisWeek;
|
||||||
|
|
||||||
std::map<HeroPtr, CGoal> lockedHeroes; //TODO: allow non-elementar objectives
|
std::map<HeroPtr, CGoal> lockedHeroes; //TODO: allow non-elementar objectives
|
||||||
@@ -378,6 +378,8 @@ public:
|
|||||||
void markObjectVisited (const CGObjectInstance *obj);
|
void markObjectVisited (const CGObjectInstance *obj);
|
||||||
void reserveObject (HeroPtr h, const CGObjectInstance *obj);
|
void reserveObject (HeroPtr h, const CGObjectInstance *obj);
|
||||||
//void removeVisitableObj(const CGObjectInstance *obj);
|
//void removeVisitableObj(const CGObjectInstance *obj);
|
||||||
|
void validateObject(const CGObjectInstance *obj); //checks if object is still visible and if not, removes references to it
|
||||||
|
void validateObject(ObjectIdRef obj); //checks if object is still visible and if not, removes references to it
|
||||||
void validateVisitableObjs();
|
void validateVisitableObjs();
|
||||||
void retreiveVisitableObjs(std::vector<const CGObjectInstance *> &out, bool includeOwned = false) const;
|
void retreiveVisitableObjs(std::vector<const CGObjectInstance *> &out, bool includeOwned = false) const;
|
||||||
std::vector<const CGObjectInstance *> getFlaggedObjects() const;
|
std::vector<const CGObjectInstance *> getFlaggedObjects() const;
|
||||||
|
@@ -295,6 +295,8 @@ DLL_LINKAGE void RemoveBonus::applyGs( CGameState *gs )
|
|||||||
|
|
||||||
DLL_LINKAGE void RemoveObject::applyGs( CGameState *gs )
|
DLL_LINKAGE void RemoveObject::applyGs( CGameState *gs )
|
||||||
{
|
{
|
||||||
|
logGlobal->debugStream() << "removing object oid=" << id;
|
||||||
|
|
||||||
CGObjectInstance *obj = gs->getObjInstance(id);
|
CGObjectInstance *obj = gs->getObjInstance(id);
|
||||||
//unblock tiles
|
//unblock tiles
|
||||||
if(obj->defInfo)
|
if(obj->defInfo)
|
||||||
|
Reference in New Issue
Block a user