diff --git a/AI/VCAI/Goals.cpp b/AI/VCAI/Goals.cpp index 4d97047cd..acc1f8543 100644 --- a/AI/VCAI/Goals.cpp +++ b/AI/VCAI/Goals.cpp @@ -67,7 +67,7 @@ std::string Goals::CGoal::name() const //TODO: virtualize } } -#define I_AM_ELEMENTAR return Goals::CGoal(*this).setisElementar(true) //FIXME: we loose some information about clas here? +#define I_AM_ELEMENTAR return (*this).setisElementar(true) TSubgoal Win::whatToDoToAchieve() { @@ -83,11 +83,11 @@ TSubgoal Win::whatToDoToAchieve() switch(cond) { case EVictoryConditionType::ARTIFACT: - return CGoal(GET_ART_TYPE).setaid(vc.objectId); + return Goals::GetArtOfType().setaid(vc.objectId); case EVictoryConditionType::BEATHERO: - return CGoal(GET_OBJ).setobjid(vc.obj->id.getNum()); + return Goals::GetObj(vc.obj->id.getNum()); case EVictoryConditionType::BEATMONSTER: - return CGoal(GET_OBJ).setobjid(vc.obj->id.getNum()); + return Goals::GetObj(vc.obj->id.getNum()); case EVictoryConditionType::BUILDCITY: //TODO build castle/capitol break; @@ -99,7 +99,7 @@ TSubgoal Win::whatToDoToAchieve() if(h->visitedTown && !vstd::contains(h->visitedTown->forbiddenBuildings, BuildingID::GRAIL)) { const CGTownInstance *t = h->visitedTown; - return CGoal(BUILD_STRUCTURE).setbid(BuildingID::GRAIL).settown(t); + return Goals::BuildThis().setbid(BuildingID::GRAIL).settown(t); } else { @@ -113,7 +113,7 @@ TSubgoal Win::whatToDoToAchieve() boost::sort(towns, isCloser); if(towns.size()) { - return CGoal(VISIT_TILE).sethero(h).settile(towns.front()->visitablePos()); + return Goals::VisitTile(towns.front()->visitablePos()).sethero(h); } } } @@ -121,25 +121,25 @@ TSubgoal Win::whatToDoToAchieve() int3 grailPos = cb->getGrailPos(ratio); if(ratio > 0.99) { - return CGoal(DIG_AT_TILE).settile(grailPos); + return Goals::DigAtTile().settile(grailPos); } //TODO: use FIND_OBJ else if(const CGObjectInstance * obj = ai->getUnvisitedObj(objWithID)) //there are unvisited Obelisks { - return CGoal(GET_OBJ).setobjid(obj->id.getNum()); + return Goals::GetObj(obj->id.getNum()); } else - return CGoal(EXPLORE); + return Goals::Explore(); } break; case EVictoryConditionType::CAPTURECITY: - return CGoal(GET_OBJ).setobjid(vc.obj->id.getNum()); + return Goals::GetObj(vc.obj->id.getNum()); case EVictoryConditionType::GATHERRESOURCE: - return CGoal(COLLECT_RES).setresID(static_cast(vc.objectId)).setvalue(vc.count); + return Goals::CollectRes().setresID(static_cast(vc.objectId)).setvalue(vc.count); //TODO mines? piles? marketplace? //save? break; case EVictoryConditionType::GATHERTROOP: - return CGoal(GATHER_TROOPS).setobjid(vc.objectId).setvalue(vc.count); + return Goals::GatherTroops().setobjid(vc.objectId).setvalue(vc.count); break; case EVictoryConditionType::TAKEDWELLINGS: break; @@ -148,7 +148,7 @@ TSubgoal Win::whatToDoToAchieve() case EVictoryConditionType::TRANSPORTITEM: break; case EVictoryConditionType::WINSTANDARD: - return CGoal(CONQUER); + return Goals::Conquer(); default: assert(0); } @@ -180,35 +180,35 @@ TSubgoal FindObj::whatToDoToAchieve() } } if (o && isReachable(o)) - return CGoal(GET_OBJ).setobjid(o->id.getNum()); + return Goals::GetObj(o->id.getNum()); else - return CGoal(EXPLORE); + return Goals::Explore(); } TSubgoal GetObj::whatToDoToAchieve() { const CGObjectInstance * obj = cb->getObj(ObjectInstanceID(objid)); if(!obj) - return CGoal(EXPLORE); + return Goals::Explore(); int3 pos = obj->visitablePos(); - return CGoal(VISIT_TILE).settile(pos); + return Goals::VisitTile(pos); } TSubgoal VisitHero::whatToDoToAchieve() { const CGObjectInstance * obj = cb->getObj(ObjectInstanceID(objid)); if(!obj) - return CGoal(EXPLORE); + return Goals::Explore(); int3 pos = obj->visitablePos(); if (hero && ai->isAccessibleForHero(pos, hero, true) && isSafeToVisit(hero, pos)) //enemy heroes can get reinforcements - return CGoal(*this).settile(pos).setisElementar(true); + return (*this).settile(pos).setisElementar(true); } TSubgoal GetArtOfType::whatToDoToAchieve() { TSubgoal alternativeWay = CGoal::lookForArtSmart(aid); //TODO: use if(alternativeWay.invalid()) - return CGoal(FIND_OBJ).setobjid(Obj::ARTIFACT).setresID(aid); + return Goals::FindObj(Obj::ARTIFACT, aid); } TSubgoal ClearWayTo::whatToDoToAchieve() @@ -217,12 +217,12 @@ TSubgoal ClearWayTo::whatToDoToAchieve() if(!cb->isVisible(tile)) { logAi->errorStream() << "Clear way should be used with visible tiles!"; - return CGoal(EXPLORE); + return Goals::Explore(); } HeroPtr h = hero ? hero : ai->primaryHero(); if(!h) - return CGoal(RECRUIT_HERO); + return Goals::RecruitHero(); cb->setSelection(*h); @@ -235,7 +235,7 @@ TSubgoal ClearWayTo::whatToDoToAchieve() //if(isSafeToVisit(h, tileToHit)) if(isBlockedBorderGate(tileToHit)) { //FIXME: this way we'll not visit gate and activate quest :? - return CGoal(FIND_OBJ).setobjid(Obj::KEYMASTER).setresID(cb->getTile(tileToHit)->visitableObjects.back()->subID); + return Goals::FindObj (Obj::KEYMASTER, cb->getTile(tileToHit)->visitableObjects.back()->subID); } //FIXME: this code shouldn't be necessary @@ -253,7 +253,7 @@ TSubgoal ClearWayTo::whatToDoToAchieve() throw cannotFulfillGoalException(problem); } - return CGoal(VISIT_TILE).settile(tileToHit).sethero(h); //FIXME:: attempts to visit completely unreachable tile with hero results in stall + return Goals::VisitTile(tileToHit).sethero(h); //FIXME:: attempts to visit completely unreachable tile with hero results in stall //TODO czy istnieje lepsza droga? @@ -292,7 +292,7 @@ TSubgoal Explore::whatToDoToAchieve() 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 if (isSafeToVisit(hero, pos) && ai->isAccessibleForHero(pos, hero)) - return CGoal(VISIT_TILE).settile(pos).sethero(hero); + return Goals::VisitTile(pos).sethero(hero); } } else @@ -301,7 +301,7 @@ TSubgoal Explore::whatToDoToAchieve() { auto pos = obj->visitablePos(); if (ai->isAccessible (pos)) //TODO: check safety? - return CGoal(VISIT_TILE).settile(pos).sethero(hero); + return Goals::VisitTile(pos).sethero(hero); } } } @@ -329,12 +329,12 @@ TSubgoal Explore::whatToDoToAchieve() }); if (objs.size()) { - return CGoal (VISIT_TILE).settile(objs.front()->visitablePos()).sethero(hero).setisAbstract(true); + return Goals::VisitTile(objs.front()->visitablePos()).sethero(hero).setisAbstract(true); } else throw cannotFulfillGoalException("Cannot explore - no possible ways found!"); } - return CGoal(VISIT_TILE).settile(t).sethero(hero); + return Goals::VisitTile(t).sethero(hero); } auto hs = cb->getHeroesInfo(); @@ -347,7 +347,7 @@ TSubgoal Explore::whatToDoToAchieve() 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 - return CGoal(RECRUIT_HERO); + return Goals::RecruitHero(); else //find mobile hero with weakest army { hs = cb->getHeroesInfo(); @@ -358,7 +358,7 @@ TSubgoal Explore::whatToDoToAchieve() if (hs.empty()) { if (howManyHeroes < GameConstants::MAX_HEROES_PER_PLAYER) - return CGoal(RECRUIT_HERO); + return Goals::RecruitHero(); else throw cannotFulfillGoalException("No heroes with remaining MPs for exploring!\n"); } @@ -377,10 +377,10 @@ TSubgoal RecruitHero::whatToDoToAchieve() { const CGTownInstance *t = ai->findTownWithTavern(); if(!t) - return CGoal(BUILD_STRUCTURE).setbid(BuildingID::TAVERN); + return Goals::BuildThis().setbid(BuildingID::TAVERN); if(cb->getResourceAmount(Res::GOLD) < HERO_GOLD_COST) - return CGoal(COLLECT_RES).setresID(Res::GOLD).setvalue(HERO_GOLD_COST); + return Goals::CollectRes().setresID(Res::GOLD).setvalue(HERO_GOLD_COST); I_AM_ELEMENTAR; } @@ -388,7 +388,7 @@ TSubgoal RecruitHero::whatToDoToAchieve() TSubgoal VisitTile::whatToDoToAchieve() { if(!cb->isVisible(tile)) - return CGoal(EXPLORE); + return Goals::Explore(); if(hero && !ai->isAccessibleForHero(tile, hero)) hero = nullptr; @@ -397,7 +397,7 @@ TSubgoal VisitTile::whatToDoToAchieve() { if(cb->getHeroesInfo().empty()) { - return CGoal(RECRUIT_HERO); + return Goals::RecruitHero(); } for(const CGHeroInstance *h : cb->getHeroesInfo()) @@ -413,15 +413,15 @@ TSubgoal VisitTile::whatToDoToAchieve() if(hero) { if(isSafeToVisit(hero, tile)) - return CGoal(*this).setisElementar(true); + return (*this).setisElementar(true); else { - return CGoal(GATHER_ARMY).sethero(hero).setvalue(evaluateDanger(tile, *hero) * SAFE_ATTACK_CONSTANT); //TODO: should it be abstract? + return Goals::GatherArmy().sethero(hero).setvalue(evaluateDanger(tile, *hero) * SAFE_ATTACK_CONSTANT); //TODO: should it be abstract? } } else //inaccessible for all heroes { - return CGoal(CLEAR_WAY_TO).settile(tile); + return Goals::ClearWayTo(tile); } } @@ -431,10 +431,10 @@ TSubgoal DigAtTile::whatToDoToAchieve() if(firstObj && firstObj->ID == Obj::HERO && firstObj->tempOwner == ai->playerID) //we have hero at dest { const CGHeroInstance *h = dynamic_cast(firstObj); - return CGoal(*this).sethero(h).setisElementar(true); + return (*this).sethero(h).setisElementar(true); } - return CGoal(VISIT_TILE).settile(tile); + return Goals::VisitTile(tile); } TSubgoal BuildThis::whatToDoToAchieve() @@ -478,7 +478,7 @@ TSubgoal CollectRes::whatToDoToAchieve() for(const CGTownInstance *t : cb->getTownsInfo()) { if(cb->canBuildStructure(t, BuildingID::MARKETPLACE) == EBuildingState::ALLOWED) - return CGoal(BUILD_STRUCTURE).settown(t).setbid(BuildingID::MARKETPLACE); + return Goals::BuildThis().settown(t).setbid(BuildingID::MARKETPLACE); } } else @@ -500,11 +500,11 @@ TSubgoal CollectRes::whatToDoToAchieve() auto backObj = backOrNull(cb->getVisitableObjs(m->o->visitablePos())); //it'll be a hero if we have one there; otherwise marketplace assert(backObj); if(backObj->tempOwner != ai->playerID) - return CGoal(GET_OBJ).setobjid(m->o->id.getNum()); + return Goals::GetObj(m->o->id.getNum()); return setobjid(m->o->id.getNum()).setisElementar(true); } } - return CGoal(INVALID); //FIXME: unused? + return Goals::Invalid(); //FIXME: unused? } TSubgoal GatherTroops::whatToDoToAchieve() @@ -530,7 +530,7 @@ TSubgoal GatherTroops::whatToDoToAchieve() } else { - return CGoal (BUILD_STRUCTURE).settown(t).setbid(bid); + return Goals::BuildThis().settown(t).setbid(bid); } } } @@ -555,10 +555,10 @@ TSubgoal GatherTroops::whatToDoToAchieve() if (dwellings.size()) { boost::sort(dwellings, isCloser); - return CGoal(GET_OBJ).setobjid (dwellings.front()->id.getNum()); + return Goals::GetObj(dwellings.front()->id.getNum()); } else - return CGoal(EXPLORE); + return Goals::Explore(); //TODO: exchange troops between heroes } @@ -574,7 +574,7 @@ TSubgoal Conquer::whatToDoToAchieve() 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 - return CGoal(RECRUIT_HERO); + return Goals::RecruitHero(); else //find mobile hero with weakest army { hs = cb->getHeroesInfo(); @@ -585,7 +585,7 @@ TSubgoal Conquer::whatToDoToAchieve() if (hs.empty()) { if (howManyHeroes < GameConstants::MAX_HEROES_PER_PLAYER) - return CGoal(RECRUIT_HERO); + return Goals::RecruitHero(); else throw cannotFulfillGoalException("No heroes with remaining MPs for exploring!\n"); } @@ -614,7 +614,7 @@ TSubgoal Conquer::whatToDoToAchieve() } if(objs.empty()) - return CGoal(EXPLORE); //we need to find an enemy + return Goals::Explore(); //we need to find an enemy erase_if(objs, [&](const CGObjectInstance *obj) { @@ -632,13 +632,13 @@ TSubgoal Conquer::whatToDoToAchieve() ai->reserveObject(h, obj); //no one else will capture same object until we fail if (obj->ID == Obj::HERO) - return CGoal(VISIT_HERO).sethero(h).setobjid(obj->id.getNum()).setisAbstract(true); //track enemy hero + return Goals::VisitHero().sethero(h).setobjid(obj->id.getNum()).setisAbstract(true); //track enemy hero else - return CGoal(VISIT_TILE).sethero(h).settile(obj->visitablePos()); + return Goals::VisitTile(obj->visitablePos()).sethero(h); } } - return CGoal(EXPLORE); //enemy is inaccessible + return Goals::Explore(); //enemy is inaccessible } TSubgoal Build::whatToDoToAchieve() @@ -675,7 +675,7 @@ TSubgoal GatherArmy::whatToDoToAchieve() if(townsReachable.size()) //try towns first { boost::sort(townsReachable, compareReinforcements); - return CGoal(VISIT_TILE).sethero(hero).settile(townsReachable.back()->visitablePos()); + return Goals::VisitTile(townsReachable.back()->visitablePos()).sethero(hero); } else { @@ -698,9 +698,9 @@ TSubgoal GatherArmy::whatToDoToAchieve() secondaryPath = cb->getPathInfo(hero->visitablePos())->turns; if (primaryPath < secondaryPath) - return CGoal(VISIT_HERO).setisAbstract(true).setobjid(h->id.getNum()).sethero(hero); //go to the other hero if we are faster + return Goals::VisitHero().setisAbstract(true).setobjid(h->id.getNum()).sethero(hero); //go to the other hero if we are faster else - return CGoal(VISIT_HERO).setisAbstract(true).setobjid(hero->id.getNum()).sethero(h); //let the other hero come to us + return Goals::VisitHero().setisAbstract(true).setobjid(hero->id.getNum()).sethero(h); //let the other hero come to us } } @@ -736,7 +736,7 @@ TSubgoal GatherArmy::whatToDoToAchieve() return true; }); if(objs.empty()) //no possible objects, we did eveyrthing already - return CGoal(EXPLORE).sethero(hero); + return Goals::Explore().sethero(hero); //TODO: check if we can recruit any creatures there, evaluate army else { @@ -756,31 +756,31 @@ TSubgoal GatherArmy::whatToDoToAchieve() } } if (h && isSafeToVisit(h, pos) && ai->isAccessibleForHero(pos, h)) - return CGoal(VISIT_TILE).sethero(h).settile(pos); + return Goals::VisitTile(pos).sethero(h); } } } - return CGoal(EXPLORE).sethero(hero); //find dwelling. use current hero to prevent him from doing nothing. + return Goals::Explore().sethero(hero); //find dwelling. use current hero to prevent him from doing nothing. } TSubgoal CGoal::whatToDoToAchieve() { logAi->debugStream() << boost::format("Decomposing goal of type %s") % name(); - return CGoal(EXPLORE); + return Goals::Explore(); } TSubgoal CGoal::goVisitOrLookFor(const CGObjectInstance *obj) { if(obj) - return CGoal(GET_OBJ).setobjid(obj->id.getNum()); + return Goals::GetObj(obj->id.getNum()); else - return CGoal(EXPLORE); + return Goals::Explore(); } TSubgoal CGoal::lookForArtSmart(int aid) { - return CGoal(INVALID); + return Goals::Invalid(); } bool CGoal::invalid() const diff --git a/AI/VCAI/Goals.h b/AI/VCAI/Goals.h index e022aa6e5..b92041329 100644 --- a/AI/VCAI/Goals.h +++ b/AI/VCAI/Goals.h @@ -113,61 +113,73 @@ struct CGoal class Invalid : public CGoal { public: + Invalid() : CGoal (Goals::INVALID){}; TSubgoal whatToDoToAchieve() override; }; class Win : public CGoal { public: + Win() : CGoal (Goals::WIN){}; TSubgoal whatToDoToAchieve() override; }; class NotLose : public CGoal { public: + NotLose() : CGoal (Goals::DO_NOT_LOSE){}; TSubgoal whatToDoToAchieve() override; }; class Conquer : public CGoal { public: + Conquer() : CGoal (Goals::CONQUER){}; TSubgoal whatToDoToAchieve() override; }; class Build : public CGoal { public: + Build() : CGoal (Goals::BUILD){}; TSubgoal whatToDoToAchieve() override; }; class Explore : public CGoal { public: + Explore() : CGoal (Goals::EXPLORE){}; TSubgoal whatToDoToAchieve() override; }; class GatherArmy : public CGoal { public: + GatherArmy() : CGoal (Goals::GATHER_ARMY){}; TSubgoal whatToDoToAchieve() override; }; class BoostHero : public CGoal { public: + BoostHero() : CGoal (Goals::INVALID){}; //TODO TSubgoal whatToDoToAchieve() override; }; class RecruitHero : public CGoal { public: + RecruitHero() : CGoal (Goals::RECRUIT_HERO){}; TSubgoal whatToDoToAchieve() override; }; class BuildThis : public CGoal { public: + BuildThis() : CGoal (Goals::BUILD_STRUCTURE){}; TSubgoal whatToDoToAchieve() override; }; class CollectRes : public CGoal { public: + CollectRes() : CGoal (Goals::COLLECT_RES){}; TSubgoal whatToDoToAchieve() override; }; class GatherTroops : public CGoal { public: + GatherTroops() : CGoal (Goals::GATHER_TROOPS){}; TSubgoal whatToDoToAchieve() override; }; class GetObj : public CGoal @@ -175,7 +187,7 @@ class GetObj : public CGoal private: GetObj() {}; // empty constructor not allowed public: - GetObj(const int Objid) {setobjid(Objid);}; + GetObj(const int Objid) : CGoal(Goals::GET_OBJ) {setobjid(Objid);}; TSubgoal whatToDoToAchieve() override; }; class FindObj : public CGoal @@ -183,49 +195,52 @@ class FindObj : public CGoal private: FindObj() {}; // empty constructor not allowed public: - FindObj(int ID) {setobjid(ID);}; - FindObj(int ID, int subID) {setobjid(ID).setresID(subID);}; + FindObj(int ID) : CGoal(Goals::FIND_OBJ) {setobjid(ID);}; + FindObj(int ID, int subID) : CGoal(Goals::FIND_OBJ) {setobjid(ID).setresID(subID);}; TSubgoal whatToDoToAchieve() override; }; class VisitHero : public CGoal { public: + VisitHero() : CGoal (Goals::VISIT_HERO){}; TSubgoal whatToDoToAchieve() override; }; class GetArtOfType : public CGoal { public: + GetArtOfType() : CGoal (Goals::GET_ART_TYPE){}; TSubgoal whatToDoToAchieve() override; }; -class IssueCommand : public CGoal -{ - public: - TSubgoal whatToDoToAchieve() override; -}; -class VisitTile : public CGoal //tile, in conjunction with hero elementar; assumes tile is reachable +class VisitTile : public CGoal + //tile, in conjunction with hero elementar; assumes tile is reachable { private: VisitTile() {}; // empty constructor not allowed public: - VisitTile(int3 Tile) {settile(Tile);}; + VisitTile(int3 Tile) : CGoal (Goals::VISIT_TILE) {settile(Tile);}; TSubgoal whatToDoToAchieve() override; }; class ClearWayTo : public CGoal { public: + ClearWayTo(int3 Tile) : CGoal (Goals::CLEAR_WAY_TO) {settile(Tile);}; TSubgoal whatToDoToAchieve() override; }; -class DigAtTile : public CGoal //elementar with hero on tile +class DigAtTile : public CGoal + //elementar with hero on tile { public: + DigAtTile() : CGoal (Goals::DIG_AT_TILE){}; TSubgoal whatToDoToAchieve() override; }; -struct CIssueCommand : CGoal +class CIssueCommand : CGoal { std::function command; + public: CIssueCommand(std::function _command): CGoal(ISSUE_COMMAND), command(_command) {} + TSubgoal whatToDoToAchieve() override; }; } \ No newline at end of file diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index 022bbc2bd..6aa2eab7c 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -1697,11 +1697,11 @@ void VCAI::striveToGoal(const Goals::CGoal &ultimateGoal) if (ultimateGoal.invalid()) return; - Goals::CGoal abstractGoal; + Goals::CGoal &abstractGoal = Goals::CGoal(); //reference must be initialized while(1) { - Goals::CGoal goal = ultimateGoal; + Goals::CGoal &goal = const_cast(ultimateGoal); 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 while(!goal.isElementar && !goal.isAbstract && maxGoals) @@ -1710,7 +1710,7 @@ void VCAI::striveToGoal(const Goals::CGoal &ultimateGoal) try { boost::this_thread::interruption_point(); - goal = goal.whatToDoToAchieve(); + goal = goal.whatToDoToAchieve(); //FIXME: must keep information about goal class --maxGoals; } catch(std::exception &e) diff --git a/AI/VCAI/VCAI.h b/AI/VCAI/VCAI.h index 41dd0d7cb..0a4fc498f 100644 --- a/AI/VCAI/VCAI.h +++ b/AI/VCAI/VCAI.h @@ -231,7 +231,7 @@ public: void performTypicalActions(); void buildArmyIn(const CGTownInstance * t); - void striveToGoal(const Goals::CGoal &ultimateGoal); + void striveToGoal(const Goals::CGoal & ultimateGoal); void endTurn(); void wander(HeroPtr h); void setGoal(HeroPtr h, const Goals::CGoal goal);