From fcdad0d323cfb94a145971d6b37c06bdeba0f129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Sat, 30 Jun 2012 23:48:40 +0000 Subject: [PATCH] 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. --- AI/VCAI/Fuzzy.h | 1 + AI/VCAI/StdInc.h | 2 + AI/VCAI/VCAI.cpp | 216 ++++++++++++++++++++++++++++++++--------------- AI/VCAI/VCAI.h | 71 +++++++++++----- 4 files changed, 201 insertions(+), 89 deletions(-) diff --git a/AI/VCAI/Fuzzy.h b/AI/VCAI/Fuzzy.h index fa2f37128..135bbfecf 100644 --- a/AI/VCAI/Fuzzy.h +++ b/AI/VCAI/Fuzzy.h @@ -1,3 +1,4 @@ +#pragma once #include "../FuzzyLite/FuzzyLite.h" /* diff --git a/AI/VCAI/StdInc.h b/AI/VCAI/StdInc.h index 59dc0896c..008993c65 100644 --- a/AI/VCAI/StdInc.h +++ b/AI/VCAI/StdInc.h @@ -26,6 +26,8 @@ #include "../../lib/CondSh.h" #include "../../lib/CStopWatch.h" +#include "Fuzzy.h" + #include #include diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index 008ca606f..cc2a775cb 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -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 cb; boost::thread_specific_ptr ai; +//std::map > 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 > 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 h1, std::pair h2) -> bool + //heroes tend to die in the process and loose their goals, unsafe to iterate it + std::vector > 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 VCAI::getPossibleDestinations(const CGHeroInstance *h) +std::vector VCAI::getPossibleDestinations(HeroPtr h) { validateVisitableObjs(); std::vector possibleDestinations; @@ -1289,7 +1296,7 @@ std::vector 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::functionsetSelection(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 VCAI::getUnblockedHeroes() const +std::vector VCAI::getUnblockedHeroes() const { - std::vector ret = cb->getHeroesInfo(); + std::vector 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 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 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 > &tiles) +int3 VCAI::explorationNewPoint(int radius, HeroPtr h, std::vector > &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 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 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; -} \ No newline at end of file +} + +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(); +} + diff --git a/AI/VCAI/VCAI.h b/AI/VCAI/VCAI.h index 740957330..9644000a7 100644 --- a/AI/VCAI/VCAI.h +++ b/AI/VCAI/VCAI.h @@ -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 knownSubterraneanGates; std::vector visitedThisWeek; //only OPWs - std::map > townVisitsThisWeek; + std::map > townVisitsThisWeek; - std::map lockedHeroes; //TODO: allow non-elementar objectives - std::map > reservedHeroesMap; //objects reserved by specific heroes + std::map lockedHeroes; //TODO: allow non-elementar objectives + std::map > reservedHeroesMap; //objects reserved by specific heroes std::vector visitableObjs; std::vector 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 > &tiles); + int3 explorationBestNeighbour(int3 hpos, int radius, HeroPtr h); + int3 explorationNewPoint(int radius, HeroPtr h, std::vector > &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 getPossibleDestinations(const CGHeroInstance *h); + std::vector 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 &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 &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 getUnblockedHeroes() const; - const CGHeroInstance *primaryHero() const; + std::vector 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); \ No newline at end of file +bool shouldVisit (HeroPtr h, const CGObjectInstance * obj); \ No newline at end of file