1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Added class HeroPtr to VCAI that should replace CGHeroInstance*. HeroPtr is able to detect when the hero under it becomes unavailable.

Hopefully fixed #954 (and all bugs caused by keeping a reference to hero that got killed: #998, #1002, #1008, #1011, #1018).
If not, assertions should pop up earlier.
This commit is contained in:
Michał W. Urbańczyk 2012-06-30 23:48:40 +00:00
parent 613172fa45
commit fcdad0d323
4 changed files with 201 additions and 89 deletions

View File

@ -1,3 +1,4 @@
#pragma once
#include "../FuzzyLite/FuzzyLite.h"
/*

View File

@ -26,6 +26,8 @@
#include "../../lib/CondSh.h"
#include "../../lib/CStopWatch.h"
#include "Fuzzy.h"
#include <fstream>
#include <queue>

View File

@ -1,7 +1,6 @@
#include "StdInc.h"
#include "VCAI.h"
#include "../../lib/UnlockGuard.h"
#include "Fuzzy.h"
#include "../../lib/CObjectHandler.h"
#define I_AM_ELEMENTAR return CGoal(*this).setisElementar(true)
@ -20,6 +19,8 @@ using namespace vstd;
boost::thread_specific_ptr<CCallback> cb;
boost::thread_specific_ptr<VCAI> ai;
//std::map<int, std::map<int, int> > HeroView::infosCount;
// CCallback *cb;
// VCAI *ai;
@ -96,10 +97,11 @@ std::string goalName(EGoals goalType)
}
}
bool compareHeroStrength(const CGHeroInstance *h1, const CGHeroInstance *h2)
bool compareHeroStrength(HeroPtr h1, HeroPtr h2)
{
return h1->getTotalStrength() < h2->getTotalStrength();
}
bool compareArmyStrength(const CArmedInstance *a1, const CArmedInstance *a2)
{
return a1->getArmyStrength() < a2->getArmyStrength();
@ -259,7 +261,7 @@ bool isReachable(const CGObjectInstance *obj)
return cb->getPathInfo(obj->visitablePos())->turns < 255;
}
ui64 howManyReinforcementsCanGet(const CGHeroInstance *h, const CGTownInstance *t)
ui64 howManyReinforcementsCanGet(HeroPtr h, const CGTownInstance *t)
{
ui64 ret = 0;
int freeHeroSlots = GameConstants::ARMY_SIZE - h->stacksCount();
@ -306,7 +308,7 @@ bool isCloser(const CGObjectInstance *lhs, const CGObjectInstance *rhs)
return (ln->moveRemains > rn->moveRemains);
};
bool compareMovement(const CGHeroInstance *lhs, const CGHeroInstance *rhs)
bool compareMovement(HeroPtr lhs, HeroPtr rhs)
{
return lhs->movement > rhs->movement;
};
@ -665,6 +667,7 @@ void VCAI::objectRemoved(const CGObjectInstance *obj)
{
NET_EVENT_HANDLER;
LOG_ENTRY;
if(remove_if_present(visitableObjs, obj))
assert(obj->isVisitable());
@ -673,6 +676,12 @@ void VCAI::objectRemoved(const CGObjectInstance *obj)
//TODO
//there are other places where CGObjectinstance ptrs are stored...
//
if(obj->ID == GameConstants::HEROI_TYPE && obj->tempOwner == playerID)
{
lostHero(cb->getHero(obj->id)); //we can promote, since objectRemoved is killed just before actual deletion
}
}
void VCAI::showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor)
@ -923,8 +932,7 @@ void VCAI::makeTurn()
break;
case 7: //reconsider strategy
{
const CGHeroInstance * h = primaryHero();
if (h) //check if our primary hero can handle danger
if(auto h = primaryHero()) //check if our primary hero can handle danger
{
ui64 totalDanger = 0;
int dangerousObjects = 0;
@ -934,7 +942,7 @@ void VCAI::makeTurn()
{
if (evaluateDanger(obj)) //potentilaly dnagerous
{
totalDanger += evaluateDanger (obj->visitablePos(), h);
totalDanger += evaluateDanger(obj->visitablePos(), *h);
++dangerousObjects;
}
}
@ -968,26 +976,25 @@ void VCAI::makeTurnInternal()
//Pick objects reserved in previous turn - we expect only nerby objects there
BOOST_FOREACH (auto hero, reservedHeroesMap)
{
cb->setSelection(hero.first);
cb->setSelection(hero.first.get());
boost::sort (hero.second, isCloser);
BOOST_FOREACH (auto obj, hero.second)
{
const CGHeroInstance * h = hero.first;
striveToGoal (CGoal(VISIT_TILE).sethero(h).settile(obj->visitablePos()));
striveToGoal (CGoal(VISIT_TILE).sethero(hero.first).settile(obj->visitablePos()));
}
}
//now try to win
striveToGoal(CGoal(WIN));
//finally, continue our abstract long-temr goals
std::vector<std::pair<const CGHeroInstance *, CGoal> > safeCopy; //heroes tend to die in the process and loose their goals, unsafe to iterate it
BOOST_FOREACH (auto h, lockedHeroes)
{
safeCopy.push_back(h);
}
//finally, continue our abstract long-term goals
auto lockedHeroesSorter = [](std::pair<const CGHeroInstance *, CGoal> h1, std::pair<const CGHeroInstance *, CGoal> h2) -> bool
//heroes tend to die in the process and loose their goals, unsafe to iterate it
std::vector<std::pair<HeroPtr, CGoal> > safeCopy;
boost::copy(lockedHeroes, std::back_inserter(safeCopy));
typedef decltype(*safeCopy.begin()) TItrType;
auto lockedHeroesSorter = [](TItrType h1, TItrType h2) -> bool
{
return compareMovement (h1.first, h2.first);
};
@ -998,7 +1005,7 @@ void VCAI::makeTurnInternal()
auto it = safeCopy.begin();
if (it->first && it->first->tempOwner == playerID && vstd::contains(lockedHeroes, it->first)) //make sure hero still has his goal
{
cb->setSelection(it->first);
cb->setSelection(*it->first);
striveToGoal (it->second);
}
safeCopy.erase(it);
@ -1019,14 +1026,14 @@ void VCAI::makeTurnInternal()
endTurn();
}
bool VCAI::goVisitObj(const CGObjectInstance * obj, const CGHeroInstance * h)
bool VCAI::goVisitObj(const CGObjectInstance * obj, HeroPtr h)
{
int3 dst = obj->visitablePos();
BNLOG("%s will try to visit %s at (%s)", h->name % obj->hoverName % strFromInt3(dst));
return moveHeroToTile(dst, h);
}
void VCAI::performObjectInteraction(const CGObjectInstance * obj, const CGHeroInstance * h)
void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
{
switch (obj->ID)
{
@ -1230,10 +1237,10 @@ void VCAI::buildStructure(const CGTownInstance * t)
return;
}
bool isSafeToVisit(const CGHeroInstance *h, crint3 tile)
bool isSafeToVisit(HeroPtr h, crint3 tile)
{
const ui64 heroStrength = h->getTotalStrength(),
dangerStrength = evaluateDanger(tile, h);
dangerStrength = evaluateDanger(tile, *h);
if(dangerStrength)
{
if(heroStrength / SAFE_ATTACK_CONSTANT > dangerStrength)
@ -1249,7 +1256,7 @@ bool isSafeToVisit(const CGHeroInstance *h, crint3 tile)
return true; //there's no danger
}
std::vector<const CGObjectInstance *> VCAI::getPossibleDestinations(const CGHeroInstance *h)
std::vector<const CGObjectInstance *> VCAI::getPossibleDestinations(HeroPtr h)
{
validateVisitableObjs();
std::vector<const CGObjectInstance *> possibleDestinations;
@ -1289,7 +1296,7 @@ std::vector<const CGObjectInstance *> VCAI::getPossibleDestinations(const CGHero
return possibleDestinations;
}
void VCAI::wander(const CGHeroInstance * h)
void VCAI::wander(HeroPtr h)
{
while(1)
{
@ -1385,7 +1392,7 @@ void VCAI::wander(const CGHeroInstance * h)
}
}
void VCAI::setGoal (const CGHeroInstance *h, const CGoal goal)
void VCAI::setGoal(HeroPtr h, const CGoal goal)
{ //TODO: check for presence?
if (goal.goalType == EGoals::INVALID)
remove_if_present(lockedHeroes, h);
@ -1393,7 +1400,7 @@ void VCAI::setGoal (const CGHeroInstance *h, const CGoal goal)
lockedHeroes[h] = CGoal(goal).setisElementar(false); //always evaluate goals before realizing
}
void VCAI::setGoal (const CGHeroInstance *h, EGoals goalType)
void VCAI::setGoal(HeroPtr h, EGoals goalType)
{
if (goalType == EGoals::INVALID)
remove_if_present(lockedHeroes, h);
@ -1403,7 +1410,7 @@ void VCAI::setGoal (const CGHeroInstance *h, EGoals goalType)
void VCAI::completeGoal (const CGoal goal)
{
if (const CGHeroInstance * h = goal.hero)
if (const CGHeroInstance * h = goal.hero.get(true))
{
auto it = lockedHeroes.find(h);
if (it != lockedHeroes.end())
@ -1448,7 +1455,7 @@ void VCAI::markObjectVisited (const CGObjectInstance *obj)
alreadyVisited.push_back(obj);
}
void VCAI::reserveObject (const CGHeroInstance * h, const CGObjectInstance *obj)
void VCAI::reserveObject(HeroPtr h, const CGObjectInstance *obj)
{
reservedObjs.push_back(obj);
reservedHeroesMap[h].push_back(obj);
@ -1524,7 +1531,7 @@ bool VCAI::isAccessible(const int3 &pos)
return false;
}
const CGHeroInstance * VCAI::getHeroWithGrail() const
HeroPtr VCAI::getHeroWithGrail() const
{
BOOST_FOREACH(const CGHeroInstance *h, cb->getHeroesInfo())
if(h->hasArt(2)) //grail
@ -1543,9 +1550,9 @@ const CGObjectInstance * VCAI::getUnvisitedObj(const boost::function<bool(const
return NULL;
}
bool VCAI::isAccessibleForHero(const int3 & pos, const CGHeroInstance * h, bool includeAllies) const
bool VCAI::isAccessibleForHero(const int3 & pos, HeroPtr h, bool includeAllies /*= false*/) const
{
cb->setSelection(h);
cb->setSelection(*h);
if (!includeAllies)
{ //don't visit tile occupied by allied hero
BOOST_FOREACH (auto obj, cb->getVisitableObjs(pos))
@ -1592,7 +1599,7 @@ public:
}
};
bool VCAI::moveHeroToTile(int3 dst, const CGHeroInstance * h)
bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
{
visitedObject = NULL;
int3 startHpos = h->visitablePos();
@ -1600,7 +1607,7 @@ bool VCAI::moveHeroToTile(int3 dst, const CGHeroInstance * h)
if(startHpos == dst)
{
assert(cb->getVisitableObjs(dst).size() > 1); //there's no point in revisiting tile where there is no visitable object
cb->moveHero(h,CGHeroInstance::convertPosition(dst, true));
cb->moveHero(*h, CGHeroInstance::convertPosition(dst, true));
waitTillFree(); //movement may cause battle or blocking dialog
ret = true;
}
@ -1638,19 +1645,14 @@ bool VCAI::moveHeroToTile(int3 dst, const CGHeroInstance * h)
//
// }
//tlog0 << "Moving " << h->name << " from " << h->getPosition() << " to " << endpos << std::endl;
cb->moveHero(h,CGHeroInstance::convertPosition(endpos, true));
cb->moveHero(*h, CGHeroInstance::convertPosition(endpos, true));
waitTillFree(); //movement may cause battle or blocking dialog
boost::this_thread::interruption_point();
if(h->tempOwner != playerID) //we lost hero - remove all tasks assigned to him/her
{
remove_if_present(lockedHeroes, h);
BOOST_FOREACH (auto obj, reservedHeroesMap[h])
{
remove_if_present(reservedObjs, obj); //unreserve all objects for that hero
}
remove_if_present(reservedHeroesMap, h);
throw std::runtime_error("Hero was lost!"); //we need to throw, otherwise hero will be assigned to sth again
lostHero(h);
//we need to throw, otherwise hero will be assigned to sth again
throw std::runtime_error("Hero was lost!");
break;
}
@ -1738,7 +1740,7 @@ void VCAI::tryRealize(CGoal g)
throw cannotFulfillGoalException("Cannot visit tile: hero is out of MPs!");
if(!g.isBlockedBorderGate(g.tile))
{
if (ai->moveHeroToTile(g.tile, g.hero))
if (ai->moveHeroToTile(g.tile, g.hero.get()))
{
throw goalFulfilledException("");
}
@ -1781,8 +1783,8 @@ void VCAI::tryRealize(CGoal g)
assert(g.hero->visitablePos() == g.tile);
if (g.hero->diggingStatus() == CGHeroInstance::CAN_DIG)
{
cb->dig (g.hero);
setGoal (g.hero, INVALID); // finished digging
cb->dig(g.hero.get());
setGoal(g.hero, INVALID); // finished digging
}
else
{
@ -1846,9 +1848,11 @@ const CGTownInstance * VCAI::findTownWithTavern() const
return NULL;
}
std::vector<const CGHeroInstance *> VCAI::getUnblockedHeroes() const
std::vector<HeroPtr> VCAI::getUnblockedHeroes() const
{
std::vector<const CGHeroInstance *> ret = cb->getHeroesInfo();
std::vector<HeroPtr> ret;
boost::copy(cb->getHeroesInfo(), std::back_inserter(ret));
BOOST_FOREACH(auto h, lockedHeroes)
{
if (!h.second.invalid()) //we can use heroes without valid goal
@ -1857,7 +1861,7 @@ std::vector<const CGHeroInstance *> VCAI::getUnblockedHeroes() const
return ret;
}
const CGHeroInstance * VCAI::primaryHero() const
HeroPtr VCAI::primaryHero() const
{
auto hs = cb->getHeroesInfo();
boost::sort(hs, compareHeroStrength);
@ -1921,11 +1925,11 @@ void VCAI::striveToGoal(const CGoal &ultimateGoal)
{
if (maxGoals)
{
setGoal (goal.hero, goal);
setGoal(goal.hero, goal);
}
else
{
setGoal (goal.hero, INVALID); // we seemingly don't know what to do with hero
setGoal(goal.hero, INVALID); // we seemingly don't know what to do with hero
}
}
@ -2025,12 +2029,12 @@ void VCAI::performTypicalActions()
}
}
BOOST_FOREACH(const CGHeroInstance *h, getUnblockedHeroes())
BOOST_FOREACH(auto h, getUnblockedHeroes())
{
BNLOG("Looking into %s, MP=%d", h->name.c_str() % h->movement);
INDENT;
makePossibleUpgrades(h);
cb->setSelection(h);
makePossibleUpgrades(*h);
cb->setSelection(*h);
try
{
wander(h);
@ -2051,7 +2055,7 @@ void VCAI::buildArmyIn(const CGTownInstance * t)
moveCreaturesToHero(t);
}
int3 VCAI::explorationBestNeighbour(int3 hpos, int radius, const CGHeroInstance * h)
int3 VCAI::explorationBestNeighbour(int3 hpos, int radius, HeroPtr h)
{
TimeCheck tc("looking for best exploration neighbour");
std::map<int3, int> dstToRevealedTiles;
@ -2076,7 +2080,7 @@ int3 VCAI::explorationBestNeighbour(int3 hpos, int radius, const CGHeroInstance
throw cannotFulfillGoalException("No neighbour will bring new discoveries!");
}
int3 VCAI::explorationNewPoint(int radius, const CGHeroInstance * h, std::vector<std::vector<int3> > &tiles)
int3 VCAI::explorationNewPoint(int radius, HeroPtr h, std::vector<std::vector<int3> > &tiles)
{
TimeCheck tc("looking for new exploration point");
PNLOG("Looking for an another place for exploration...");
@ -2187,6 +2191,18 @@ void VCAI::requestActionASAP(boost::function<void()> whatToDo)
b.wait();
}
void VCAI::lostHero(HeroPtr h)
{
BNLOG("I lost my hero %s. It's best to forget and move on.\n", h.name);
remove_if_present(lockedHeroes, h);
BOOST_FOREACH(auto obj, reservedHeroesMap[h])
{
remove_if_present(reservedObjs, obj); //unreserve all objects for that hero
}
remove_if_present(reservedHeroesMap, h);
}
AIStatus::AIStatus()
{
battle = NO_BATTLE;
@ -2264,10 +2280,10 @@ bool AIStatus::haveTurn()
return havingTurn;
}
int3 whereToExplore(const CGHeroInstance *h)
int3 whereToExplore(HeroPtr h)
{
//TODO it's stupid and ineffective, write sth better
cb->setSelection(h);
cb->setSelection(*h);
int radius = h->getSightRadious();
int3 hpos = h->visitablePos();
@ -2348,7 +2364,7 @@ TSubgoal CGoal::whatToDoToAchieve()
break;
case EVictoryConditionType::BUILDGRAIL:
{
if(const CGHeroInstance *h = ai->getHeroWithGrail())
if(auto h = ai->getHeroWithGrail())
{
//hero is in a town that can host Grail
if(h->visitedTown && !vstd::contains(h->visitedTown->forbiddenBuildings, EBuilding::GRAIL))
@ -2441,11 +2457,11 @@ TSubgoal CGoal::whatToDoToAchieve()
return CGoal(EXPLORE);
}
const CGHeroInstance *h = hero ? hero : ai->primaryHero();
HeroPtr h = hero ? hero : ai->primaryHero();
if(!h)
return CGoal(RECRUIT_HERO);
cb->setSelection(h);
cb->setSelection(*h);
SectorMap sm;
bool dropToFile = false;
@ -2724,18 +2740,18 @@ TSubgoal CGoal::whatToDoToAchieve()
case GATHER_ARMY:
{
//TODO: find hero if none set
assert(hero);
const CGHeroInstance *h = hero;
cb->setSelection(h);
auto compareReinforcements = [h](const CGTownInstance *lhs, const CGTownInstance *rhs) -> bool
cb->setSelection(*hero);
auto compareReinforcements = [this](const CGTownInstance *lhs, const CGTownInstance *rhs) -> bool
{
return howManyReinforcementsCanGet(h, lhs) < howManyReinforcementsCanGet(h, rhs);
return howManyReinforcementsCanGet(hero, lhs) < howManyReinforcementsCanGet(hero, rhs);
};
std::vector<const CGTownInstance *> townsReachable;
BOOST_FOREACH(const CGTownInstance *t, cb->getTownsInfo())
{
if(!t->visitingHero && howManyReinforcementsCanGet(h,t))
if(!t->visitingHero && howManyReinforcementsCanGet(hero,t))
{
if(isReachable(t))
townsReachable.push_back(t);
@ -2934,7 +2950,7 @@ bool isWeeklyRevisitable (const CGObjectInstance * obj)
return false;
}
bool shouldVisit (const CGHeroInstance * h, const CGObjectInstance * obj)
bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
{
switch (obj->ID)
{
@ -2986,7 +3002,7 @@ bool shouldVisit (const CGHeroInstance * h, const CGObjectInstance * obj)
return true;
}
int3 SectorMap::firstTileToGet(const CGHeroInstance *h, crint3 dst)
int3 SectorMap::firstTileToGet(HeroPtr h, crint3 dst)
{
int sourceSector = retreiveTile(h->visitablePos()),
destinationSector = retreiveTile(dst);
@ -3209,4 +3225,68 @@ ObjectIdRef::ObjectIdRef(const CGObjectInstance *obj) : id(obj->id)
bool ObjectIdRef::operator<(const ObjectIdRef &rhs) const
{
return id < rhs.id;
}
}
HeroPtr::HeroPtr(const CGHeroInstance *H)
{
if(!H)
{
//init from nullptr should equal to default init
*this = HeroPtr();
return;
}
h = H;
name = h->name;
hid = H->subID;
// infosCount[ai->playerID][hid]++;
}
HeroPtr::HeroPtr()
{
h = nullptr;
hid = -1;
}
HeroPtr::~HeroPtr()
{
// if(hid >= 0)
// infosCount[ai->playerID][hid]--;
}
bool HeroPtr::operator<(const HeroPtr &rhs) const
{
return hid < rhs.hid;
}
const CGHeroInstance * HeroPtr::get(bool doWeExpectNull /*= false*/) const
{
//TODO? check if these all assertions every time we get info about hero affect efficiency
//
//behave terribly when attempting unauthorised access to hero that is not ours (or was lost)
assert(doWeExpectNull || h);
if(h)
{
assert(cb->getObj(h->id));
assert(h->tempOwner == ai->playerID);
}
return h;
}
const CGHeroInstance * HeroPtr::operator->() const
{
return get();
}
bool HeroPtr::validAndSet() const
{
return get(true);
}
const CGHeroInstance * HeroPtr::operator*() const
{
return get();
}

View File

@ -2,6 +2,34 @@
typedef const int3& crint3;
typedef const std::string& crstring;
//provisional class for AI to store a reference to an owned hero object
//checks if it's valid on access, should be used in place of const CGHeroInstance*
struct HeroPtr
{
const CGHeroInstance *h;
int hid; //hero id (object subID or type ID)
public:
std::string name;
HeroPtr();
HeroPtr(const CGHeroInstance *H);
~HeroPtr();
operator bool() const
{
return validAndSet();
}
bool operator<(const HeroPtr &rhs) const;
const CGHeroInstance *operator->() const;
const CGHeroInstance *operator*() const; //not that consistent with -> but all interfaces use CGHeroInstance*, so it's convenient
const CGHeroInstance *get(bool doWeExpectNull = false) const;
bool validAndSet() const;
};
enum BattleState
{
NO_BATTLE,
@ -87,7 +115,6 @@ struct CGoal
objid = -1;
aid = -1;
tile = int3(-1, -1, -1);
hero = NULL;
town = NULL;
}
@ -102,7 +129,7 @@ struct CGoal
int objid; SETTER(int, objid)
int aid; SETTER(int, aid)
int3 tile; SETTER(int3, tile)
const CGHeroInstance *hero; SETTER(CGHeroInstance *, hero)
HeroPtr hero; SETTER(HeroPtr, hero)
const CGTownInstance *town; SETTER(CGTownInstance *, town)
int bid; SETTER(int, bid)
};
@ -141,7 +168,7 @@ struct SectorMap
void makeParentBFS(crint3 source);
int3 firstTileToGet(const CGHeroInstance *h, crint3 dst); //if h wants to reach tile dst, which tile he should visit to clear the way?
int3 firstTileToGet(HeroPtr h, crint3 dst); //if h wants to reach tile dst, which tile he should visit to clear the way?
};
struct CIssueCommand : CGoal
@ -188,10 +215,10 @@ public:
std::map<const CGObjectInstance *, const CGObjectInstance *> knownSubterraneanGates;
std::vector<const CGObjectInstance *> visitedThisWeek; //only OPWs
std::map<const CGHeroInstance *, std::vector<const CGTownInstance *> > townVisitsThisWeek;
std::map<HeroPtr, std::vector<const CGTownInstance *> > townVisitsThisWeek;
std::map<const CGHeroInstance *, CGoal> lockedHeroes; //TODO: allow non-elementar objectives
std::map<const CGHeroInstance *, std::vector<const CGObjectInstance *> > reservedHeroesMap; //objects reserved by specific heroes
std::map<HeroPtr, CGoal> lockedHeroes; //TODO: allow non-elementar objectives
std::map<HeroPtr, std::vector<const CGObjectInstance *> > reservedHeroesMap; //objects reserved by specific heroes
std::vector<const CGObjectInstance *> visitableObjs;
std::vector<const CGObjectInstance *> alreadyVisited;
@ -212,8 +239,8 @@ public:
void tryRealize(CGoal g);
int3 explorationBestNeighbour(int3 hpos, int radius, const CGHeroInstance * h);
int3 explorationNewPoint(int radius, const CGHeroInstance * h, std::vector<std::vector<int3> > &tiles);
int3 explorationBestNeighbour(int3 hpos, int radius, HeroPtr h);
int3 explorationNewPoint(int radius, HeroPtr h, std::vector<std::vector<int3> > &tiles);
void recruitHero();
virtual void init(CCallback * CB);
@ -284,27 +311,29 @@ public:
void buildArmyIn(const CGTownInstance * t);
void striveToGoal(const CGoal &ultimateGoal);
void endTurn();
void wander(const CGHeroInstance * h);
void setGoal (const CGHeroInstance *h, const CGoal goal);
void setGoal (const CGHeroInstance *h, EGoals goalType = INVALID);
void wander(HeroPtr h);
void setGoal(HeroPtr h, const CGoal goal);
void setGoal(HeroPtr h, EGoals goalType = INVALID);
void completeGoal (const CGoal goal); //safely removes goal from reserved hero
void recruitHero(const CGTownInstance * t);
std::vector<const CGObjectInstance *> getPossibleDestinations(const CGHeroInstance *h);
std::vector<const CGObjectInstance *> getPossibleDestinations(HeroPtr h);
void buildStructure(const CGTownInstance * t);
//void recruitCreatures(const CGTownInstance * t);
void recruitCreatures(const CGDwelling * d);
void pickBestCreatures(const CArmedInstance * army, const CArmedInstance * source); //called when we can't find a slot for new stack
void moveCreaturesToHero(const CGTownInstance * t);
bool goVisitObj(const CGObjectInstance * obj, const CGHeroInstance * h);
void performObjectInteraction(const CGObjectInstance * obj, const CGHeroInstance * h);
bool goVisitObj(const CGObjectInstance * obj, HeroPtr h);
void performObjectInteraction(const CGObjectInstance * obj, HeroPtr h);
bool moveHeroToTile(int3 dst, const CGHeroInstance * h);
bool moveHeroToTile(int3 dst, HeroPtr h);
void lostHero(HeroPtr h); //should remove all references to hero (assigned tasks and so on)
void waitTillFree();
void addVisitableObj(const CGObjectInstance *obj);
void markObjectVisited (const CGObjectInstance *obj);
void reserveObject (const CGHeroInstance * h, const CGObjectInstance *obj);
void reserveObject (HeroPtr h, const CGObjectInstance *obj);
//void removeVisitableObj(const CGObjectInstance *obj);
void validateVisitableObjs();
void retreiveVisitableObjs(std::vector<const CGObjectInstance *> &out, bool includeOwned = false) const;
@ -312,15 +341,15 @@ public:
const CGObjectInstance *lookForArt(int aid) const;
bool isAccessible(const int3 &pos);
const CGHeroInstance *getHeroWithGrail() const;
HeroPtr getHeroWithGrail() const;
const CGObjectInstance *getUnvisitedObj(const boost::function<bool(const CGObjectInstance *)> &predicate);
bool isAccessibleForHero(const int3 & pos, const CGHeroInstance * h, bool includeAllies = false) const;
bool isAccessibleForHero(const int3 & pos, HeroPtr h, bool includeAllies = false) const;
const CGTownInstance *findTownWithTavern() const;
std::vector<const CGHeroInstance *> getUnblockedHeroes() const;
const CGHeroInstance *primaryHero() const;
std::vector<HeroPtr> getUnblockedHeroes() const;
HeroPtr primaryHero() const;
TResources estimateIncome() const;
bool containsSavedRes(const TResources &cost) const;
@ -336,4 +365,4 @@ bool objWithID(const CGObjectInstance *obj)
}
bool isWeeklyRevisitable (const CGObjectInstance * obj);
bool shouldVisit (const CGHeroInstance * h, const CGObjectInstance * obj);
bool shouldVisit (HeroPtr h, const CGObjectInstance * obj);