1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-04-15 11:46:56 +02:00

- Compile fixes for MVS

- AI goals will now be handled by smart pointers
This commit is contained in:
DjWarmonger 2013-11-09 21:29:46 +00:00
parent 29e98b2d51
commit 1657f124e1
6 changed files with 107 additions and 95 deletions

View File

@ -67,7 +67,7 @@ std::string Goals::CGoal::name() const //TODO: virtualize
} }
} }
#define I_AM_ELEMENTAR return (*this).setisElementar(true) #define I_AM_ELEMENTAR return make_shared<Goals::CGoal>(setisElementar(true))
TSubgoal Win::whatToDoToAchieve() TSubgoal Win::whatToDoToAchieve()
{ {
@ -83,11 +83,11 @@ TSubgoal Win::whatToDoToAchieve()
switch(cond) switch(cond)
{ {
case EVictoryConditionType::ARTIFACT: case EVictoryConditionType::ARTIFACT:
return Goals::GetArtOfType().setaid(vc.objectId); return make_shared<Goals::CGoal> (Goals::GetArtOfType().setaid(vc.objectId));
case EVictoryConditionType::BEATHERO: case EVictoryConditionType::BEATHERO:
return Goals::GetObj(vc.obj->id.getNum()); return make_shared<Goals::CGoal> (Goals::GetObj(vc.obj->id.getNum()));
case EVictoryConditionType::BEATMONSTER: case EVictoryConditionType::BEATMONSTER:
return Goals::GetObj(vc.obj->id.getNum()); return make_shared<Goals::CGoal> (Goals::GetObj(vc.obj->id.getNum()));
case EVictoryConditionType::BUILDCITY: case EVictoryConditionType::BUILDCITY:
//TODO build castle/capitol //TODO build castle/capitol
break; break;
@ -99,7 +99,7 @@ TSubgoal Win::whatToDoToAchieve()
if(h->visitedTown && !vstd::contains(h->visitedTown->forbiddenBuildings, BuildingID::GRAIL)) if(h->visitedTown && !vstd::contains(h->visitedTown->forbiddenBuildings, BuildingID::GRAIL))
{ {
const CGTownInstance *t = h->visitedTown; const CGTownInstance *t = h->visitedTown;
return Goals::BuildThis().setbid(BuildingID::GRAIL).settown(t); return make_shared<Goals::CGoal> (Goals::BuildThis().setbid(BuildingID::GRAIL).settown(t));
} }
else else
{ {
@ -113,7 +113,7 @@ TSubgoal Win::whatToDoToAchieve()
boost::sort(towns, isCloser); boost::sort(towns, isCloser);
if(towns.size()) if(towns.size())
{ {
return Goals::VisitTile(towns.front()->visitablePos()).sethero(h); return make_shared<Goals::CGoal> (Goals::VisitTile(towns.front()->visitablePos()).sethero(h));
} }
} }
} }
@ -121,25 +121,25 @@ TSubgoal Win::whatToDoToAchieve()
int3 grailPos = cb->getGrailPos(ratio); int3 grailPos = cb->getGrailPos(ratio);
if(ratio > 0.99) if(ratio > 0.99)
{ {
return Goals::DigAtTile().settile(grailPos); return make_shared<Goals::CGoal> (Goals::DigAtTile().settile(grailPos));
} //TODO: use FIND_OBJ } //TODO: use FIND_OBJ
else if(const CGObjectInstance * obj = ai->getUnvisitedObj(objWithID<Obj::OBELISK>)) //there are unvisited Obelisks else if(const CGObjectInstance * obj = ai->getUnvisitedObj(objWithID<Obj::OBELISK>)) //there are unvisited Obelisks
{ {
return Goals::GetObj(obj->id.getNum()); return make_shared<Goals::CGoal> (Goals::GetObj(obj->id.getNum()));
} }
else else
return Goals::Explore(); return make_shared<Goals::CGoal> (Goals::Explore());
} }
break; break;
case EVictoryConditionType::CAPTURECITY: case EVictoryConditionType::CAPTURECITY:
return Goals::GetObj(vc.obj->id.getNum()); return make_shared<Goals::CGoal> (Goals::GetObj(vc.obj->id.getNum()));
case EVictoryConditionType::GATHERRESOURCE: case EVictoryConditionType::GATHERRESOURCE:
return Goals::CollectRes().setresID(static_cast<Res::ERes>(vc.objectId)).setvalue(vc.count); return make_shared<Goals::CGoal> (Goals::CollectRes().setresID(static_cast<Res::ERes>(vc.objectId)).setvalue(vc.count));
//TODO mines? piles? marketplace? //TODO mines? piles? marketplace?
//save? //save?
break; break;
case EVictoryConditionType::GATHERTROOP: case EVictoryConditionType::GATHERTROOP:
return Goals::GatherTroops().setobjid(vc.objectId).setvalue(vc.count); return make_shared<Goals::CGoal> (Goals::GatherTroops().setobjid(vc.objectId).setvalue(vc.count));
break; break;
case EVictoryConditionType::TAKEDWELLINGS: case EVictoryConditionType::TAKEDWELLINGS:
break; break;
@ -148,11 +148,11 @@ TSubgoal Win::whatToDoToAchieve()
case EVictoryConditionType::TRANSPORTITEM: case EVictoryConditionType::TRANSPORTITEM:
break; break;
case EVictoryConditionType::WINSTANDARD: case EVictoryConditionType::WINSTANDARD:
return Goals::Conquer(); return make_shared<Goals::CGoal> (Goals::Conquer());
default: default:
assert(0); assert(0);
} }
return TSubgoal(Goals::INVALID); return make_shared<Goals::CGoal> (Goals::INVALID);
} }
TSubgoal FindObj::whatToDoToAchieve() TSubgoal FindObj::whatToDoToAchieve()
@ -181,37 +181,37 @@ TSubgoal FindObj::whatToDoToAchieve()
} }
} }
if (o && isReachable(o)) if (o && isReachable(o))
return Goals::GetObj(o->id.getNum()); return make_shared<Goals::CGoal> (Goals::GetObj(o->id.getNum()));
else else
return Goals::Explore(); return make_shared<Goals::CGoal> (Goals::Explore());
} }
TSubgoal GetObj::whatToDoToAchieve() TSubgoal GetObj::whatToDoToAchieve()
{ {
const CGObjectInstance * obj = cb->getObj(ObjectInstanceID(objid)); const CGObjectInstance * obj = cb->getObj(ObjectInstanceID(objid));
if(!obj) if(!obj)
return Goals::Explore(); return make_shared<Goals::CGoal> (Goals::Explore());
int3 pos = obj->visitablePos(); int3 pos = obj->visitablePos();
return Goals::VisitTile(pos); return make_shared<Goals::CGoal> (Goals::VisitTile(pos));
} }
TSubgoal VisitHero::whatToDoToAchieve() TSubgoal VisitHero::whatToDoToAchieve()
{ {
const CGObjectInstance * obj = cb->getObj(ObjectInstanceID(objid)); const CGObjectInstance * obj = cb->getObj(ObjectInstanceID(objid));
if(!obj) if(!obj)
return Goals::Explore(); return make_shared<Goals::CGoal> (Goals::Explore());
int3 pos = obj->visitablePos(); int3 pos = obj->visitablePos();
if (hero && ai->isAccessibleForHero(pos, hero, true) && isSafeToVisit(hero, pos)) //enemy heroes can get reinforcements if (hero && ai->isAccessibleForHero(pos, hero, true) && isSafeToVisit(hero, pos)) //enemy heroes can get reinforcements
return (*this).settile(pos).setisElementar(true); return make_shared<Goals::CGoal> (settile(pos).setisElementar(true));
return TSubgoal(Goals::INVALID); return make_shared<Goals::CGoal> (Goals::INVALID);
} }
TSubgoal GetArtOfType::whatToDoToAchieve() TSubgoal GetArtOfType::whatToDoToAchieve()
{ {
TSubgoal alternativeWay = CGoal::lookForArtSmart(aid); //TODO: use TSubgoal alternativeWay = CGoal::lookForArtSmart(aid); //TODO: use
if(alternativeWay.invalid()) if(alternativeWay->invalid())
return Goals::FindObj(Obj::ARTIFACT, aid); return make_shared<Goals::CGoal> (Goals::FindObj(Obj::ARTIFACT, aid));
return TSubgoal(Goals::INVALID); return make_shared<Goals::CGoal> (Goals::INVALID);
} }
TSubgoal ClearWayTo::whatToDoToAchieve() TSubgoal ClearWayTo::whatToDoToAchieve()
@ -220,12 +220,12 @@ TSubgoal ClearWayTo::whatToDoToAchieve()
if(!cb->isVisible(tile)) if(!cb->isVisible(tile))
{ {
logAi->errorStream() << "Clear way should be used with visible tiles!"; logAi->errorStream() << "Clear way should be used with visible tiles!";
return Goals::Explore(); return make_shared<Goals::CGoal> (Goals::Explore());
} }
HeroPtr h = hero ? hero : ai->primaryHero(); HeroPtr h = hero ? hero : ai->primaryHero();
if(!h) if(!h)
return Goals::RecruitHero(); return make_shared<Goals::CGoal> (Goals::RecruitHero());
cb->setSelection(*h); cb->setSelection(*h);
@ -238,7 +238,7 @@ TSubgoal ClearWayTo::whatToDoToAchieve()
//if(isSafeToVisit(h, tileToHit)) //if(isSafeToVisit(h, tileToHit))
if(isBlockedBorderGate(tileToHit)) if(isBlockedBorderGate(tileToHit))
{ //FIXME: this way we'll not visit gate and activate quest :? { //FIXME: this way we'll not visit gate and activate quest :?
return Goals::FindObj (Obj::KEYMASTER, cb->getTile(tileToHit)->visitableObjects.back()->subID); return make_shared<Goals::CGoal> (Goals::FindObj (Obj::KEYMASTER, cb->getTile(tileToHit)->visitableObjects.back()->subID));
} }
//FIXME: this code shouldn't be necessary //FIXME: this code shouldn't be necessary
@ -256,7 +256,8 @@ TSubgoal ClearWayTo::whatToDoToAchieve()
throw cannotFulfillGoalException(problem); throw cannotFulfillGoalException(problem);
} }
return Goals::VisitTile(tileToHit).sethero(h); //FIXME:: attempts to visit completely unreachable tile with hero results in stall return make_shared<Goals::CGoal> (Goals::VisitTile(tileToHit).sethero(h));
//FIXME:: attempts to visit completely unreachable tile with hero results in stall
//TODO czy istnieje lepsza droga? //TODO czy istnieje lepsza droga?
@ -295,7 +296,7 @@ TSubgoal Explore::whatToDoToAchieve()
auto pos = obj->visitablePos(); auto pos = obj->visitablePos();
//FIXME: this confition fails if everything but guarded subterranen gate was explored. in this case we should gather army for hero //FIXME: this confition fails if everything but guarded subterranen gate was explored. in this case we should gather army for hero
if (isSafeToVisit(hero, pos) && ai->isAccessibleForHero(pos, hero)) if (isSafeToVisit(hero, pos) && ai->isAccessibleForHero(pos, hero))
return Goals::VisitTile(pos).sethero(hero); return make_shared<Goals::CGoal> (Goals::VisitTile(pos).sethero(hero));
} }
} }
else else
@ -304,7 +305,7 @@ TSubgoal Explore::whatToDoToAchieve()
{ {
auto pos = obj->visitablePos(); auto pos = obj->visitablePos();
if (ai->isAccessible (pos)) //TODO: check safety? if (ai->isAccessible (pos)) //TODO: check safety?
return Goals::VisitTile(pos).sethero(hero); return make_shared<Goals::CGoal> (Goals::VisitTile(pos).sethero(hero));
} }
} }
} }
@ -332,12 +333,12 @@ TSubgoal Explore::whatToDoToAchieve()
}); });
if (objs.size()) if (objs.size())
{ {
return Goals::VisitTile(objs.front()->visitablePos()).sethero(hero).setisAbstract(true); return make_shared<Goals::CGoal> (Goals::VisitTile(objs.front()->visitablePos()).sethero(hero).setisAbstract(true));
} }
else else
throw cannotFulfillGoalException("Cannot explore - no possible ways found!"); throw cannotFulfillGoalException("Cannot explore - no possible ways found!");
} }
return Goals::VisitTile(t).sethero(hero); return make_shared<Goals::CGoal> (Goals::VisitTile(t).sethero(hero));
} }
auto hs = cb->getHeroesInfo(); auto hs = cb->getHeroesInfo();
@ -350,7 +351,7 @@ TSubgoal Explore::whatToDoToAchieve()
if(hs.empty()) //all heroes are busy. buy new one if(hs.empty()) //all heroes are busy. buy new one
{ {
if (howManyHeroes < 3 && ai->findTownWithTavern()) //we may want to recruit second hero. TODO: make it smart finally if (howManyHeroes < 3 && ai->findTownWithTavern()) //we may want to recruit second hero. TODO: make it smart finally
return Goals::RecruitHero(); return make_shared<Goals::CGoal> (Goals::RecruitHero());
else //find mobile hero with weakest army else //find mobile hero with weakest army
{ {
hs = cb->getHeroesInfo(); hs = cb->getHeroesInfo();
@ -361,7 +362,7 @@ TSubgoal Explore::whatToDoToAchieve()
if (hs.empty()) if (hs.empty())
{ {
if (howManyHeroes < GameConstants::MAX_HEROES_PER_PLAYER) if (howManyHeroes < GameConstants::MAX_HEROES_PER_PLAYER)
return Goals::RecruitHero(); return make_shared<Goals::CGoal> (Goals::RecruitHero());
else else
throw cannotFulfillGoalException("No heroes with remaining MPs for exploring!\n"); throw cannotFulfillGoalException("No heroes with remaining MPs for exploring!\n");
} }
@ -371,7 +372,7 @@ TSubgoal Explore::whatToDoToAchieve()
const CGHeroInstance *h = hs.front(); const CGHeroInstance *h = hs.front();
return (*this).sethero(h).setisAbstract(true); return make_shared<Goals::CGoal> (sethero(h).setisAbstract(true));
I_AM_ELEMENTAR; //FIXME: how can this be called? I_AM_ELEMENTAR; //FIXME: how can this be called?
}; };
@ -380,10 +381,10 @@ TSubgoal RecruitHero::whatToDoToAchieve()
{ {
const CGTownInstance *t = ai->findTownWithTavern(); const CGTownInstance *t = ai->findTownWithTavern();
if(!t) if(!t)
return Goals::BuildThis().setbid(BuildingID::TAVERN); return make_shared<Goals::CGoal> (Goals::BuildThis().setbid(BuildingID::TAVERN));
if(cb->getResourceAmount(Res::GOLD) < HERO_GOLD_COST) if(cb->getResourceAmount(Res::GOLD) < HERO_GOLD_COST)
return Goals::CollectRes().setresID(Res::GOLD).setvalue(HERO_GOLD_COST); return make_shared<Goals::CGoal> (Goals::CollectRes().setresID(Res::GOLD).setvalue(HERO_GOLD_COST));
I_AM_ELEMENTAR; I_AM_ELEMENTAR;
} }
@ -391,7 +392,7 @@ TSubgoal RecruitHero::whatToDoToAchieve()
TSubgoal VisitTile::whatToDoToAchieve() TSubgoal VisitTile::whatToDoToAchieve()
{ {
if(!cb->isVisible(tile)) if(!cb->isVisible(tile))
return Goals::Explore(); return make_shared<Goals::CGoal> (Goals::Explore());
if(hero && !ai->isAccessibleForHero(tile, hero)) if(hero && !ai->isAccessibleForHero(tile, hero))
hero = nullptr; hero = nullptr;
@ -400,7 +401,7 @@ TSubgoal VisitTile::whatToDoToAchieve()
{ {
if(cb->getHeroesInfo().empty()) if(cb->getHeroesInfo().empty())
{ {
return Goals::RecruitHero(); return make_shared<Goals::CGoal> (Goals::RecruitHero());
} }
for(const CGHeroInstance *h : cb->getHeroesInfo()) for(const CGHeroInstance *h : cb->getHeroesInfo())
@ -416,15 +417,15 @@ TSubgoal VisitTile::whatToDoToAchieve()
if(hero) if(hero)
{ {
if(isSafeToVisit(hero, tile)) if(isSafeToVisit(hero, tile))
return (*this).setisElementar(true); return make_shared<Goals::CGoal>(setisElementar(true));
else else
{ {
return Goals::GatherArmy().sethero(hero).setvalue(evaluateDanger(tile, *hero) * SAFE_ATTACK_CONSTANT); //TODO: should it be abstract? return make_shared<Goals::CGoal>(Goals::GatherArmy().sethero(hero).setvalue(evaluateDanger(tile, *hero) * SAFE_ATTACK_CONSTANT)); //TODO: should it be abstract?
} }
} }
else //inaccessible for all heroes else //inaccessible for all heroes
{ {
return Goals::ClearWayTo(tile); return make_shared<Goals::CGoal>(Goals::ClearWayTo(tile));
} }
} }
@ -434,10 +435,10 @@ TSubgoal DigAtTile::whatToDoToAchieve()
if(firstObj && firstObj->ID == Obj::HERO && firstObj->tempOwner == ai->playerID) //we have hero at dest if(firstObj && firstObj->ID == Obj::HERO && firstObj->tempOwner == ai->playerID) //we have hero at dest
{ {
const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(firstObj); const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(firstObj);
return (*this).sethero(h).setisElementar(true); return make_shared<Goals::CGoal> (sethero(h).setisElementar(true));
} }
return Goals::VisitTile(tile); return make_shared<Goals::CGoal>(Goals::VisitTile(tile));
} }
TSubgoal BuildThis::whatToDoToAchieve() TSubgoal BuildThis::whatToDoToAchieve()
@ -481,7 +482,7 @@ TSubgoal CollectRes::whatToDoToAchieve()
for(const CGTownInstance *t : cb->getTownsInfo()) for(const CGTownInstance *t : cb->getTownsInfo())
{ {
if(cb->canBuildStructure(t, BuildingID::MARKETPLACE) == EBuildingState::ALLOWED) if(cb->canBuildStructure(t, BuildingID::MARKETPLACE) == EBuildingState::ALLOWED)
return Goals::BuildThis().settown(t).setbid(BuildingID::MARKETPLACE); return make_shared<Goals::CGoal>(Goals::BuildThis().settown(t).setbid(BuildingID::MARKETPLACE));
} }
} }
else else
@ -503,11 +504,11 @@ TSubgoal CollectRes::whatToDoToAchieve()
auto backObj = backOrNull(cb->getVisitableObjs(m->o->visitablePos())); //it'll be a hero if we have one there; otherwise marketplace auto backObj = backOrNull(cb->getVisitableObjs(m->o->visitablePos())); //it'll be a hero if we have one there; otherwise marketplace
assert(backObj); assert(backObj);
if(backObj->tempOwner != ai->playerID) if(backObj->tempOwner != ai->playerID)
return Goals::GetObj(m->o->id.getNum()); return make_shared<Goals::CGoal>(Goals::GetObj(m->o->id.getNum()));
return setobjid(m->o->id.getNum()).setisElementar(true); return make_shared<Goals::CGoal>(setobjid(m->o->id.getNum()).setisElementar(true));
} }
} }
return Goals::Invalid(); //FIXME: unused? return make_shared<Goals::CGoal>(Goals::Invalid()); //FIXME: unused?
} }
TSubgoal GatherTroops::whatToDoToAchieve() TSubgoal GatherTroops::whatToDoToAchieve()
@ -533,7 +534,7 @@ TSubgoal GatherTroops::whatToDoToAchieve()
} }
else else
{ {
return Goals::BuildThis().settown(t).setbid(bid); return make_shared<Goals::CGoal>(Goals::BuildThis().settown(t).setbid(bid));
} }
} }
} }
@ -558,10 +559,10 @@ TSubgoal GatherTroops::whatToDoToAchieve()
if (dwellings.size()) if (dwellings.size())
{ {
boost::sort(dwellings, isCloser); boost::sort(dwellings, isCloser);
return Goals::GetObj(dwellings.front()->id.getNum()); return make_shared<Goals::CGoal>(Goals::GetObj(dwellings.front()->id.getNum()));
} }
else else
return Goals::Explore(); return make_shared<Goals::CGoal>(Goals::Explore());
//TODO: exchange troops between heroes //TODO: exchange troops between heroes
} }
@ -577,7 +578,7 @@ TSubgoal Conquer::whatToDoToAchieve()
if(hs.empty()) //all heroes are busy. buy new one if(hs.empty()) //all heroes are busy. buy new one
{ {
if (howManyHeroes < 3 && ai->findTownWithTavern()) //we may want to recruit second hero. TODO: make it smart finally if (howManyHeroes < 3 && ai->findTownWithTavern()) //we may want to recruit second hero. TODO: make it smart finally
return Goals::RecruitHero(); return make_shared<Goals::CGoal>(Goals::RecruitHero());
else //find mobile hero with weakest army else //find mobile hero with weakest army
{ {
hs = cb->getHeroesInfo(); hs = cb->getHeroesInfo();
@ -588,7 +589,7 @@ TSubgoal Conquer::whatToDoToAchieve()
if (hs.empty()) if (hs.empty())
{ {
if (howManyHeroes < GameConstants::MAX_HEROES_PER_PLAYER) if (howManyHeroes < GameConstants::MAX_HEROES_PER_PLAYER)
return Goals::RecruitHero(); return make_shared<Goals::CGoal>(Goals::RecruitHero());
else else
throw cannotFulfillGoalException("No heroes with remaining MPs for exploring!\n"); throw cannotFulfillGoalException("No heroes with remaining MPs for exploring!\n");
} }
@ -617,7 +618,7 @@ TSubgoal Conquer::whatToDoToAchieve()
} }
if(objs.empty()) if(objs.empty())
return Goals::Explore(); //we need to find an enemy return make_shared<Goals::CGoal>(Goals::Explore()); //we need to find an enemy
erase_if(objs, [&](const CGObjectInstance *obj) erase_if(objs, [&](const CGObjectInstance *obj)
{ {
@ -635,13 +636,15 @@ TSubgoal Conquer::whatToDoToAchieve()
ai->reserveObject(h, obj); //no one else will capture same object until we fail ai->reserveObject(h, obj); //no one else will capture same object until we fail
if (obj->ID == Obj::HERO) if (obj->ID == Obj::HERO)
return Goals::VisitHero().sethero(h).setobjid(obj->id.getNum()).setisAbstract(true); //track enemy hero return make_shared<Goals::CGoal>(
Goals::VisitHero().sethero(h).setobjid(obj->id.getNum()).setisAbstract(true));
//track enemy hero
else else
return Goals::VisitTile(obj->visitablePos()).sethero(h); return make_shared<Goals::CGoal>(Goals::VisitTile(obj->visitablePos()).sethero(h));
} }
} }
return Goals::Explore(); //enemy is inaccessible return make_shared<Goals::CGoal>(Goals::Explore()); //enemy is inaccessible
} }
TSubgoal Build::whatToDoToAchieve() TSubgoal Build::whatToDoToAchieve()
@ -678,7 +681,8 @@ TSubgoal GatherArmy::whatToDoToAchieve()
if(townsReachable.size()) //try towns first if(townsReachable.size()) //try towns first
{ {
boost::sort(townsReachable, compareReinforcements); boost::sort(townsReachable, compareReinforcements);
return Goals::VisitTile(townsReachable.back()->visitablePos()).sethero(hero); return make_shared<Goals::CGoal>(
Goals::VisitTile(townsReachable.back()->visitablePos()).sethero(hero));
} }
else else
{ {
@ -701,9 +705,13 @@ TSubgoal GatherArmy::whatToDoToAchieve()
secondaryPath = cb->getPathInfo(hero->visitablePos())->turns; secondaryPath = cb->getPathInfo(hero->visitablePos())->turns;
if (primaryPath < secondaryPath) if (primaryPath < secondaryPath)
return Goals::VisitHero().setisAbstract(true).setobjid(h->id.getNum()).sethero(hero); //go to the other hero if we are faster return make_shared<Goals::CGoal>(
Goals::VisitHero().setisAbstract(true).setobjid(h->id.getNum()).sethero(hero));
//go to the other hero if we are faster
else else
return Goals::VisitHero().setisAbstract(true).setobjid(hero->id.getNum()).sethero(h); //let the other hero come to us return make_shared<Goals::CGoal>(
Goals::VisitHero().setisAbstract(true).setobjid(hero->id.getNum()).sethero(h))
; //let the other hero come to us
} }
} }
@ -739,7 +747,7 @@ TSubgoal GatherArmy::whatToDoToAchieve()
return true; return true;
}); });
if(objs.empty()) //no possible objects, we did eveyrthing already if(objs.empty()) //no possible objects, we did eveyrthing already
return Goals::Explore().sethero(hero); return make_shared<Goals::CGoal>(Goals::Explore().sethero(hero));
//TODO: check if we can recruit any creatures there, evaluate army //TODO: check if we can recruit any creatures there, evaluate army
else else
{ {
@ -759,31 +767,31 @@ TSubgoal GatherArmy::whatToDoToAchieve()
} }
} }
if (h && isSafeToVisit(h, pos) && ai->isAccessibleForHero(pos, h)) if (h && isSafeToVisit(h, pos) && ai->isAccessibleForHero(pos, h))
return Goals::VisitTile(pos).sethero(h); return make_shared<Goals::CGoal>(Goals::VisitTile(pos).sethero(h));
} }
} }
} }
return Goals::Explore().sethero(hero); //find dwelling. use current hero to prevent him from doing nothing. return make_shared<Goals::CGoal>(Goals::Explore().sethero(hero)); //find dwelling. use current hero to prevent him from doing nothing.
} }
TSubgoal CGoal::whatToDoToAchieve() TSubgoal CGoal::whatToDoToAchieve()
{ {
logAi->debugStream() << boost::format("Decomposing goal of type %s") % name(); logAi->debugStream() << boost::format("Decomposing goal of type %s") % name();
return Goals::Explore(); return make_shared<Goals::CGoal>(Goals::Explore());
} }
TSubgoal CGoal::goVisitOrLookFor(const CGObjectInstance *obj) TSubgoal CGoal::goVisitOrLookFor(const CGObjectInstance *obj)
{ {
if(obj) if(obj)
return Goals::GetObj(obj->id.getNum()); return make_shared<Goals::CGoal>(Goals::GetObj(obj->id.getNum()));
else else
return Goals::Explore(); return make_shared<Goals::CGoal>(Goals::Explore());
} }
TSubgoal CGoal::lookForArtSmart(int aid) TSubgoal CGoal::lookForArtSmart(int aid)
{ {
return Goals::Invalid(); return make_shared<Goals::CGoal>(Goals::Invalid());
} }
bool CGoal::invalid() const bool CGoal::invalid() const

View File

@ -21,7 +21,7 @@ struct HeroPtr;
namespace Goals namespace Goals
{ {
struct CGoal; struct CGoal;
typedef CGoal TSubgoal; typedef std::shared_ptr<Goals::CGoal> TSubgoal;
enum EGoals enum EGoals
{ {

View File

@ -18,6 +18,7 @@
extern FuzzyHelper *fh; extern FuzzyHelper *fh;
class CGVisitableOPW; class CGVisitableOPW;
class TSubgoal;
const double SAFE_ATTACK_CONSTANT = 1.5; const double SAFE_ATTACK_CONSTANT = 1.5;
const int GOLD_RESERVE = 10000; //when buying creatures we want to keep at least this much gold (10000 so at least we'll be able to reach capitol) const int GOLD_RESERVE = 10000; //when buying creatures we want to keep at least this much gold (10000 so at least we'll be able to reach capitol)
@ -1696,25 +1697,25 @@ void VCAI::striveToGoal(const Goals::CGoal &ultimateGoal)
if (ultimateGoal.invalid()) if (ultimateGoal.invalid())
return; return;
Goals::CGoal abstractGoal; //can't create reference from temporary std::shared_ptr<Goals::CGoal> abstractGoal = make_shared<Goals::CGoal>(Goals::Invalid());
while(1) while(1)
{ {
Goals::CGoal &goal = const_cast<Goals::CGoal&>(ultimateGoal); std::shared_ptr<Goals::CGoal> goal = make_shared<Goals::CGoal>(ultimateGoal);
logAi->debugStream() << boost::format("Striving to goal of type %s") % ultimateGoal.name(); logAi->debugStream() << boost::format("Striving to goal of type %s") % ultimateGoal.name();
int maxGoals = 100; //preventing deadlock for mutually dependent goals, FIXME: do not try to realize goal when loop didn't suceed int maxGoals = 100; //preventing deadlock for mutually dependent goals, FIXME: do not try to realize goal when loop didn't suceed
while(!goal.isElementar && !goal.isAbstract && maxGoals) while(!goal->isElementar && !goal->isAbstract && maxGoals)
{ {
logAi->debugStream() << boost::format("Considering goal %s") % goal.name(); logAi->debugStream() << boost::format("Considering goal %s") % goal->name();
try try
{ {
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
goal = goal.whatToDoToAchieve(); //FIXME: must keep information about goal class goal = goal->whatToDoToAchieve(); //FIXME: why it calls always base class?
--maxGoals; --maxGoals;
} }
catch(std::exception &e) catch(std::exception &e)
{ {
logAi->debugStream() << boost::format("Goal %s decomposition failed: %s") % goal.name() % e.what(); logAi->debugStream() << boost::format("Goal %s decomposition failed: %s") % goal->name() % e.what();
//setGoal (goal.hero, INVALID); //test: if we don't know how to realize goal, we should abandon it for now //setGoal (goal.hero, INVALID); //test: if we don't know how to realize goal, we should abandon it for now
return; return;
} }
@ -1730,26 +1731,26 @@ void VCAI::striveToGoal(const Goals::CGoal &ultimateGoal)
throw (e); throw (e);
} }
if (goal.hero) //lock this hero to fulfill ultimate goal if (goal->hero) //lock this hero to fulfill ultimate goal
{ {
if (maxGoals) if (maxGoals)
{ {
setGoal(goal.hero, goal); setGoal(goal->hero, *goal.get());
} }
else else
{ {
setGoal(goal.hero, Goals::INVALID); // we seemingly don't know what to do with hero setGoal(goal->hero, Goals::INVALID); // we seemingly don't know what to do with hero
} }
} }
if (goal.isAbstract) if (goal->isAbstract)
{ {
abstractGoal = goal; //allow only one abstract goal per call abstractGoal = goal; //allow only one abstract goal per call
logAi->debugStream() << boost::format("Choosing abstract goal %s") % goal.name(); logAi->debugStream() << boost::format("Choosing abstract goal %s") % goal->name();
break; break;
} }
else else
tryRealize(goal); tryRealize(*goal);
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
} }
@ -1760,36 +1761,38 @@ void VCAI::striveToGoal(const Goals::CGoal &ultimateGoal)
} }
catch(goalFulfilledException &e) catch(goalFulfilledException &e)
{ {
completeGoal (goal); completeGoal (*goal);
if (fulfillsGoal (goal, ultimateGoal) || maxGoals > 98) //completed goal was main goal //TODO: find better condition if (fulfillsGoal (*goal, ultimateGoal) || maxGoals > 98) //completed goal was main goal //TODO: find better condition
return; return;
} }
catch(std::exception &e) catch(std::exception &e)
{ {
logAi->debugStream() << boost::format("Failed to realize subgoal of type %s (greater goal type was %s), I will stop.") % goal.name() % ultimateGoal.name(); logAi->debugStream() << boost::format("Failed to realize subgoal of type %s (greater goal type was %s), I will stop.") % goal->name() % ultimateGoal.name();
logAi->debugStream() << boost::format("The error message was: %s") % e.what(); logAi->debugStream() << boost::format("The error message was: %s") % e.what();
break; break;
} }
} }
//TODO: save abstract goals not related to hero //TODO: save abstract goals not related to hero
if (!abstractGoal.invalid()) //try to realize our one goal //TODO: refactor, duplicated code
if (!abstractGoal->invalid()) //try to realize our one goal
{ {
while (1) while (1)
{ {
Goals::CGoal goal = Goals::CGoal(abstractGoal).setisAbstract(false); std::shared_ptr<Goals::CGoal> goal(abstractGoal);
goal->setisAbstract(false);
int maxGoals = 50; int maxGoals = 50;
while (!goal.isElementar && maxGoals) //find elementar goal and fulfill it while (!goal->isElementar && maxGoals) //find elementar goal and fulfill it
{ {
try try
{ {
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
goal = goal.whatToDoToAchieve(); goal = goal->whatToDoToAchieve();
--maxGoals; --maxGoals;
} }
catch(std::exception &e) catch(std::exception &e)
{ {
logAi->debugStream() << boost::format("Goal %s decomposition failed: %s") % goal.name() % e.what(); logAi->debugStream() << boost::format("Goal %s decomposition failed: %s") % goal->name() % e.what();
//setGoal (goal.hero, INVALID); //setGoal (goal.hero, INVALID);
return; return;
} }
@ -1802,7 +1805,7 @@ void VCAI::striveToGoal(const Goals::CGoal &ultimateGoal)
std::runtime_error e("Too many subgoals, don't know what to do"); std::runtime_error e("Too many subgoals, don't know what to do");
throw (e); throw (e);
} }
tryRealize(goal); tryRealize(*goal);
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
} }
catch(boost::thread_interrupted &e) catch(boost::thread_interrupted &e)
@ -1812,13 +1815,13 @@ void VCAI::striveToGoal(const Goals::CGoal &ultimateGoal)
} }
catch(goalFulfilledException &e) catch(goalFulfilledException &e)
{ {
completeGoal (goal); //FIXME: deduce that we have realized GET_OBJ goal completeGoal (*goal); //FIXME: deduce that we have realized GET_OBJ goal
if (fulfillsGoal (goal, abstractGoal) || maxGoals > 98) //completed goal was main goal if (fulfillsGoal (*goal, *abstractGoal) || maxGoals > 98) //completed goal was main goal
return; return;
} }
catch(std::exception &e) catch(std::exception &e)
{ {
logAi->debugStream() << boost::format("Failed to realize subgoal of type %s (greater goal type was %s), I will stop.") % goal.name() % ultimateGoal.name(); logAi->debugStream() << boost::format("Failed to realize subgoal of type %s (greater goal type was %s), I will stop.") % goal->name() % ultimateGoal.name();
logAi->debugStream() << boost::format("The error message was: %s") % e.what(); logAi->debugStream() << boost::format("The error message was: %s") % e.what();
break; break;
} }

View File

@ -41,4 +41,4 @@ struct DLL_LINKAGE BattleAction
static BattleAction makeEndOFTacticPhase(ui8 side); static BattleAction makeEndOFTacticPhase(ui8 side);
}; };
std::ostream & operator<<(std::ostream & os, const BattleAction & ba); DLL_EXPORT std::ostream & operator<<(std::ostream & os, const BattleAction & ba);

View File

@ -114,4 +114,4 @@ struct DLL_LINKAGE BattleHex
static BattleHex getClosestTile(bool attackerOwned, BattleHex initialPos, std::set<BattleHex> & possibilities); //TODO: vector or set? copying one to another is bad static BattleHex getClosestTile(bool attackerOwned, BattleHex initialPos, std::set<BattleHex> & possibilities); //TODO: vector or set? copying one to another is bad
}; };
std::ostream & operator<<(std::ostream & os, const BattleHex & hex); DLL_EXPORT std::ostream & operator<<(std::ostream & os, const BattleHex & hex);

View File

@ -10,6 +10,7 @@
#include "CModHandler.h" #include "CModHandler.h"
#include "CTownHandler.h" #include "CTownHandler.h"
#include "CObjectHandler.h" //for hero specialty #include "CObjectHandler.h" //for hero specialty
#include <math.h>
/* /*
* CHeroHandler.cpp, part of VCMI engine * CHeroHandler.cpp, part of VCMI engine
@ -203,7 +204,7 @@ void CHeroClassHandler::afterLoadFinalization()
continue; continue;
float chance = heroClass->defaultTavernChance * faction->town->defaultTavernChance; float chance = heroClass->defaultTavernChance * faction->town->defaultTavernChance;
heroClass->selectionProbability[faction->index] = round(sqrt(chance)); heroClass->selectionProbability[faction->index] = static_cast<int>(sqrt(chance) + 0.5); //FIXME: replace with std::round once MVS supports it
} }
} }
} }