Goals.cpp 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663
  1. /*
  2. * Goals.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "Goals.h"
  12. #include "VCAI.h"
  13. #include "FuzzyHelper.h"
  14. #include "ResourceManager.h"
  15. #include "BuildingManager.h"
  16. #include "../../lib/mapping/CMap.h" //for victory conditions
  17. #include "../../lib/CPathfinder.h"
  18. #include "../../lib/StringConstants.h"
  19. #include "AIhelper.h"
  20. extern boost::thread_specific_ptr<CCallback> cb;
  21. extern boost::thread_specific_ptr<VCAI> ai;
  22. extern FuzzyHelper * fh;
  23. using namespace Goals;
  24. TSubgoal Goals::sptr(const AbstractGoal & tmp)
  25. {
  26. TSubgoal ptr;
  27. ptr.reset(tmp.clone());
  28. return ptr;
  29. }
  30. std::string Goals::AbstractGoal::name() const //TODO: virtualize
  31. {
  32. std::string desc;
  33. switch(goalType)
  34. {
  35. case INVALID:
  36. return "INVALID";
  37. case WIN:
  38. return "WIN";
  39. case DO_NOT_LOSE:
  40. return "DO NOT LOOSE";
  41. case CONQUER:
  42. return "CONQUER";
  43. case BUILD:
  44. return "BUILD";
  45. case EXPLORE:
  46. desc = "EXPLORE";
  47. break;
  48. case GATHER_ARMY:
  49. desc = "GATHER ARMY";
  50. break;
  51. case BUY_ARMY:
  52. return "BUY ARMY";
  53. break;
  54. case BOOST_HERO:
  55. desc = "BOOST_HERO (unsupported)";
  56. break;
  57. case RECRUIT_HERO:
  58. return "RECRUIT HERO";
  59. case BUILD_STRUCTURE:
  60. return "BUILD STRUCTURE";
  61. case COLLECT_RES:
  62. desc = "COLLECT RESOURCE " + GameConstants::RESOURCE_NAMES[resID] + " (" + boost::lexical_cast<std::string>(value) + ")";
  63. break;
  64. case TRADE:
  65. {
  66. auto obj = cb->getObjInstance(ObjectInstanceID(objid));
  67. if (obj)
  68. desc = (boost::format("TRADE %d of %s at %s") % value % GameConstants::RESOURCE_NAMES[resID] % obj->getObjectName()).str();
  69. }
  70. break;
  71. case GATHER_TROOPS:
  72. desc = "GATHER TROOPS";
  73. break;
  74. case VISIT_OBJ:
  75. {
  76. auto obj = cb->getObjInstance(ObjectInstanceID(objid));
  77. if(obj)
  78. desc = "GET OBJ " + obj->getObjectName();
  79. }
  80. break;
  81. case FIND_OBJ:
  82. desc = "FIND OBJ " + boost::lexical_cast<std::string>(objid);
  83. break;
  84. case VISIT_HERO:
  85. {
  86. auto obj = cb->getObjInstance(ObjectInstanceID(objid));
  87. if(obj)
  88. desc = "VISIT HERO " + obj->getObjectName();
  89. }
  90. break;
  91. case GET_ART_TYPE:
  92. desc = "GET ARTIFACT OF TYPE " + VLC->arth->artifacts[aid]->Name();
  93. break;
  94. case ISSUE_COMMAND:
  95. return "ISSUE COMMAND (unsupported)";
  96. case VISIT_TILE:
  97. desc = "VISIT TILE " + tile.toString();
  98. break;
  99. case CLEAR_WAY_TO:
  100. desc = "CLEAR WAY TO " + tile.toString();
  101. break;
  102. case DIG_AT_TILE:
  103. desc = "DIG AT TILE " + tile.toString();
  104. break;
  105. default:
  106. return boost::lexical_cast<std::string>(goalType);
  107. }
  108. if(hero.get(true)) //FIXME: used to crash when we lost hero and failed goal
  109. desc += " (" + hero->name + ")";
  110. return desc;
  111. }
  112. bool Goals::BuildBoat::operator==(const BuildBoat & other) const
  113. {
  114. return shipyard->o->id == other.shipyard->o->id;
  115. }
  116. bool Goals::Explore::operator==(const Explore & other) const
  117. {
  118. return other.hero.h == hero.h;
  119. }
  120. bool Goals::Conquer::operator==(const Conquer & other) const
  121. {
  122. return other.hero.h == hero.h;
  123. }
  124. bool Goals::GatherArmy::operator==(const GatherArmy & other) const
  125. {
  126. return other.hero.h == hero.h || town == other.town;
  127. }
  128. bool Goals::BuyArmy::operator==(const BuyArmy & other) const
  129. {
  130. return town == other.town && objid == other.objid;
  131. }
  132. bool Goals::BoostHero::operator==(const BoostHero & other) const
  133. {
  134. return other.hero.h == hero.h;
  135. }
  136. bool Goals::BuildThis::operator==(const BuildThis & other) const
  137. {
  138. return town == other.town && bid == other.bid;
  139. }
  140. bool Goals::CollectRes::operator==(const CollectRes & other) const
  141. {
  142. return resID == other.resID;
  143. }
  144. bool Goals::Trade::operator==(const Trade & other) const
  145. {
  146. return resID == other.resID;
  147. }
  148. bool Goals::GatherTroops::operator==(const GatherTroops & other) const
  149. {
  150. return objid == other.objid;
  151. }
  152. bool Goals::VisitObj::operator==(const VisitObj & other) const
  153. {
  154. return other.hero.h == hero.h && other.objid == objid;
  155. }
  156. bool Goals::FindObj::operator==(const FindObj & other) const
  157. {
  158. return other.hero.h == hero.h && other.objid == objid;
  159. }
  160. bool Goals::VisitHero::operator==(const VisitHero & other) const
  161. {
  162. return other.hero.h == hero.h && other.objid == objid;
  163. }
  164. bool Goals::GetArtOfType::operator==(const GetArtOfType & other) const
  165. {
  166. return other.hero.h == hero.h && other.objid == objid;
  167. }
  168. bool Goals::VisitTile::operator==(const VisitTile & other) const
  169. {
  170. return other.hero.h == hero.h && other.tile == tile;
  171. }
  172. bool Goals::ClearWayTo::operator==(const ClearWayTo & other) const
  173. {
  174. return other.hero.h == hero.h && other.tile == tile;
  175. }
  176. bool Goals::DigAtTile::operator==(const DigAtTile & other) const
  177. {
  178. return other.hero.h == hero.h && other.tile == tile;
  179. }
  180. bool Goals::AbstractGoal::operator==(const AbstractGoal & g) const
  181. {
  182. return false;
  183. }
  184. bool Goals::AbstractGoal::operator<(AbstractGoal & g) //for std::unique
  185. {
  186. //TODO: make sure it gets goals consistent with == operator
  187. if (goalType < g.goalType)
  188. return true;
  189. if (goalType > g.goalType)
  190. return false;
  191. if (hero < g.hero)
  192. return true;
  193. if (hero > g.hero)
  194. return false;
  195. if (tile < g.tile)
  196. return true;
  197. if (g.tile < tile)
  198. return false;
  199. if (objid < g.objid)
  200. return true;
  201. if (objid > g.objid)
  202. return false;
  203. if (town < g.town)
  204. return true;
  205. if (town > g.town)
  206. return false;
  207. if (value < g.value)
  208. return true;
  209. if (value > g.value)
  210. return false;
  211. if (priority < g.priority)
  212. return true;
  213. if (priority > g.priority)
  214. return false;
  215. if (resID < g.resID)
  216. return true;
  217. if (resID > g.resID)
  218. return false;
  219. if (bid < g.bid)
  220. return true;
  221. if (bid > g.bid)
  222. return false;
  223. if (aid < g.aid)
  224. return true;
  225. if (aid > g.aid)
  226. return false;
  227. return false;
  228. }
  229. //TODO: find out why the following are not generated automatically on MVS?
  230. namespace Goals
  231. {
  232. template<>
  233. void CGoal<Win>::accept(VCAI * ai)
  234. {
  235. ai->tryRealize(static_cast<Win &>(*this));
  236. }
  237. template<>
  238. void CGoal<Build>::accept(VCAI * ai)
  239. {
  240. ai->tryRealize(static_cast<Build &>(*this));
  241. }
  242. template<>
  243. float CGoal<Win>::accept(FuzzyHelper * f)
  244. {
  245. return f->evaluate(static_cast<Win &>(*this));
  246. }
  247. template<>
  248. float CGoal<Build>::accept(FuzzyHelper * f)
  249. {
  250. return f->evaluate(static_cast<Build &>(*this));
  251. }
  252. bool TSubgoal::operator==(const TSubgoal & rhs) const
  253. {
  254. return *get() == *rhs.get(); //comparison for Goals is overloaded, so they don't need to be identical to match
  255. }
  256. bool TSubgoal::operator<(const TSubgoal & rhs) const
  257. {
  258. return get() < rhs.get(); //compae by value
  259. }
  260. bool BuyArmy::fulfillsMe(TSubgoal goal)
  261. {
  262. //if (hero && hero != goal->hero)
  263. // return false;
  264. return town == goal->town && goal->value >= value; //can always buy more army
  265. }
  266. TSubgoal BuyArmy::whatToDoToAchieve()
  267. {
  268. //TODO: calculate the actual cost of units instead
  269. TResources price;
  270. price[Res::GOLD] = value * 0.4f; //some approximate value
  271. return ai->ah->whatToDo(price, iAmElementar()); //buy right now or gather resources
  272. }
  273. std::string BuyArmy::completeMessage() const
  274. {
  275. return boost::format("Bought army of value %d in town of %s") % value, town->name;
  276. }
  277. }
  278. TSubgoal Trade::whatToDoToAchieve()
  279. {
  280. return iAmElementar();
  281. }
  282. //TSubgoal AbstractGoal::whatToDoToAchieve()
  283. //{
  284. // logAi->debug("Decomposing goal of type %s",name());
  285. // return sptr (Goals::Explore());
  286. //}
  287. TSubgoal Win::whatToDoToAchieve()
  288. {
  289. auto toBool = [=](const EventCondition &)
  290. {
  291. // TODO: proper implementation
  292. // Right now even already fulfilled goals will be included into generated list
  293. // Proper check should test if event condition is already fulfilled
  294. // Easiest way to do this is to call CGameState::checkForVictory but this function should not be
  295. // used on client side or in AI code
  296. return false;
  297. };
  298. std::vector<EventCondition> goals;
  299. for(const TriggeredEvent & event : cb->getMapHeader()->triggeredEvents)
  300. {
  301. //TODO: try to eliminate human player(s) using loss conditions that have isHuman element
  302. if(event.effect.type == EventEffect::VICTORY)
  303. {
  304. boost::range::copy(event.trigger.getFulfillmentCandidates(toBool), std::back_inserter(goals));
  305. }
  306. }
  307. //TODO: instead of returning first encountered goal AI should generate list of possible subgoals
  308. for(const EventCondition & goal : goals)
  309. {
  310. switch(goal.condition)
  311. {
  312. case EventCondition::HAVE_ARTIFACT:
  313. return sptr(Goals::GetArtOfType(goal.objectType));
  314. case EventCondition::DESTROY:
  315. {
  316. if(goal.object)
  317. {
  318. auto obj = cb->getObj(goal.object->id);
  319. if(obj)
  320. if(obj->getOwner() == ai->playerID) //we can't capture our own object
  321. return sptr(Goals::Conquer());
  322. return sptr(Goals::VisitObj(goal.object->id.getNum()));
  323. }
  324. else
  325. {
  326. // TODO: destroy all objects of type goal.objectType
  327. // This situation represents "kill all creatures" condition from H3
  328. break;
  329. }
  330. }
  331. case EventCondition::HAVE_BUILDING:
  332. {
  333. // TODO build other buildings apart from Grail
  334. // goal.objectType = buidingID to build
  335. // goal.object = optional, town in which building should be built
  336. // Represents "Improve town" condition from H3 (but unlike H3 it consists from 2 separate conditions)
  337. if(goal.objectType == BuildingID::GRAIL)
  338. {
  339. if(auto h = ai->getHeroWithGrail())
  340. {
  341. //hero is in a town that can host Grail
  342. if(h->visitedTown && !vstd::contains(h->visitedTown->forbiddenBuildings, BuildingID::GRAIL))
  343. {
  344. const CGTownInstance * t = h->visitedTown;
  345. return sptr(Goals::BuildThis(BuildingID::GRAIL, t).setpriority(10));
  346. }
  347. else
  348. {
  349. auto towns = cb->getTownsInfo();
  350. towns.erase(boost::remove_if(towns,
  351. [](const CGTownInstance * t) -> bool
  352. {
  353. return vstd::contains(t->forbiddenBuildings, BuildingID::GRAIL);
  354. }),
  355. towns.end());
  356. boost::sort(towns, CDistanceSorter(h.get()));
  357. if(towns.size())
  358. {
  359. return sptr(Goals::VisitTile(towns.front()->visitablePos()).sethero(h));
  360. }
  361. }
  362. }
  363. double ratio = 0;
  364. // maybe make this check a bit more complex? For example:
  365. // 0.75 -> dig randomly within 3 tiles radius
  366. // 0.85 -> radius now 2 tiles
  367. // 0.95 -> 1 tile radius, position is fully known
  368. // AFAIK H3 AI does something like this
  369. int3 grailPos = cb->getGrailPos(&ratio);
  370. if(ratio > 0.99)
  371. {
  372. return sptr(Goals::DigAtTile(grailPos));
  373. } //TODO: use FIND_OBJ
  374. else if(const CGObjectInstance * obj = ai->getUnvisitedObj(objWithID<Obj::OBELISK>)) //there are unvisited Obelisks
  375. return sptr(Goals::VisitObj(obj->id.getNum()));
  376. else
  377. return sptr(Goals::Explore());
  378. }
  379. break;
  380. }
  381. case EventCondition::CONTROL:
  382. {
  383. if(goal.object)
  384. {
  385. auto objRelations = cb->getPlayerRelations(ai->playerID, goal.object->tempOwner);
  386. if(objRelations == PlayerRelations::ENEMIES)
  387. {
  388. return sptr(Goals::VisitObj(goal.object->id.getNum()));
  389. }
  390. else
  391. {
  392. // TODO: Defance
  393. break;
  394. }
  395. }
  396. else
  397. {
  398. //TODO: control all objects of type "goal.objectType"
  399. // Represents H3 condition "Flag all mines"
  400. break;
  401. }
  402. }
  403. case EventCondition::HAVE_RESOURCES:
  404. //TODO mines? piles? marketplace?
  405. //save?
  406. return sptr(Goals::CollectRes(static_cast<Res::ERes>(goal.objectType), goal.value));
  407. case EventCondition::HAVE_CREATURES:
  408. return sptr(Goals::GatherTroops(goal.objectType, goal.value));
  409. case EventCondition::TRANSPORT:
  410. {
  411. //TODO. merge with bring Grail to town? So AI will first dig grail, then transport it using this goal and builds it
  412. // Represents "transport artifact" condition:
  413. // goal.objectType = type of artifact
  414. // goal.object = destination-town where artifact should be transported
  415. break;
  416. }
  417. case EventCondition::STANDARD_WIN:
  418. return sptr(Goals::Conquer());
  419. // Conditions that likely don't need any implementation
  420. case EventCondition::DAYS_PASSED:
  421. break; // goal.value = number of days for condition to trigger
  422. case EventCondition::DAYS_WITHOUT_TOWN:
  423. break; // goal.value = number of days to trigger this
  424. case EventCondition::IS_HUMAN:
  425. break; // Should be only used in calculation of candidates (see toBool lambda)
  426. case EventCondition::CONST_VALUE:
  427. break;
  428. case EventCondition::HAVE_0:
  429. case EventCondition::HAVE_BUILDING_0:
  430. case EventCondition::DESTROY_0:
  431. //TODO: support new condition format
  432. return sptr(Goals::Conquer());
  433. default:
  434. assert(0);
  435. }
  436. }
  437. return sptr(Goals::Invalid());
  438. }
  439. TSubgoal BuildBoat::whatToDoToAchieve()
  440. {
  441. if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
  442. {
  443. return fh->chooseSolution(ai->ah->howToVisitObj(shipyard->o));
  444. }
  445. if(shipyard->shipyardStatus() != IShipyard::GOOD)
  446. {
  447. throw cannotFulfillGoalException("Shipyard is busy.");
  448. }
  449. TResources boatCost;
  450. shipyard->getBoatCost(boatCost);
  451. return ai->ah->whatToDo(boatCost, this->iAmElementar());
  452. }
  453. void BuildBoat::accept(VCAI * ai)
  454. {
  455. TResources boatCost;
  456. shipyard->getBoatCost(boatCost);
  457. if(!cb->getResourceAmount().canAfford(boatCost))
  458. {
  459. throw cannotFulfillGoalException("Can not afford boat");
  460. }
  461. if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
  462. {
  463. throw cannotFulfillGoalException("Can not build boat in enemy shipyard");
  464. }
  465. if(shipyard->shipyardStatus() != IShipyard::GOOD)
  466. {
  467. throw cannotFulfillGoalException("Shipyard is busy.");
  468. }
  469. cb->buildBoat(shipyard);
  470. }
  471. std::string BuildBoat::name() const
  472. {
  473. return "BuildBoat";
  474. }
  475. std::string BuildBoat::completeMessage() const
  476. {
  477. return "Boat have been built at " + shipyard->o->visitablePos().toString();
  478. }
  479. TSubgoal FindObj::whatToDoToAchieve()
  480. {
  481. const CGObjectInstance * o = nullptr;
  482. if(resID > -1) //specified
  483. {
  484. for(const CGObjectInstance * obj : ai->visitableObjs)
  485. {
  486. if(obj->ID == objid && obj->subID == resID)
  487. {
  488. o = obj;
  489. break; //TODO: consider multiple objects and choose best
  490. }
  491. }
  492. }
  493. else
  494. {
  495. for(const CGObjectInstance * obj : ai->visitableObjs)
  496. {
  497. if(obj->ID == objid)
  498. {
  499. o = obj;
  500. break; //TODO: consider multiple objects and choose best
  501. }
  502. }
  503. }
  504. if(o && ai->isAccessible(o->pos)) //we don't use isAccessibleForHero as we don't know which hero it is
  505. return sptr(Goals::VisitObj(o->id.getNum()));
  506. else
  507. return sptr(Goals::Explore());
  508. }
  509. bool Goals::FindObj::fulfillsMe(TSubgoal goal)
  510. {
  511. if (goal->goalType == Goals::VISIT_TILE) //visiting tile visits object at same time
  512. {
  513. if (!hero || hero == goal->hero)
  514. for (auto obj : cb->getVisitableObjs(goal->tile)) //check if any object on that tile matches criteria
  515. if (obj->visitablePos() == goal->tile) //object could be removed
  516. if (obj->ID == objid && obj->subID == resID) //same type and subtype
  517. return true;
  518. }
  519. return false;
  520. }
  521. std::string VisitObj::completeMessage() const
  522. {
  523. return "hero " + hero.get()->name + " captured Object ID = " + boost::lexical_cast<std::string>(objid);
  524. }
  525. TGoalVec VisitObj::getAllPossibleSubgoals()
  526. {
  527. TGoalVec goalList;
  528. const CGObjectInstance * obj = cb->getObjInstance(ObjectInstanceID(objid));
  529. if(!obj)
  530. {
  531. throw cannotFulfillGoalException("Object is missing - goal is invalid now!");
  532. }
  533. int3 pos = obj->visitablePos();
  534. if(hero)
  535. {
  536. if(ai->isAccessibleForHero(pos, hero))
  537. {
  538. if(isSafeToVisit(hero, pos))
  539. goalList.push_back(sptr(Goals::VisitObj(obj->id.getNum()).sethero(hero)));
  540. else
  541. goalList.push_back(sptr(Goals::GatherArmy(evaluateDanger(pos, hero.h) * SAFE_ATTACK_CONSTANT).sethero(hero).setisAbstract(true)));
  542. return goalList;
  543. }
  544. }
  545. else
  546. {
  547. for(auto potentialVisitor : cb->getHeroesInfo())
  548. {
  549. if(ai->isAccessibleForHero(pos, potentialVisitor))
  550. {
  551. if(isSafeToVisit(potentialVisitor, pos))
  552. goalList.push_back(sptr(Goals::VisitObj(obj->id.getNum()).sethero(potentialVisitor)));
  553. else
  554. goalList.push_back(sptr(Goals::GatherArmy(evaluateDanger(pos, potentialVisitor) * SAFE_ATTACK_CONSTANT).sethero(potentialVisitor).setisAbstract(true)));
  555. }
  556. }
  557. if(!goalList.empty())
  558. {
  559. return goalList;
  560. }
  561. }
  562. goalList.push_back(sptr(Goals::ClearWayTo(pos)));
  563. return goalList;
  564. }
  565. TSubgoal VisitObj::whatToDoToAchieve()
  566. {
  567. auto bestGoal = fh->chooseSolution(getAllPossibleSubgoals());
  568. if(bestGoal->goalType == Goals::VISIT_OBJ && bestGoal->hero)
  569. bestGoal->setisElementar(true);
  570. return bestGoal;
  571. }
  572. Goals::VisitObj::VisitObj(int Objid) : CGoal(Goals::VISIT_OBJ)
  573. {
  574. objid = Objid;
  575. tile = ai->myCb->getObjInstance(ObjectInstanceID(objid))->visitablePos();
  576. priority = 3;
  577. }
  578. bool VisitObj::fulfillsMe(TSubgoal goal)
  579. {
  580. if(goal->goalType == Goals::VISIT_TILE)
  581. {
  582. if (!hero || hero == goal->hero)
  583. {
  584. auto obj = cb->getObjInstance(ObjectInstanceID(objid));
  585. if (obj && obj->visitablePos() == goal->tile) //object could be removed
  586. return true;
  587. }
  588. }
  589. return false;
  590. }
  591. std::string VisitHero::completeMessage() const
  592. {
  593. return "hero " + hero.get()->name + " visited hero " + boost::lexical_cast<std::string>(objid);
  594. }
  595. TSubgoal VisitHero::whatToDoToAchieve()
  596. {
  597. const CGObjectInstance * obj = cb->getObj(ObjectInstanceID(objid));
  598. if(!obj)
  599. return sptr(Goals::Explore());
  600. int3 pos = obj->visitablePos();
  601. if(hero && ai->isAccessibleForHero(pos, hero, true) && isSafeToVisit(hero, pos)) //enemy heroes can get reinforcements
  602. {
  603. if(hero->pos == pos)
  604. logAi->error("Hero %s tries to visit himself.", hero.name);
  605. else
  606. {
  607. //can't use VISIT_TILE here as tile appears blocked by target hero
  608. //FIXME: elementar goal should not be abstract
  609. return sptr(Goals::VisitHero(objid).sethero(hero).settile(pos).setisElementar(true));
  610. }
  611. }
  612. return sptr(Goals::Invalid());
  613. }
  614. bool VisitHero::fulfillsMe(TSubgoal goal)
  615. {
  616. //TODO: VisitObj shoudl not be used for heroes, but...
  617. if(goal->goalType == Goals::VISIT_TILE)
  618. {
  619. auto obj = cb->getObj(ObjectInstanceID(objid));
  620. if (!obj)
  621. {
  622. logAi->error("Hero %s: VisitHero::fulfillsMe at %s: object %d not found", hero.name, goal->tile.toString(), objid);
  623. return false;
  624. }
  625. return obj->visitablePos() == goal->tile;
  626. }
  627. return false;
  628. }
  629. TSubgoal GetArtOfType::whatToDoToAchieve()
  630. {
  631. TSubgoal alternativeWay = CGoal::lookForArtSmart(aid); //TODO: use
  632. if(alternativeWay->invalid())
  633. return sptr(Goals::FindObj(Obj::ARTIFACT, aid));
  634. return sptr(Goals::Invalid());
  635. }
  636. TSubgoal ClearWayTo::whatToDoToAchieve()
  637. {
  638. assert(cb->isInTheMap(tile)); //set tile
  639. if(!cb->isVisible(tile))
  640. {
  641. logAi->error("Clear way should be used with visible tiles!");
  642. return sptr(Goals::Explore());
  643. }
  644. return (fh->chooseSolution(getAllPossibleSubgoals()));
  645. }
  646. bool Goals::ClearWayTo::fulfillsMe(TSubgoal goal)
  647. {
  648. if (goal->goalType == Goals::VISIT_TILE)
  649. {
  650. if (!hero || hero == goal->hero)
  651. return tile == goal->tile;
  652. }
  653. return false;
  654. }
  655. TGoalVec ClearWayTo::getAllPossibleSubgoals()
  656. {
  657. TGoalVec ret;
  658. std::vector<const CGHeroInstance *> heroes;
  659. if(hero)
  660. heroes.push_back(hero.h);
  661. else
  662. heroes = cb->getHeroesInfo();
  663. for(auto h : heroes)
  664. {
  665. //TODO: handle clearing way to allied heroes that are blocked
  666. //if ((hero && hero->visitablePos() == tile && hero == *h) || //we can't free the way ourselves
  667. // h->visitablePos() == tile) //we are already on that tile! what does it mean?
  668. // continue;
  669. //if our hero is trapped, make sure we request clearing the way from OUR perspective
  670. vstd::concatenate(ret, ai->ah->howToVisitTile(h, tile));
  671. }
  672. if(ret.empty() && ai->canRecruitAnyHero())
  673. ret.push_back(sptr(Goals::RecruitHero()));
  674. if(ret.empty())
  675. {
  676. logAi->warn("There is no known way to clear the way to tile %s", tile.toString());
  677. throw goalFulfilledException(sptr(Goals::ClearWayTo(tile))); //make sure asigned hero gets unlocked
  678. }
  679. return ret;
  680. }
  681. std::string Explore::completeMessage() const
  682. {
  683. return "Hero " + hero.get()->name + " completed exploration";
  684. }
  685. TSubgoal Explore::whatToDoToAchieve()
  686. {
  687. auto ret = fh->chooseSolution(getAllPossibleSubgoals());
  688. if(hero) //use best step for this hero
  689. {
  690. return ret;
  691. }
  692. else
  693. {
  694. if(ret->hero.get(true))
  695. return sptr(sethero(ret->hero.h).setisAbstract(true)); //choose this hero and then continue with him
  696. else
  697. return ret; //other solutions, like buying hero from tavern
  698. }
  699. }
  700. TGoalVec Explore::getAllPossibleSubgoals()
  701. {
  702. TGoalVec ret;
  703. std::vector<const CGHeroInstance *> heroes;
  704. if(hero)
  705. {
  706. heroes.push_back(hero.h);
  707. }
  708. else
  709. {
  710. //heroes = ai->getUnblockedHeroes();
  711. heroes = cb->getHeroesInfo();
  712. vstd::erase_if(heroes, [](const HeroPtr h)
  713. {
  714. if(ai->getGoal(h)->goalType == Goals::EXPLORE) //do not reassign hero who is already explorer
  715. return true;
  716. if(!ai->isAbleToExplore(h))
  717. return true;
  718. return !h->movement; //saves time, immobile heroes are useless anyway
  719. });
  720. }
  721. //try to use buildings that uncover map
  722. std::vector<const CGObjectInstance *> objs;
  723. for(auto obj : ai->visitableObjs)
  724. {
  725. if(!vstd::contains(ai->alreadyVisited, obj))
  726. {
  727. switch(obj->ID.num)
  728. {
  729. case Obj::REDWOOD_OBSERVATORY:
  730. case Obj::PILLAR_OF_FIRE:
  731. case Obj::CARTOGRAPHER:
  732. objs.push_back(obj);
  733. break;
  734. case Obj::MONOLITH_ONE_WAY_ENTRANCE:
  735. case Obj::MONOLITH_TWO_WAY:
  736. case Obj::SUBTERRANEAN_GATE:
  737. auto tObj = dynamic_cast<const CGTeleport *>(obj);
  738. assert(ai->knownTeleportChannels.find(tObj->channel) != ai->knownTeleportChannels.end());
  739. if(TeleportChannel::IMPASSABLE != ai->knownTeleportChannels[tObj->channel]->passability)
  740. objs.push_back(obj);
  741. break;
  742. }
  743. }
  744. else
  745. {
  746. switch(obj->ID.num)
  747. {
  748. case Obj::MONOLITH_TWO_WAY:
  749. case Obj::SUBTERRANEAN_GATE:
  750. auto tObj = dynamic_cast<const CGTeleport *>(obj);
  751. if(TeleportChannel::IMPASSABLE == ai->knownTeleportChannels[tObj->channel]->passability)
  752. break;
  753. for(auto exit : ai->knownTeleportChannels[tObj->channel]->exits)
  754. {
  755. if(!cb->getObj(exit))
  756. { // Always attempt to visit two-way teleports if one of channel exits is not visible
  757. objs.push_back(obj);
  758. break;
  759. }
  760. }
  761. break;
  762. }
  763. }
  764. }
  765. auto primaryHero = ai->primaryHero().h;
  766. for(auto h : heroes)
  767. {
  768. for(auto obj : objs) //double loop, performance risk?
  769. {
  770. auto waysToVisitObj = ai->ah->howToVisitObj(h, obj);
  771. vstd::concatenate(ret, waysToVisitObj);
  772. }
  773. int3 t = whereToExplore(h);
  774. if(t.valid())
  775. {
  776. ret.push_back(sptr(Goals::VisitTile(t).sethero(h)));
  777. }
  778. else
  779. {
  780. //FIXME: possible issues when gathering army to break
  781. if(hero.h == h || //exporation is assigned to this hero
  782. (!hero && h == primaryHero)) //not assigned to specific hero, let our main hero do the job
  783. {
  784. t = ai->explorationDesperate(h); //check this only ONCE, high cost
  785. if (t.valid()) //don't waste time if we are completely blocked
  786. {
  787. auto waysToVisitTile = ai->ah->howToVisitTile(h, t);
  788. vstd::concatenate(ret, waysToVisitTile);
  789. continue;
  790. }
  791. }
  792. ai->markHeroUnableToExplore(h); //there is no freely accessible tile, do not poll this hero anymore
  793. }
  794. }
  795. //we either don't have hero yet or none of heroes can explore
  796. if((!hero || ret.empty()) && ai->canRecruitAnyHero())
  797. ret.push_back(sptr(Goals::RecruitHero()));
  798. if(ret.empty())
  799. {
  800. throw goalFulfilledException(sptr(Goals::Explore().sethero(hero)));
  801. }
  802. //throw cannotFulfillGoalException("Cannot explore - no possible ways found!");
  803. return ret;
  804. }
  805. bool Explore::fulfillsMe(TSubgoal goal)
  806. {
  807. if(goal->goalType == Goals::EXPLORE)
  808. {
  809. if(goal->hero)
  810. return hero == goal->hero;
  811. else
  812. return true; //cancel ALL exploration
  813. }
  814. return false;
  815. }
  816. TSubgoal RecruitHero::whatToDoToAchieve()
  817. {
  818. const CGTownInstance * t = ai->findTownWithTavern();
  819. if(!t)
  820. return sptr(Goals::BuildThis(BuildingID::TAVERN).setpriority(2));
  821. TResources res;
  822. res[Res::GOLD] = GameConstants::HERO_GOLD_COST;
  823. return ai->ah->whatToDo(res, iAmElementar()); //either buy immediately, or collect res
  824. }
  825. std::string VisitTile::completeMessage() const
  826. {
  827. return "Hero " + hero.get()->name + " visited tile " + tile.toString();
  828. }
  829. TSubgoal VisitTile::whatToDoToAchieve()
  830. {
  831. auto ret = fh->chooseSolution(getAllPossibleSubgoals());
  832. if(ret->hero)
  833. {
  834. if(isSafeToVisit(ret->hero, tile) && ai->isAccessibleForHero(tile, ret->hero))
  835. {
  836. ret->setisElementar(true);
  837. return ret;
  838. }
  839. else
  840. {
  841. return sptr(Goals::GatherArmy(evaluateDanger(tile, *ret->hero) * SAFE_ATTACK_CONSTANT)
  842. .sethero(ret->hero).setisAbstract(true));
  843. }
  844. }
  845. return ret;
  846. }
  847. TGoalVec VisitTile::getAllPossibleSubgoals()
  848. {
  849. assert(cb->isInTheMap(tile));
  850. TGoalVec ret;
  851. if(!cb->isVisible(tile))
  852. ret.push_back(sptr(Goals::Explore())); //what sense does it make?
  853. else
  854. {
  855. std::vector<const CGHeroInstance *> heroes;
  856. if(hero)
  857. heroes.push_back(hero.h); //use assigned hero if any
  858. else
  859. heroes = cb->getHeroesInfo(); //use most convenient hero
  860. for(auto h : heroes)
  861. {
  862. if(ai->isAccessibleForHero(tile, h))
  863. ret.push_back(sptr(Goals::VisitTile(tile).sethero(h)));
  864. }
  865. if(ai->canRecruitAnyHero())
  866. ret.push_back(sptr(Goals::RecruitHero()));
  867. }
  868. if(ret.empty())
  869. {
  870. auto obj = vstd::frontOrNull(cb->getVisitableObjs(tile));
  871. if(obj && obj->ID == Obj::HERO && obj->tempOwner == ai->playerID) //our own hero stands on that tile
  872. {
  873. if(hero.get(true) && hero->id == obj->id) //if it's assigned hero, visit tile. If it's different hero, we can't visit tile now
  874. ret.push_back(sptr(Goals::VisitTile(tile).sethero(dynamic_cast<const CGHeroInstance *>(obj)).setisElementar(true)));
  875. else
  876. throw cannotFulfillGoalException("Tile is already occupied by another hero "); //FIXME: we should give up this tile earlier
  877. }
  878. else
  879. ret.push_back(sptr(Goals::ClearWayTo(tile)));
  880. }
  881. //important - at least one sub-goal must handle case which is impossible to fulfill (unreachable tile)
  882. return ret;
  883. }
  884. TSubgoal DigAtTile::whatToDoToAchieve()
  885. {
  886. const CGObjectInstance * firstObj = vstd::frontOrNull(cb->getVisitableObjs(tile));
  887. if(firstObj && firstObj->ID == Obj::HERO && firstObj->tempOwner == ai->playerID) //we have hero at dest
  888. {
  889. const CGHeroInstance * h = dynamic_cast<const CGHeroInstance *>(firstObj);
  890. sethero(h).setisElementar(true);
  891. return sptr(*this);
  892. }
  893. return sptr(Goals::VisitTile(tile));
  894. }
  895. TSubgoal BuildThis::whatToDoToAchieve()
  896. {
  897. auto b = BuildingID(bid);
  898. // find town if not set
  899. if (!town && hero)
  900. town = hero->visitedTown;
  901. if (!town)
  902. {
  903. for (const CGTownInstance * t : cb->getTownsInfo())
  904. {
  905. switch (cb->canBuildStructure(town, b))
  906. {
  907. case EBuildingState::ALLOWED:
  908. town = t;
  909. break; //TODO: look for prerequisites? this is not our reponsibility
  910. default:
  911. continue;
  912. }
  913. }
  914. }
  915. if (town) //we have specific town to build this
  916. {
  917. switch (cb->canBuildStructure(town, b))
  918. {
  919. case EBuildingState::ALLOWED:
  920. case EBuildingState::NO_RESOURCES:
  921. {
  922. auto res = town->town->buildings.at(BuildingID(bid))->resources;
  923. return ai->ah->whatToDo(res, iAmElementar()); //realize immediately or gather resources
  924. }
  925. break;
  926. default:
  927. throw cannotFulfillGoalException("Not possible to build");
  928. }
  929. }
  930. else
  931. throw cannotFulfillGoalException("Cannot find town to build this");
  932. }
  933. TGoalVec Goals::CollectRes::getAllPossibleSubgoals()
  934. {
  935. TGoalVec ret;
  936. auto givesResource = [this](const CGObjectInstance * obj) -> bool
  937. {
  938. //TODO: move this logic to object side
  939. //TODO: remember mithril exists
  940. //TODO: water objects
  941. //TODO: Creature banks
  942. //return false first from once-visitable, before checking if they were even visited
  943. switch (obj->ID.num)
  944. {
  945. case Obj::TREASURE_CHEST:
  946. return resID == Res::GOLD;
  947. break;
  948. case Obj::RESOURCE:
  949. return obj->subID == resID;
  950. break;
  951. case Obj::MINE:
  952. return (obj->subID == resID &&
  953. (cb->getPlayerRelations(obj->tempOwner, ai->playerID) == PlayerRelations::ENEMIES)); //don't capture our mines
  954. break;
  955. case Obj::CAMPFIRE:
  956. return true; //contains all resources
  957. break;
  958. case Obj::WINDMILL:
  959. switch (resID)
  960. {
  961. case Res::GOLD:
  962. case Res::WOOD:
  963. return false;
  964. }
  965. break;
  966. case Obj::WATER_WHEEL:
  967. if (resID != Res::GOLD)
  968. return false;
  969. break;
  970. case Obj::MYSTICAL_GARDEN:
  971. if ((resID != Res::GOLD) && (resID != Res::GEMS))
  972. return false;
  973. break;
  974. case Obj::LEAN_TO:
  975. case Obj::WAGON:
  976. if (resID != Res::GOLD)
  977. return false;
  978. break;
  979. default:
  980. return false;
  981. break;
  982. }
  983. return !vstd::contains(ai->alreadyVisited, obj); //for weekly / once visitable
  984. };
  985. std::vector<const CGObjectInstance *> objs;
  986. for (auto obj : ai->visitableObjs)
  987. {
  988. if (givesResource(obj))
  989. objs.push_back(obj);
  990. }
  991. for (auto h : cb->getHeroesInfo())
  992. {
  993. std::vector<const CGObjectInstance *> ourObjs(objs); //copy common objects
  994. for (auto obj : ai->reservedHeroesMap[h]) //add objects reserved by this hero
  995. {
  996. if (givesResource(obj))
  997. ourObjs.push_back(obj);
  998. }
  999. for (auto obj : ourObjs)
  1000. {
  1001. auto waysToGo = ai->ah->howToVisitObj(h, ObjectIdRef(obj));
  1002. vstd::concatenate(ret, waysToGo);
  1003. }
  1004. }
  1005. return ret;
  1006. }
  1007. TSubgoal CollectRes::whatToDoToAchieve()
  1008. {
  1009. auto goals = getAllPossibleSubgoals();
  1010. auto trade = whatToDoToTrade();
  1011. if (!trade->invalid())
  1012. goals.push_back(trade);
  1013. if (goals.empty())
  1014. return sptr(Goals::Explore()); //we can always do that
  1015. else
  1016. return fh->chooseSolution(goals); //TODO: evaluate trading
  1017. }
  1018. TSubgoal Goals::CollectRes::whatToDoToTrade()
  1019. {
  1020. std::vector<const IMarket *> markets;
  1021. std::vector<const CGObjectInstance *> visObjs;
  1022. ai->retrieveVisitableObjs(visObjs, true);
  1023. for (const CGObjectInstance * obj : visObjs)
  1024. {
  1025. if (const IMarket * m = IMarket::castFrom(obj, false))
  1026. {
  1027. if (obj->ID == Obj::TOWN && obj->tempOwner == ai->playerID && m->allowsTrade(EMarketMode::RESOURCE_RESOURCE))
  1028. markets.push_back(m);
  1029. else if (obj->ID == Obj::TRADING_POST)
  1030. markets.push_back(m);
  1031. }
  1032. }
  1033. boost::sort(markets, [](const IMarket * m1, const IMarket * m2) -> bool
  1034. {
  1035. return m1->getMarketEfficiency() < m2->getMarketEfficiency();
  1036. });
  1037. markets.erase(boost::remove_if(markets, [](const IMarket * market) -> bool
  1038. {
  1039. if (!(market->o->ID == Obj::TOWN && market->o->tempOwner == ai->playerID))
  1040. {
  1041. if (!ai->isAccessible(market->o->visitablePos()))
  1042. return true;
  1043. }
  1044. return false;
  1045. }), markets.end());
  1046. if (!markets.size())
  1047. {
  1048. for (const CGTownInstance * t : cb->getTownsInfo())
  1049. {
  1050. if (cb->canBuildStructure(t, BuildingID::MARKETPLACE) == EBuildingState::ALLOWED)
  1051. return sptr(Goals::BuildThis(BuildingID::MARKETPLACE, t).setpriority(2));
  1052. }
  1053. }
  1054. else
  1055. {
  1056. const IMarket * m = markets.back();
  1057. //attempt trade at back (best prices)
  1058. int howManyCanWeBuy = 0;
  1059. for (Res::ERes i = Res::WOOD; i <= Res::GOLD; vstd::advance(i, 1))
  1060. {
  1061. if (i == resID)
  1062. continue;
  1063. int toGive = -1, toReceive = -1;
  1064. m->getOffer(i, resID, toGive, toReceive, EMarketMode::RESOURCE_RESOURCE);
  1065. assert(toGive > 0 && toReceive > 0);
  1066. howManyCanWeBuy += toReceive * (ai->ah->freeResources()[i] / toGive);
  1067. }
  1068. if (howManyCanWeBuy >= value)
  1069. {
  1070. auto backObj = cb->getTopObj(m->o->visitablePos()); //it'll be a hero if we have one there; otherwise marketplace
  1071. assert(backObj);
  1072. auto objid = m->o->id.getNum();
  1073. if (backObj->tempOwner != ai->playerID) //top object not owned
  1074. {
  1075. return sptr(Goals::VisitObj(objid)); //just go there
  1076. }
  1077. else //either it's our town, or we have hero there
  1078. {
  1079. Goals::Trade trade(resID, value, objid);
  1080. return sptr(trade.setisElementar(true)); //we can do this immediately
  1081. }
  1082. }
  1083. }
  1084. return sptr(Goals::Invalid()); //cannot trade
  1085. }
  1086. bool CollectRes::fulfillsMe(TSubgoal goal)
  1087. {
  1088. if (goal->resID == resID)
  1089. if (goal->value >= value)
  1090. return true;
  1091. return false;
  1092. }
  1093. int GatherTroops::getCreaturesCount(const CArmedInstance * army)
  1094. {
  1095. int count = 0;
  1096. for(auto stack : army->Slots())
  1097. {
  1098. if(objid == stack.second->getCreatureID().num)
  1099. {
  1100. count += stack.second->count;
  1101. }
  1102. }
  1103. return count;
  1104. }
  1105. TSubgoal GatherTroops::whatToDoToAchieve()
  1106. {
  1107. auto heroes = cb->getHeroesInfo(true);
  1108. for(auto hero : heroes)
  1109. {
  1110. if(getCreaturesCount(hero) >= this->value)
  1111. {
  1112. logAi->trace("Completing GATHER_TROOPS by hero %s", hero->name);
  1113. throw goalFulfilledException(sptr(*this));
  1114. }
  1115. }
  1116. TGoalVec solutions = getAllPossibleSubgoals();
  1117. if(solutions.empty())
  1118. return sptr(Goals::Explore());
  1119. return fh->chooseSolution(solutions);
  1120. }
  1121. TGoalVec GatherTroops::getAllPossibleSubgoals()
  1122. {
  1123. TGoalVec solutions;
  1124. for(const CGTownInstance * t : cb->getTownsInfo())
  1125. {
  1126. int count = getCreaturesCount(t->getUpperArmy());
  1127. if(count >= this->value)
  1128. {
  1129. vstd::concatenate(solutions, ai->ah->howToVisitObj(t));
  1130. continue;
  1131. }
  1132. auto creature = VLC->creh->creatures[objid];
  1133. if(t->subID == creature->faction) //TODO: how to force AI to build unupgraded creatures? :O
  1134. {
  1135. auto creatures = vstd::tryAt(t->town->creatures, creature->level - 1);
  1136. if(!creatures)
  1137. continue;
  1138. int upgradeNumber = vstd::find_pos(*creatures, creature->idNumber);
  1139. if(upgradeNumber < 0)
  1140. continue;
  1141. BuildingID bid(BuildingID::DWELL_FIRST + creature->level - 1 + upgradeNumber * GameConstants::CREATURES_PER_TOWN);
  1142. if(t->hasBuilt(bid)) //this assumes only creatures with dwellings are assigned to faction
  1143. {
  1144. solutions.push_back(sptr(Goals::BuyArmy(t, creature->AIValue * this->value).setobjid(objid)));
  1145. }
  1146. /*else //disable random building requests for now - this code needs to know a lot of town/resource context to do more good than harm
  1147. {
  1148. return sptr(Goals::BuildThis(bid, t).setpriority(priority));
  1149. }*/
  1150. }
  1151. }
  1152. for(auto obj : ai->visitableObjs)
  1153. {
  1154. auto d = dynamic_cast<const CGDwelling *>(obj);
  1155. if(!d || obj->ID == Obj::TOWN)
  1156. continue;
  1157. for(auto creature : d->creatures)
  1158. {
  1159. if(creature.first) //there are more than 0 creatures avaliabe
  1160. {
  1161. for(auto type : creature.second)
  1162. {
  1163. if(type == objid && ai->ah->freeResources().canAfford(VLC->creh->creatures[type]->cost))
  1164. vstd::concatenate(solutions, ai->ah->howToVisitObj(obj));
  1165. }
  1166. }
  1167. }
  1168. }
  1169. return solutions;
  1170. //TODO: exchange troops between heroes
  1171. }
  1172. bool Goals::GatherTroops::fulfillsMe(TSubgoal goal)
  1173. {
  1174. if (!hero || hero == goal->hero) //we got army for desired hero or any hero
  1175. if (goal->objid == objid) //same creature type //TODO: consider upgrades?
  1176. if (goal->value >= value) //notify every time we get resources?
  1177. return true;
  1178. return false;
  1179. }
  1180. TSubgoal Conquer::whatToDoToAchieve()
  1181. {
  1182. return fh->chooseSolution(getAllPossibleSubgoals());
  1183. }
  1184. TGoalVec Conquer::getAllPossibleSubgoals()
  1185. {
  1186. TGoalVec ret;
  1187. auto conquerable = [](const CGObjectInstance * obj) -> bool
  1188. {
  1189. if(cb->getPlayerRelations(ai->playerID, obj->tempOwner) == PlayerRelations::ENEMIES)
  1190. {
  1191. switch(obj->ID.num)
  1192. {
  1193. case Obj::TOWN:
  1194. case Obj::HERO:
  1195. case Obj::CREATURE_GENERATOR1:
  1196. case Obj::MINE: //TODO: check ai->knownSubterraneanGates
  1197. return true;
  1198. }
  1199. }
  1200. return false;
  1201. };
  1202. std::vector<const CGObjectInstance *> objs;
  1203. for(auto obj : ai->visitableObjs)
  1204. {
  1205. if(conquerable(obj))
  1206. objs.push_back(obj);
  1207. }
  1208. for(auto h : cb->getHeroesInfo())
  1209. {
  1210. std::vector<const CGObjectInstance *> ourObjs(objs); //copy common objects
  1211. for(auto obj : ai->reservedHeroesMap[h]) //add objects reserved by this hero
  1212. {
  1213. if(conquerable(obj))
  1214. ourObjs.push_back(obj);
  1215. }
  1216. for(auto obj : ourObjs)
  1217. {
  1218. auto waysToGo = ai->ah->howToVisitObj(h, ObjectIdRef(obj));
  1219. vstd::concatenate(ret, waysToGo);
  1220. }
  1221. }
  1222. if(!objs.empty() && ai->canRecruitAnyHero()) //probably no point to recruit hero if we see no objects to capture
  1223. ret.push_back(sptr(Goals::RecruitHero()));
  1224. if(ret.empty())
  1225. ret.push_back(sptr(Goals::Explore())); //we need to find an enemy
  1226. return ret;
  1227. }
  1228. TGoalVec Goals::Build::getAllPossibleSubgoals()
  1229. {
  1230. TGoalVec ret;
  1231. for (const CGTownInstance * t : cb->getTownsInfo())
  1232. {
  1233. //start fresh with every town
  1234. ai->ah->getBuildingOptions(t);
  1235. auto immediateBuilding = ai->ah->immediateBuilding();
  1236. auto expensiveBuilding = ai->ah->expensiveBuilding();
  1237. //handling for early town development to save money and focus on income
  1238. if(!t->hasBuilt(ai->ah->getMaxPossibleGoldBuilding(t)) && expensiveBuilding.is_initialized())
  1239. {
  1240. auto potentialBuilding = expensiveBuilding.get();
  1241. switch(expensiveBuilding.get().bid)
  1242. {
  1243. case BuildingID::TOWN_HALL:
  1244. case BuildingID::CITY_HALL:
  1245. case BuildingID::CAPITOL:
  1246. case BuildingID::FORT:
  1247. case BuildingID::CITADEL:
  1248. case BuildingID::CASTLE:
  1249. //If above buildings are next to be bought, but no money... do not buy anything else, try to gather resources for these. Simple but has to suffice for now.
  1250. auto goal = ai->ah->whatToDo(potentialBuilding.price, sptr(Goals::BuildThis(potentialBuilding.bid, t).setpriority(2.25)));
  1251. ret.push_back(goal);
  1252. return ret;
  1253. break;
  1254. }
  1255. }
  1256. if (immediateBuilding.is_initialized())
  1257. {
  1258. ret.push_back(sptr(Goals::BuildThis(immediateBuilding.get().bid, t).setpriority(2))); //prioritize buildings we can build quick
  1259. }
  1260. else //try build later
  1261. {
  1262. if (expensiveBuilding.is_initialized())
  1263. {
  1264. auto potentialBuilding = expensiveBuilding.get(); //gather resources for any we can't afford
  1265. auto goal = ai->ah->whatToDo(potentialBuilding.price, sptr(Goals::BuildThis(potentialBuilding.bid, t).setpriority(0.5)));
  1266. ret.push_back(goal);
  1267. }
  1268. }
  1269. }
  1270. if (ret.empty())
  1271. throw cannotFulfillGoalException("BUILD has been realized as much as possible.");
  1272. else
  1273. return ret;
  1274. }
  1275. TSubgoal Build::whatToDoToAchieve()
  1276. {
  1277. return fh->chooseSolution(getAllPossibleSubgoals());
  1278. }
  1279. bool Goals::Build::fulfillsMe(TSubgoal goal)
  1280. {
  1281. if (goal->goalType == Goals::BUILD || goal->goalType == Goals::BUILD_STRUCTURE)
  1282. return (!town || town == goal->town); //building anything will do, in this town if set
  1283. else
  1284. return false;
  1285. }
  1286. TSubgoal Invalid::whatToDoToAchieve()
  1287. {
  1288. return iAmElementar();
  1289. }
  1290. std::string GatherArmy::completeMessage() const
  1291. {
  1292. return "Hero " + hero.get()->name + " gathered army of value " + boost::lexical_cast<std::string>(value);
  1293. }
  1294. TSubgoal GatherArmy::whatToDoToAchieve()
  1295. {
  1296. //TODO: find hero if none set
  1297. assert(hero.h);
  1298. return fh->chooseSolution(getAllPossibleSubgoals()); //find dwelling. use current hero to prevent him from doing nothing.
  1299. }
  1300. static const BuildingID unitsSource[] = { BuildingID::DWELL_LVL_1, BuildingID::DWELL_LVL_2, BuildingID::DWELL_LVL_3,
  1301. BuildingID::DWELL_LVL_4, BuildingID::DWELL_LVL_5, BuildingID::DWELL_LVL_6, BuildingID::DWELL_LVL_7};
  1302. TGoalVec GatherArmy::getAllPossibleSubgoals()
  1303. {
  1304. //get all possible towns, heroes and dwellings we may use
  1305. TGoalVec ret;
  1306. if(!hero.validAndSet())
  1307. {
  1308. return ret;
  1309. }
  1310. //TODO: include evaluation of monsters gather in calculation
  1311. for(auto t : cb->getTownsInfo())
  1312. {
  1313. auto pos = t->visitablePos();
  1314. if(ai->isAccessibleForHero(pos, hero))
  1315. {
  1316. //grab army from town
  1317. if(!t->visitingHero && howManyReinforcementsCanGet(hero, t))
  1318. {
  1319. if(!vstd::contains(ai->townVisitsThisWeek[hero], t))
  1320. ret.push_back(sptr(Goals::VisitTile(pos).sethero(hero)));
  1321. }
  1322. //buy army in town
  1323. if (!t->visitingHero || t->visitingHero == hero.get(true))
  1324. {
  1325. ui32 val = std::min<ui32>(value, howManyReinforcementsCanBuy(hero, t));
  1326. if (val)
  1327. {
  1328. auto goal = sptr(Goals::BuyArmy(t, val).sethero(hero));
  1329. if(!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
  1330. ret.push_back(goal);
  1331. else
  1332. logAi->debug("Can not buy army, because of ai->ah->containsObjective");
  1333. }
  1334. }
  1335. //build dwelling
  1336. //TODO: plan building over multiple turns?
  1337. //auto bid = ah->canBuildAnyStructure(t, std::vector<BuildingID>(unitsSource, unitsSource + ARRAY_COUNT(unitsSource)), 8 - cb->getDate(Date::DAY_OF_WEEK));
  1338. //Do not use below code for now, rely on generic Build. Code below needs to know a lot of town/resource context to do more good than harm
  1339. /*auto bid = ai->ah->canBuildAnyStructure(t, std::vector<BuildingID>(unitsSource, unitsSource + ARRAY_COUNT(unitsSource)), 1);
  1340. if (bid.is_initialized())
  1341. {
  1342. auto goal = sptr(BuildThis(bid.get(), t).setpriority(priority));
  1343. if (!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
  1344. ret.push_back(goal);
  1345. else
  1346. logAi->debug("Can not build a structure, because of ai->ah->containsObjective");
  1347. }*/
  1348. }
  1349. }
  1350. auto otherHeroes = cb->getHeroesInfo();
  1351. auto heroDummy = hero;
  1352. vstd::erase_if(otherHeroes, [heroDummy](const CGHeroInstance * h)
  1353. {
  1354. if(h == heroDummy.h)
  1355. return true;
  1356. else if(!ai->isAccessibleForHero(heroDummy->visitablePos(), h, true))
  1357. return true;
  1358. else if(!ai->canGetArmy(heroDummy.h, h)) //TODO: return actual aiValue
  1359. return true;
  1360. else if(ai->getGoal(h)->goalType == Goals::GATHER_ARMY)
  1361. return true;
  1362. else
  1363. return false;
  1364. });
  1365. for(auto h : otherHeroes)
  1366. {
  1367. // Go to the other hero if we are faster
  1368. if (!vstd::contains(ai->visitedHeroes[hero], h)
  1369. && ai->isAccessibleForHero(h->visitablePos(), hero, true)) //visit only once each turn //FIXME: this is only bug workaround
  1370. ret.push_back(sptr(Goals::VisitHero(h->id.getNum()).setisAbstract(true).sethero(hero)));
  1371. // Let the other hero come to us
  1372. if (!vstd::contains(ai->visitedHeroes[h], hero))
  1373. ret.push_back(sptr(Goals::VisitHero(hero->id.getNum()).setisAbstract(true).sethero(h)));
  1374. }
  1375. std::vector<const CGObjectInstance *> objs;
  1376. for(auto obj : ai->visitableObjs)
  1377. {
  1378. if(obj->ID == Obj::CREATURE_GENERATOR1)
  1379. {
  1380. auto relationToOwner = cb->getPlayerRelations(obj->getOwner(), ai->playerID);
  1381. //Use flagged dwellings only when there are available creatures that we can afford
  1382. if(relationToOwner == PlayerRelations::SAME_PLAYER)
  1383. {
  1384. auto dwelling = dynamic_cast<const CGDwelling *>(obj);
  1385. ui32 val = std::min<ui32>(value, howManyReinforcementsCanBuy(hero, dwelling));
  1386. if(val)
  1387. {
  1388. for(auto & creLevel : dwelling->creatures)
  1389. {
  1390. if(creLevel.first)
  1391. {
  1392. for(auto & creatureID : creLevel.second)
  1393. {
  1394. auto creature = VLC->creh->creatures[creatureID];
  1395. if(ai->ah->freeResources().canAfford(creature->cost))
  1396. objs.push_back(obj); //TODO: reserve resources?
  1397. }
  1398. }
  1399. }
  1400. }
  1401. }
  1402. }
  1403. }
  1404. for(auto h : cb->getHeroesInfo())
  1405. {
  1406. for(auto obj : objs)
  1407. {
  1408. //find safe dwelling
  1409. if(ai->isGoodForVisit(obj, h))
  1410. {
  1411. vstd::concatenate(ret, ai->ah->howToVisitObj(h, obj));
  1412. }
  1413. }
  1414. }
  1415. if(ai->canRecruitAnyHero() && ai->ah->freeGold() > GameConstants::HERO_GOLD_COST) //this is not stupid in early phase of game
  1416. {
  1417. if(auto t = ai->findTownWithTavern())
  1418. {
  1419. for(auto h : cb->getAvailableHeroes(t)) //we assume that all towns have same set of heroes
  1420. {
  1421. if(h && h->getTotalStrength() > 500) //do not buy heroes with single creatures for GatherArmy
  1422. {
  1423. ret.push_back(sptr(Goals::RecruitHero()));
  1424. break;
  1425. }
  1426. }
  1427. }
  1428. }
  1429. if(ret.empty())
  1430. {
  1431. if(hero == ai->primaryHero())
  1432. ret.push_back(sptr(Goals::Explore()));
  1433. else
  1434. throw cannotFulfillGoalException("No ways to gather army");
  1435. }
  1436. return ret;
  1437. }
  1438. //TSubgoal AbstractGoal::whatToDoToAchieve()
  1439. //{
  1440. // logAi->debug("Decomposing goal of type %s",name());
  1441. // return sptr (Goals::Explore());
  1442. //}
  1443. TSubgoal AbstractGoal::goVisitOrLookFor(const CGObjectInstance * obj)
  1444. {
  1445. if(obj)
  1446. return sptr(Goals::VisitObj(obj->id.getNum()));
  1447. else
  1448. return sptr(Goals::Explore());
  1449. }
  1450. TSubgoal AbstractGoal::lookForArtSmart(int aid)
  1451. {
  1452. return sptr(Goals::Invalid());
  1453. }
  1454. bool AbstractGoal::invalid() const
  1455. {
  1456. return goalType == INVALID;
  1457. }
  1458. void AbstractGoal::accept(VCAI * ai)
  1459. {
  1460. ai->tryRealize(*this);
  1461. }
  1462. template<typename T>
  1463. void CGoal<T>::accept(VCAI * ai)
  1464. {
  1465. ai->tryRealize(static_cast<T &>(*this)); //casting enforces template instantiation
  1466. }
  1467. float AbstractGoal::accept(FuzzyHelper * f)
  1468. {
  1469. return f->evaluate(*this);
  1470. }
  1471. template<typename T>
  1472. float CGoal<T>::accept(FuzzyHelper * f)
  1473. {
  1474. return f->evaluate(static_cast<T &>(*this)); //casting enforces template instantiation
  1475. }