Goals.cpp 46 KB

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