CGeniusAI.cpp 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382
  1. #include "CGeniusAI.h"
  2. #include <iostream>
  3. #include <boost/lexical_cast.hpp>
  4. #include "../../hch/CBuildingHandler.h"
  5. #include "../../hch/CHeroHandler.h"
  6. #include "../../lib/VCMI_Lib.h"
  7. #include "../../lib/NetPacks.h"
  8. #include "AIPriorities.h"
  9. using std::cout;
  10. using std::endl;
  11. using geniusai::CGeniusAI;
  12. #if defined (_MSC_VER) && (_MSC_VER >= 1020) || (__MINGW32__)
  13. // Excludes rarely used stuff from windows headers - delete this line if
  14. // something is missing.
  15. #define WIN32_LEAN_AND_MEAN
  16. #include <windows.h>
  17. #endif
  18. void DbgBox(const char* msg, bool messageBox)
  19. {
  20. #if defined PRINT_DEBUG
  21. #if defined _DEBUG
  22. //# if 0
  23. # if defined (_MSC_VER) && (_MSC_VER >= 1020)
  24. if (messageBox)
  25. {
  26. MessageBoxA(NULL, msg, "Debug message", MB_OK | MB_ICONASTERISK);
  27. }
  28. # endif
  29. std::cout << msg << std::endl;
  30. #endif
  31. #endif
  32. }
  33. // TODO: Rewrite those i-s, o-s to something meaningful.
  34. bool CGeniusAI::AIObjectContainer::operator<(
  35. const AIObjectContainer& b) const
  36. {
  37. if (o->pos != b.o->pos)
  38. return o->pos < b.o->pos;
  39. else
  40. return o->id < b.o->id;
  41. }
  42. CGeniusAI::HypotheticalGameState::HeroModel::HeroModel(
  43. const CGHeroInstance* h)
  44. : h(h), finished(false)
  45. {
  46. pos = h->getPosition(false);
  47. remainingMovement = h->movement;
  48. }
  49. CGeniusAI::HypotheticalGameState::TownModel::TownModel(
  50. const CGTownInstance* t)
  51. : t(t)
  52. {
  53. hasBuilt = static_cast<bool>(t->builded);
  54. creaturesToRecruit = t->creatures;
  55. creaturesInGarrison = t->getArmy();
  56. }
  57. CGeniusAI::HypotheticalGameState::HypotheticalGameState(CGeniusAI& ai)
  58. : knownVisitableObjects(ai.knownVisitableObjects)
  59. {
  60. AI = &ai;
  61. std::vector<const CGHeroInstance*> heroes = ai.m_cb->getHeroesInfo();
  62. for (std::vector<const CGHeroInstance*>::iterator i = heroes.begin();
  63. i != heroes.end();
  64. i++)
  65. heroModels.push_back(HeroModel(*i));
  66. std::vector<const CGTownInstance*> towns = ai.m_cb->getTownsInfo();
  67. for (std::vector <const CGTownInstance*>::iterator i = towns.begin();
  68. i != towns.end();
  69. i++) {
  70. if ( (*i)->tempOwner == ai.m_cb->getMyColor() )
  71. townModels.push_back(TownModel(*i));
  72. }
  73. if (ai.m_cb->howManyTowns() != 0) {
  74. AvailableHeroesToBuy =
  75. ai.m_cb->getAvailableHeroes(ai.m_cb->getTownInfo(0,0));
  76. }
  77. for (int i = 0; i < 8; i++)
  78. resourceAmounts.push_back(ai.m_cb->getResourceAmount(i));
  79. }
  80. void CGeniusAI::HypotheticalGameState::update(CGeniusAI& ai)
  81. {
  82. AI = &ai;
  83. knownVisitableObjects = ai.knownVisitableObjects;
  84. std::vector<HeroModel> oldModels = heroModels;
  85. heroModels.clear();
  86. std::vector<const CGHeroInstance*> heroes = ai.m_cb->getHeroesInfo();
  87. for (std::vector<const CGHeroInstance*>::iterator i = heroes.begin();
  88. i != heroes.end();
  89. i++)
  90. heroModels.push_back(HeroModel(*i));
  91. for (int i = 0; i < oldModels.size(); i++) {
  92. for (int j = 0; j < heroModels.size(); j++) {
  93. if (oldModels[i].h->subID == heroModels[j].h->subID) {
  94. heroModels[j].finished = oldModels[i].finished;
  95. heroModels[j].previouslyVisited_pos = oldModels[i].previouslyVisited_pos;
  96. }
  97. }
  98. }
  99. townModels.clear();
  100. std::vector<const CGTownInstance*> towns = ai.m_cb->getTownsInfo();
  101. for (std::vector<const CGTownInstance*>::iterator i = towns.begin();
  102. i != towns.end();
  103. i++) {
  104. if ( (*i)->tempOwner == ai.m_cb->getMyColor() )
  105. townModels.push_back(TownModel(*i));
  106. }
  107. if (ai.m_cb->howManyTowns() != 0) {
  108. AvailableHeroesToBuy =
  109. ai.m_cb->getAvailableHeroes(ai.m_cb->getTownInfo(0,0));
  110. }
  111. resourceAmounts.clear();
  112. for (int i = 0; i < 8; i++)
  113. resourceAmounts.push_back(ai.m_cb->getResourceAmount(i));
  114. }
  115. CGeniusAI::HeroObjective::HeroObjective(const HypotheticalGameState &hgs,
  116. Type t,
  117. const CGObjectInstance* object,
  118. HypotheticalGameState::HeroModel* h,
  119. CGeniusAI* ai)
  120. : object(object), hgs(hgs)
  121. {
  122. AI = ai;
  123. pos = object->pos;
  124. type = t;
  125. whoCanAchieve.push_back(h);
  126. _value = -1;
  127. }
  128. float CGeniusAI::HeroObjective::getValue() const
  129. {
  130. if (_value >= 0)
  131. return _value - _cost;
  132. // TODO: each object should have an associated cost to visit IE
  133. // (tree of knowledge 1000 gold/10 gems)
  134. vector<int> resourceCosts;
  135. for (int i = 0; i < 8; i++)
  136. resourceCosts.push_back(0);
  137. if (object->ID == 47) // School of magic
  138. resourceCosts[6] += 1000;
  139. // TODO: Add some meaningful (and not exploitable) number here.
  140. float bestCost = 9e9f;
  141. HypotheticalGameState::HeroModel* bestHero = NULL;
  142. if (type != AIObjective::finishTurn)
  143. {
  144. for (int i = 0; i < whoCanAchieve.size(); i++)
  145. {
  146. int distOutOfTheWay = 0;
  147. CPath path3;
  148. //from hero to object
  149. if (AI->m_cb->getPath(whoCanAchieve[i]->pos,
  150. pos,
  151. whoCanAchieve[i]->h,
  152. path3)) {
  153. distOutOfTheWay+=path3.nodes[0].dist;
  154. }
  155. // from object to goal
  156. if (AI->m_cb->getPath(pos,
  157. whoCanAchieve[i]->interestingPos,
  158. whoCanAchieve[i]->h,
  159. path3)) {
  160. distOutOfTheWay += path3.nodes[0].dist;
  161. // from hero directly to goal
  162. if (AI->m_cb->getPath(whoCanAchieve[i]->pos,
  163. whoCanAchieve[i]->interestingPos,
  164. whoCanAchieve[i]->h,
  165. path3))
  166. distOutOfTheWay-=path3.nodes[0].dist;
  167. }
  168. float cost = AI->m_priorities->getCost(resourceCosts,
  169. whoCanAchieve[i]->h,
  170. distOutOfTheWay);
  171. if (cost < bestCost) {
  172. bestCost = cost;
  173. bestHero = whoCanAchieve[i];
  174. }
  175. } // for (int i = 0; i < whoCanAchieve.size(); i++)
  176. } else // if (type != AIObjective::finishTurn)
  177. bestCost = 0;
  178. if (bestHero) {
  179. whoCanAchieve.clear();
  180. whoCanAchieve.push_back(bestHero);
  181. }
  182. _value = AI->m_priorities->getValue(*this);
  183. _cost = bestCost;
  184. return _value - _cost;
  185. }
  186. bool CGeniusAI::HeroObjective::operator<(
  187. const HeroObjective& other) const
  188. {
  189. if (type != other.type)
  190. return type < other.type;
  191. else if (pos != other.pos)
  192. return pos < other.pos;
  193. else if (object->id != other.object->id)
  194. return object->id < other.object->id;
  195. else if ((dynamic_cast<const CGVisitableOPH*>(object) != NULL) &&
  196. (whoCanAchieve.front()->h->id != other.whoCanAchieve.front()->h->id))
  197. return whoCanAchieve.front()->h->id < other.whoCanAchieve.front()->h->id;
  198. else
  199. return false;
  200. }
  201. void CGeniusAI::HeroObjective::print() const
  202. {
  203. switch (type) {
  204. case visit:
  205. cout << "visit " << object->hoverName
  206. << " at (" <<object->pos.x << ","<< object->pos.y << ")" ;
  207. break;
  208. case attack:
  209. cout << "attack " << object->hoverName;
  210. break;
  211. case finishTurn:
  212. cout << "finish turn";
  213. // TODO: Add a default, just in case.
  214. }
  215. if (whoCanAchieve.size() == 1)
  216. cout << " with " << whoCanAchieve.front()->h->hoverName;
  217. }
  218. CGeniusAI::TownObjective::TownObjective(
  219. const HypotheticalGameState& hgs,
  220. Type t,
  221. HypotheticalGameState::TownModel* tn,
  222. int Which,
  223. CGeniusAI * ai)
  224. : whichTown(tn), which(Which), hgs(hgs)
  225. {
  226. AI = ai;
  227. type = t;
  228. _value = -1;
  229. }
  230. float CGeniusAI::TownObjective::getValue() const
  231. {
  232. if (_value >= 0)
  233. return _value - _cost;
  234. // TODO: Include a constant stating the meaning of 8 (number of resources).
  235. vector<int> resourceCosts(8,0);
  236. CBuilding* b = NULL;
  237. CCreature* creature = NULL;
  238. float cost = 0; // TODO: Needed?
  239. int ID = 0;
  240. int newID = 0;
  241. int howMany = 0;
  242. ui32 creatures_max = 0;
  243. switch (type) {
  244. case recruitHero:
  245. resourceCosts[6] = 2500; // TODO: Define somehow the meaning of gold etc.
  246. break;
  247. case buildBuilding:
  248. b = VLC->buildh->buildings[whichTown->t->subID][which];
  249. for (int i = 0;
  250. b && ( i < b->resources.size() ); // TODO: b what??
  251. i++)
  252. resourceCosts[i] = b->resources[i];
  253. break;
  254. case recruitCreatures:
  255. // Buy upgraded if possible.
  256. ID = whichTown->creaturesToRecruit[which].second.back();
  257. creature = VLC->creh->creatures[ID];
  258. howMany = whichTown->creaturesToRecruit[which].first;
  259. creatures_max = 0; // Max creatures you can recruit of this type.
  260. for (int i = 0; i < creature->cost.size(); i++) {
  261. if (creature->cost[i] != 0)
  262. creatures_max = hgs.resourceAmounts[i]/creature->cost[i];
  263. else
  264. creatures_max = INT_MAX; // TODO: Will have to rewrite it.
  265. // TODO: Buy the best units (the least I can buy)?
  266. amin(howMany, creatures_max);
  267. }
  268. // The cost of recruiting the stack of creatures.
  269. for (int i = 0;
  270. creature && ( i < creature->cost.size() ); // TODO: Creature what??
  271. i++)
  272. resourceCosts[i] = creature->cost[i]*howMany;
  273. break;
  274. case upgradeCreatures:
  275. UpgradeInfo ui = AI->m_cb->getUpgradeInfo(whichTown->t,which);
  276. ID = whichTown->creaturesInGarrison.getCreature(which)->idNumber;
  277. howMany = whichTown->creaturesInGarrison.getStackCount(which);
  278. newID = ui.newID.back();
  279. int upgrade_serial = ui.newID.size() - 1;
  280. for (std::set< std::pair<int,int> >::iterator
  281. j = ui.cost[upgrade_serial].begin();
  282. j != ui.cost[upgrade_serial].end();
  283. j++)
  284. resourceCosts[j->first] = j->second*howMany;
  285. break;
  286. }
  287. _cost = AI->m_priorities->getCost(resourceCosts, NULL, 0);
  288. _value = AI->m_priorities->getValue(*this);
  289. return _value - _cost;
  290. }
  291. bool CGeniusAI::TownObjective::operator<(const TownObjective &other) const
  292. {
  293. if (type != other.type)
  294. return type < other.type;
  295. else if (which != other.which)
  296. return which < other.which;
  297. else if (whichTown->t->id != other.whichTown->t->id)
  298. return whichTown->t->id < other.whichTown->t->id;
  299. else
  300. return false;
  301. }
  302. void CGeniusAI::TownObjective::print() const
  303. {
  304. HypotheticalGameState::HeroModel hm;
  305. CBuilding* b = NULL;
  306. const CCreature* creature = NULL;
  307. int ID = 0;
  308. int howMany = 0;
  309. int newID = 0; // TODO: Needed?
  310. int hSlot = 0; // TODO: Needed?
  311. ui32 creatures_max;
  312. switch (type) {
  313. case recruitHero:
  314. cout << "recruit hero.";
  315. break;
  316. case buildBuilding:
  317. b = VLC->buildh->buildings[whichTown->t->subID][which];
  318. cout << "build " << b->Name() << " cost = ";
  319. if (b->resources.size() != 0) {
  320. if (b->resources[0] != 0)
  321. cout << b->resources[0] << " wood. ";
  322. if (b->resources[1] != 0)
  323. cout << b->resources[1] << " mercury. ";
  324. if (b->resources[2] != 0)
  325. cout << b->resources[2] << " ore. ";
  326. if (b->resources[3] != 0)
  327. cout << b->resources[3] << " sulfur. ";
  328. if (b->resources[4] != 0)
  329. cout << b->resources[4] << " crystal. ";
  330. if (b->resources[5] != 0)
  331. cout << b->resources[5] << " gems. ";
  332. if (b->resources[6] != 0)
  333. cout << b->resources[6] << " gold. ";
  334. }
  335. break;
  336. case recruitCreatures:
  337. // Buy upgraded if possible.
  338. ID = whichTown->creaturesToRecruit[which].second.back();
  339. creature = VLC->creh->creatures[ID];
  340. howMany = whichTown->creaturesToRecruit[which].first;
  341. creatures_max = 0;
  342. for (int i = 0; i < creature->cost.size(); i++) {
  343. if (creature->cost[i] != 0)
  344. creatures_max = hgs.resourceAmounts[i]/creature->cost[i];
  345. else
  346. creatures_max = INT_MAX;
  347. amin(howMany, creatures_max);
  348. }
  349. cout << "recruit " << howMany << " " << creature->namePl
  350. << " (Total AI Strength " << creature->AIValue*howMany
  351. << "). cost = ";
  352. if (creature->cost.size() != 0)
  353. {
  354. if (creature->cost[0] != 0)
  355. cout << creature->cost[0]*howMany << " wood. ";
  356. if (creature->cost[1] != 0)
  357. cout << creature->cost[1]*howMany << " mercury. ";
  358. if (creature->cost[2] != 0)
  359. cout << creature->cost[2]*howMany << " ore. ";
  360. if (creature->cost[3] != 0)
  361. cout << creature->cost[3]*howMany << " sulfur. ";
  362. if (creature->cost[4] != 0)
  363. cout << creature->cost[4]*howMany << " cristal. ";
  364. if (creature->cost[5] != 0)
  365. cout << creature->cost[5]*howMany << " gems. ";
  366. if (creature->cost[6] != 0)
  367. cout << creature->cost[6]*howMany << " gold. ";
  368. }
  369. break; // case recruitCreatures.
  370. case upgradeCreatures:
  371. UpgradeInfo ui = AI->m_cb->getUpgradeInfo(whichTown->t,which);
  372. ID = whichTown->creaturesInGarrison.getCreature(which)->idNumber;
  373. cout << "upgrade " << VLC->creh->creatures[ID]->namePl;
  374. //ui.cost
  375. break;
  376. } // switch(type)
  377. }
  378. CGeniusAI::CGeniusAI() : m_generalAI(), m_state(NO_BATTLE)
  379. {
  380. m_priorities = new Priorities("AI/GeniusAI.brain");
  381. }
  382. CGeniusAI::~CGeniusAI()
  383. {
  384. delete m_priorities;
  385. }
  386. void CGeniusAI::init(ICallback *CB)
  387. {
  388. m_cb = CB;
  389. m_generalAI.init(CB);
  390. human = false;
  391. playerID = m_cb->getMyColor();
  392. std::string info = std::string("GeniusAI initialized for player ")
  393. + boost::lexical_cast<std::string>(playerID);
  394. m_battleLogic = NULL;
  395. DbgBox(info.c_str());
  396. }
  397. void CGeniusAI::reportResources()
  398. {
  399. cout << "Day " << m_cb->getDate() << ": ";
  400. cout << "AI Player " <<m_cb->getMyColor()<< " with "
  401. << m_cb->howManyHeroes(true) << " heroes. " << endl;
  402. cout << m_cb->getResourceAmount(0) << " wood. ";
  403. cout << m_cb->getResourceAmount(1) << " mercury. ";
  404. cout << m_cb->getResourceAmount(2) << " ore. ";
  405. cout << m_cb->getResourceAmount(3) << " sulfur. ";
  406. cout << m_cb->getResourceAmount(4) << " crystal. ";
  407. cout << m_cb->getResourceAmount(5) << " gems. ";
  408. cout << m_cb->getResourceAmount(6) << " gold.";
  409. cout << endl;
  410. }
  411. void CGeniusAI::addHeroObjectives(CGeniusAI::HypotheticalGameState::HeroModel& h,
  412. CGeniusAI::HypotheticalGameState& hgs)
  413. {
  414. int3 hpos = h.pos;
  415. int3 destination;
  416. int3 interestingPos;
  417. CPath path;
  418. int movement = h.remainingMovement;
  419. int maxInteresting = 0;
  420. AIObjective::Type tp = AIObjective::visit;
  421. if (h.finished)
  422. return;
  423. for (std::set<AIObjectContainer>::const_iterator
  424. i = hgs.knownVisitableObjects.begin();
  425. i != hgs.knownVisitableObjects.end();
  426. i++) {
  427. tp = AIObjective::visit;
  428. if( h.previouslyVisited_pos==i->o->getSightCenter())
  429. continue;
  430. //TODO: what would the hero actually visit if he went to that spot
  431. // maybe the hero wants to visit a seemingly unguarded enemy town,
  432. // but there is a hero on top of it.
  433. // if(i->o->)
  434. if (i->o->ID != HEROI_TYPE) {// Unless you are trying to visit a hero.
  435. bool heroThere = false;
  436. for(int j = 0; j < hgs.heroModels.size(); j++) {
  437. if (hgs.heroModels[j].pos == i->o->getSightCenter())
  438. heroThere = true;
  439. }
  440. if (heroThere) // It won't work if there is already someone visiting that spot.
  441. continue;
  442. }
  443. if (i->o->ID == HEROI_TYPE && // Visiting friendly heroes not yet supported.
  444. i->o->getOwner() == m_cb->getMyColor())
  445. continue;
  446. if (i->o->id == h.h->id) // Don't visit yourself (should be caught by above).
  447. continue;
  448. // Don't visit a mine if you own, there's almost no
  449. // point(maybe to leave guards or because the hero's trapped).
  450. if (i->o->ID == 53
  451. && i->o->getOwner() == m_cb->getMyColor())
  452. continue;
  453. if (i->o->getOwner() != m_cb->getMyColor()) {
  454. // TODO: I feel like the AI shouldn't have access to this information.
  455. // We must get an approximation based on few, many, ... zounds etc.
  456. int enemyStrength = 0;
  457. // TODO: should be virtual maybe, army strength should be
  458. // comparable across objects.
  459. // TODO: Rewrite all those damn i->o. For someone reading it the first
  460. // time it's completely inconprehensible.
  461. // TODO: NO MAGIC NUMBERS !!!
  462. if (dynamic_cast<const CArmedInstance*> (i->o))
  463. enemyStrength =
  464. (dynamic_cast<const CArmedInstance*> (i->o))->getArmyStrength();
  465. if (dynamic_cast<const CGHeroInstance*> (i->o))
  466. enemyStrength =
  467. (dynamic_cast<const CGHeroInstance*> (i->o))->getTotalStrength();
  468. // TODO: Make constants of those 1.2 & 2.5.
  469. if (dynamic_cast<const CGTownInstance*> (i->o))
  470. enemyStrength = static_cast<int>(
  471. (dynamic_cast<const CGTownInstance*> (i->o))->getArmyStrength() * 1.2);
  472. float heroStrength = h.h->getTotalStrength();
  473. // TODO: ballence these numbers using objective cost formula.
  474. // TODO: it would be nice to do a battle simulation.
  475. if (enemyStrength * 2.5 > heroStrength)
  476. continue;
  477. if (enemyStrength > 0)
  478. tp = AIObjective::attack;
  479. }
  480. //don't visit things that have already been visited this week.
  481. if ((dynamic_cast<const CGVisitableOPW*> (i->o) != NULL) &&
  482. (dynamic_cast<const CGVisitableOPW*> (i->o)->visited))
  483. continue;
  484. //don't visit things that you have already visited OPH
  485. if ((dynamic_cast<const CGVisitableOPH*> (i->o) != NULL) &&
  486. vstd::contains(dynamic_cast<const CGVisitableOPH*> (i->o)->visitors,
  487. h.h->id))
  488. continue;
  489. // TODO: Some descriptions of those included so someone can undestand them.
  490. if (i->o->ID == 88 || i->o->ID == 89 || i->o->ID == 90) {
  491. //TODO: if no spell book continue
  492. //TODO: if the shrine's spell is identified, and the hero already has it, continue
  493. }
  494. destination = i->o->getSightCenter();
  495. // Don't try to take a path from the underworld to the top or vice versa.
  496. // TODO: Will have to make some calculations so that the AI can enter the
  497. // underground.
  498. if (hpos.z == destination.z) {
  499. //TODO: fix get path so that it doesn't return a path unless z's are
  500. // the same, or path goes through sub gate.
  501. if (m_cb->getPath(hpos, destination, h.h, path)) {
  502. path.convert(0);
  503. if (path.nodes[0].dist < movement) {
  504. // TODO: So easy to understand...
  505. HeroObjective ho(hgs, tp, i->o, &h, this);
  506. std::set<HeroObjective>::iterator found = currentHeroObjectives.find(ho);
  507. if (found == currentHeroObjectives.end())
  508. currentHeroObjectives.insert(ho);
  509. else {
  510. // TODO: Try to rewrite if possible...
  511. // A cast to a pointer, from a reference, to a pointer
  512. // of an iterator.
  513. HeroObjective* objective = (HeroObjective*)&(*found);
  514. objective->whoCanAchieve.push_back(&h);
  515. }
  516. }
  517. // Find the most interesting object that is eventually reachable,
  518. // and set that position to the ultimate goal position.
  519. // TODO: replace random numbers with some sort of ranking system.
  520. int hi = rand();
  521. if (hi > maxInteresting) {
  522. maxInteresting = hi;
  523. interestingPos = destination;
  524. }
  525. } // if (m_cb->getPath(hpos, destination, h.h, path))
  526. } // if (hpos.z == destination.z)
  527. } // for (std::set<AIObjectContainer>::const_iterator
  528. // i = knownVisitableObjects.begin();
  529. h.interestingPos = interestingPos;
  530. // there ought to be a path
  531. // if(h.remainingMovement>0&&m_cb->getPath(hpos,interestingPos,h.h,path))
  532. currentHeroObjectives.insert(HeroObjective(hgs,
  533. HeroObjective::finishTurn,
  534. h.h,
  535. &h,
  536. this));
  537. }
  538. void CGeniusAI::HeroObjective::fulfill(CGeniusAI& cg,
  539. HypotheticalGameState& hgs)
  540. {
  541. cg.m_cb->waitTillRealize = true;
  542. HypotheticalGameState::HeroModel* h = NULL;
  543. int3 hpos;
  544. int3 destination;
  545. int3 bestPos;
  546. int3 currentPos;
  547. int3 checkPos;
  548. CPath path;
  549. CPath path2;
  550. int howGood = 0;
  551. switch (type) {
  552. case finishTurn:
  553. h = whoCanAchieve.front();
  554. h->finished=true;
  555. hpos = h->pos;
  556. destination = h->interestingPos;
  557. if (!cg.m_cb->getPath(hpos, destination, h->h, path)) {
  558. cout << "AI error: invalid destination" << endl;
  559. return;
  560. }
  561. destination = h->pos;
  562. // Find closest coord that we can get to.
  563. for (int i = path.nodes.size() - 2; i >= 0; i--) {
  564. // TODO: getPath what??
  565. if ((cg.m_cb->getPath(hpos, path.nodes[i].coord, h->h, path2)) &&
  566. (path2.nodes[0].dist <= h->remainingMovement))
  567. destination = path.nodes[i].coord;
  568. }
  569. if (destination == h->interestingPos)
  570. break;
  571. // ! START ! //
  572. // Find close pos with the most neighboring empty squares. We don't want to
  573. // get in the way.
  574. bestPos = destination;
  575. howGood = 0;
  576. // TODO: Add a meaning to 3.
  577. for (int x = -3; x <= 3; x++) {
  578. for (int y = -3; y <= 3; y++) {
  579. currentPos = destination + int3(x,y,0);
  580. // There better not be anything there.
  581. if (cg.m_cb->getVisitableObjs(currentPos).size() != 0)
  582. continue;
  583. if ((cg.m_cb->getPath(hpos, currentPos, h->h, path) == false) ||
  584. // It better be reachable from the hero
  585. // TODO: remainingMovement > 0...
  586. (path.nodes[0].dist>h->remainingMovement))
  587. continue;
  588. int count = 0;
  589. for (int xx = -1; xx <= 1; xx++) {
  590. for (int yy = -1; yy <= 1; yy++) {
  591. checkPos = currentPos + int3(xx, yy, 0);
  592. if (cg.m_cb->getPath(currentPos, checkPos, h->h, path) != false)
  593. count++;
  594. }
  595. }
  596. if (count > howGood) {
  597. howGood = count;
  598. bestPos = currentPos;
  599. }
  600. }
  601. }
  602. destination = bestPos;
  603. // ! END ! //
  604. cg.m_cb->getPath(hpos, destination, h->h, path);
  605. path.convert(0);
  606. break;
  607. case visit:
  608. case attack:
  609. h = whoCanAchieve.front(); //lowest cost hero
  610. h->previouslyVisited_pos = object->getSightCenter();
  611. hpos = h->pos;
  612. destination = object->getSightCenter();
  613. break;
  614. } // switch(type)
  615. if ((type == visit || type == finishTurn || type == attack) &&
  616. (cg.m_cb->getPath(hpos, destination, h->h, path) != false))
  617. path.convert(0);
  618. if (cg.m_state.get() != NO_BATTLE)
  619. cg.m_state.waitUntil(NO_BATTLE); // Wait for battle end
  620. // Wait over, battle over too. hero might be killed. check.
  621. for (int i = path.nodes.size() - 2;
  622. (i >= 0) && (cg.m_cb->getHeroSerial(h->h) >= 0);
  623. i--) {
  624. cg.m_cb->moveHero(h->h,path.nodes[i].coord);
  625. if (cg.m_state.get() != NO_BATTLE)
  626. cg.m_state.waitUntil(NO_BATTLE); // Wait for battle end
  627. }
  628. h->remainingMovement -= path.nodes[0].dist;
  629. if (object->blockVisit)
  630. h->pos = path.nodes[1].coord;
  631. else
  632. h->pos = destination;
  633. std::set<AIObjectContainer>::iterator
  634. i = hgs.knownVisitableObjects.find(AIObjectContainer(object));
  635. if (i != hgs.knownVisitableObjects.end())
  636. hgs.knownVisitableObjects.erase(i);
  637. const CGTownInstance* town = dynamic_cast<const CGTownInstance*> (object);
  638. if (town && object->getOwner() == cg.m_cb->getMyColor()) {
  639. //upgrade hero's units
  640. cout << "visiting town" << endl;
  641. CCreatureSet hcreatures = h->h->getArmy();
  642. for (TSlots::const_iterator
  643. i = hcreatures.Slots().begin();
  644. i != hcreatures.Slots().end();
  645. i++) { // For each hero slot.
  646. UpgradeInfo ui = cg.m_cb->getUpgradeInfo(h->h,i->first);
  647. bool canUpgrade = false;
  648. if (ui.newID.size() != 0) { // Does this stack need upgrading?
  649. canUpgrade = true;
  650. for (int ii = 0; ii < ui.cost.size(); ii++) // Can afford the upgrade?
  651. for (std::set<std::pair<int,int> >::iterator
  652. j = ui.cost[ii].begin();
  653. j != ui.cost[ii].end();
  654. j++)
  655. if (hgs.resourceAmounts[j->first] < j->second * i->second->count)
  656. canUpgrade = false;
  657. }
  658. if (canUpgrade)
  659. {
  660. cg.m_cb->upgradeCreature(h->h, i->first, ui.newID.back());
  661. cout << "upgrading hero's "
  662. << i->second->type->namePl
  663. << endl;
  664. }
  665. }
  666. // Give town's units to hero.
  667. CCreatureSet tcreatures = town->getArmy();
  668. int weakestCreatureStack;
  669. int weakestCreatureAIValue = 99999; // TODO: Wtf??
  670. for (TSlots::const_iterator
  671. i = tcreatures.Slots().begin();
  672. i != tcreatures.Slots().end();
  673. i++) {
  674. if (i->second->type->AIValue <
  675. weakestCreatureAIValue) {
  676. weakestCreatureAIValue = i->second->type->AIValue;
  677. weakestCreatureStack = i->first;
  678. }
  679. }
  680. for (TSlots::const_iterator
  681. i = tcreatures.Slots().begin();
  682. i != tcreatures.Slots().end();
  683. i++) { // For each town slot.
  684. hcreatures = h->h->getArmy();
  685. int hSlot = hcreatures.getSlotFor(i->second->type->idNumber);
  686. if (hSlot == -1)
  687. continue;
  688. cout << "giving hero "
  689. << i->second->type->namePl
  690. << endl;
  691. if (!hcreatures.slotEmpty(hSlot)) {
  692. // Can't take garrisonHero's last unit.
  693. if ( (i->first == weakestCreatureStack)
  694. && (town->garrisonHero != NULL) )
  695. cg.m_cb->splitStack(town, h->h, i->first, hSlot, i->second->count - 1);
  696. else
  697. // TODO: the comment says that this code is not safe for the AI.
  698. cg.m_cb->mergeStacks(town, h->h, i->first, hSlot);
  699. } else
  700. cg.m_cb->swapCreatures(town, h->h, i->first, hSlot);
  701. } // for (std::map< si32, std::pair<ui32, si32> >::const_iterator ...
  702. } // if (town && object->getOwner == cg.m_cb->getMyColor())
  703. }
  704. void CGeniusAI::addTownObjectives(HypotheticalGameState::TownModel& t,
  705. HypotheticalGameState& hgs)
  706. {
  707. //recruitHero
  708. //buildBuilding
  709. //recruitCreatures
  710. //upgradeCreatures
  711. // Recruit hero.
  712. if ( (hgs.heroModels.size() < 3) && (hgs.resourceAmounts[6] >= 2500) ) {
  713. bool heroAtTown = false;
  714. for (int i = 0; i < hgs.heroModels.size(); i++) {
  715. if (hgs.heroModels[i].pos == t.t->getSightCenter())
  716. heroAtTown = true;
  717. }
  718. // No visiting hero and built tavern.
  719. if (!heroAtTown && vstd::contains(t.t->builtBuildings, 5)) {
  720. for (int i = 0; i < hgs.AvailableHeroesToBuy.size(); i++) {
  721. if ( (hgs.AvailableHeroesToBuy[i] != NULL)
  722. && (t.t->subID ==
  723. hgs.AvailableHeroesToBuy[i]->type->heroType / 2) ) {
  724. TownObjective to(hgs,AIObjective::recruitHero,&t,0,this);
  725. currentTownObjectives.insert(to);
  726. }
  727. }
  728. }
  729. }
  730. // Build a building.
  731. if (!t.hasBuilt) {
  732. // m_cb->getCBuildingsByID(t.t);
  733. std::map<int, CBuilding*> thisTownsBuildings =
  734. VLC->buildh->buildings[t.t->subID];
  735. for (std::map<int, CBuilding*>::iterator i = thisTownsBuildings.begin();
  736. i != thisTownsBuildings.end();
  737. i++) {
  738. if (m_cb->canBuildStructure(t.t, i->first) == 7) {
  739. TownObjective to(hgs, AIObjective::buildBuilding, &t, i->first ,this);
  740. currentTownObjectives.insert(to);
  741. }
  742. }
  743. }
  744. // Recruit creatures.
  745. for (int i = 0; i < t.creaturesToRecruit.size(); i++) {
  746. if (t.creaturesToRecruit[i].first == 0
  747. || t.creaturesToRecruit[i].second.empty())
  748. continue;
  749. int ID = t.creaturesToRecruit[i].second.back();
  750. // m_cb->getCCreatureByID(ID);
  751. const CCreature *creature = VLC->creh->creatures[ID];
  752. bool canAfford = true;
  753. for (int ii = 0; ii < creature->cost.size(); ii++)
  754. if (creature->cost[ii] > hgs.resourceAmounts[ii])
  755. canAfford = false; // Can we afford at least one creature?
  756. if (!canAfford) continue;
  757. //cout << "town has " << t.t->creatures[i]->first << " "<< creature->namePl << " (AI Strength " << creature->AIValue << ")." << endl;
  758. TownObjective to(hgs, AIObjective::recruitCreatures, &t, i, this);
  759. currentTownObjectives.insert(to);
  760. }
  761. // Upgrade creatures.
  762. for (TSlots::const_iterator
  763. i = t.creaturesInGarrison.Slots().begin();
  764. i != t.creaturesInGarrison.Slots().end();
  765. i++) {
  766. UpgradeInfo ui = m_cb->getUpgradeInfo(t.t, i->first);
  767. if (ui.newID.size() != 0) {
  768. bool canAfford = true;
  769. int upgrade_serial = ui.newID.size() - 1;
  770. for (std::set< std::pair<int, int> >::iterator
  771. j = ui.cost[upgrade_serial].begin();
  772. j != ui.cost[upgrade_serial].end();
  773. j++)
  774. if (hgs.resourceAmounts[j->first] < j->second * i->second->count)
  775. canAfford = false;
  776. if (canAfford) {
  777. TownObjective to(hgs,AIObjective::upgradeCreatures,&t,i->first,this);
  778. currentTownObjectives.insert(to);
  779. }
  780. } // if (ui.netID.size() != 0)
  781. } // for (std::map< si32, std::pair ...
  782. }
  783. void CGeniusAI::TownObjective::fulfill(CGeniusAI& cg,
  784. HypotheticalGameState& hgs)
  785. {
  786. cg.m_cb->waitTillRealize = true;
  787. CBuilding * b;
  788. const CCreature *creature;
  789. HypotheticalGameState::HeroModel hm;
  790. int ID, howMany, newID, hSlot;
  791. switch (type) {
  792. case recruitHero:
  793. cg.m_cb->recruitHero(whichTown->t, hgs.AvailableHeroesToBuy[which]);
  794. hm = HypotheticalGameState::HeroModel(hgs.AvailableHeroesToBuy[which]);
  795. hm.pos = whichTown->t->getSightCenter();
  796. hm.remainingMovement = hm.h->maxMovePoints(true);
  797. hgs.heroModels.push_back(hm);
  798. hgs.resourceAmounts[6] -= 2500;
  799. break;
  800. case buildBuilding:
  801. b = VLC->buildh->buildings[whichTown->t->subID][which];
  802. if (cg.m_cb->canBuildStructure(whichTown->t,which) == 7) {
  803. cout << "built " << b->Name() << "." << endl;
  804. if (!cg.m_cb->buildBuilding(whichTown->t, which))
  805. cout << "really tried to build unbuildable building" << endl;
  806. for (int i = 0; b && i < b->resources.size(); i++) // TODO: b what?
  807. hgs.resourceAmounts[i] -= b->resources[i];
  808. } else
  809. cout << "trying to build a structure we cannot build" << endl;
  810. whichTown->hasBuilt=true;
  811. break;
  812. case recruitCreatures:
  813. // Buy upgraded if possible.
  814. ID = whichTown->creaturesToRecruit[which].second.back();
  815. creature = VLC->creh->creatures[ID];
  816. howMany = whichTown->creaturesToRecruit[which].first;
  817. for (int i = 0; i < creature->cost.size(); i++)
  818. // TODO: rewrite.
  819. amin(howMany, creature->cost[i] ? hgs.resourceAmounts[i]/creature->cost[i] : INT_MAX);
  820. if (howMany == 0)
  821. cout << "tried to recruit without enough money.";
  822. cout << "recruiting " << howMany << " "
  823. << creature->namePl << " (Total AI Strength "
  824. << creature->AIValue*howMany << ")." << endl;
  825. cg.m_cb->recruitCreatures(whichTown->t, ID, howMany);
  826. break;
  827. case upgradeCreatures:
  828. UpgradeInfo ui = cg.m_cb->getUpgradeInfo(whichTown->t, which);
  829. ID = whichTown->creaturesInGarrison.getCreature(which)->idNumber;
  830. newID = ui.newID.back();
  831. // TODO: reduce resources in hgs
  832. cg.m_cb->upgradeCreature(whichTown->t, which, newID);
  833. cout << "upgrading " << VLC->creh->creatures[ID]->namePl << endl;
  834. break;
  835. }
  836. }
  837. void CGeniusAI::fillObjectiveQueue(HypotheticalGameState & hgs)
  838. {
  839. objectiveQueue.clear();
  840. currentHeroObjectives.clear();
  841. currentTownObjectives.clear();
  842. for (std::vector <CGeniusAI::HypotheticalGameState::HeroModel>::iterator
  843. i = hgs.heroModels.begin();
  844. i != hgs.heroModels.end();
  845. i++)
  846. addHeroObjectives(*i, hgs);
  847. for (std::vector <CGeniusAI::HypotheticalGameState::TownModel>::iterator
  848. i = hgs.townModels.begin();
  849. i != hgs.townModels.end();
  850. i++)
  851. addTownObjectives(*i, hgs);
  852. for (std::set<CGeniusAI::HeroObjective>::iterator
  853. i = currentHeroObjectives.begin();
  854. i != currentHeroObjectives.end();
  855. i++)
  856. // TODO: Recheck and try to write simpler expression.
  857. objectiveQueue.push_back(AIObjectivePtrCont((CGeniusAI::HeroObjective*)&(*i)));
  858. for (std::set<CGeniusAI::TownObjective>::iterator
  859. i = currentTownObjectives.begin();
  860. i != currentTownObjectives.end();
  861. i++)
  862. objectiveQueue.push_back(AIObjectivePtrCont((CGeniusAI::TownObjective*)&(*i)));
  863. }
  864. CGeniusAI::AIObjective * CGeniusAI::getBestObjective()
  865. {
  866. trueGameState.update(*this);
  867. fillObjectiveQueue(trueGameState);
  868. // TODO: Write this part.
  869. // if(!objectiveQueue.empty())
  870. // return max_element(objectiveQueue.begin(),objectiveQueue.end())->obj;
  871. m_priorities->fillFeatures(trueGameState);
  872. if (objectiveQueue.empty())
  873. return NULL;
  874. // sort(objectiveQueue.begin(),objectiveQueue.end());
  875. // reverse(objectiveQueue.begin(),objectiveQueue.end());
  876. int num = 1;
  877. // for(std::vector<AIObjectivePtrCont> ::iterator i = objectiveQueue.begin(); i < objectiveQueue.end();i++)
  878. // {
  879. // if(!dynamic_cast<HeroObjective*>(i->obj))continue;
  880. // cout << num++ << ": ";
  881. // i->obj->print();
  882. // cout << " value: " << i->obj->getValue();
  883. // cout << endl;
  884. // }
  885. // int choice = 0;
  886. // cout << "which would you do? (enter 0 for none): ";
  887. // cin >> choice;
  888. cout << "doing best of " << objectiveQueue.size() << " ";
  889. CGeniusAI::AIObjective* best =
  890. max_element(objectiveQueue.begin(), objectiveQueue.end())->obj;
  891. best->print();
  892. cout << " value = " << best->getValue() << endl;
  893. if (!objectiveQueue.empty())
  894. return best;
  895. return objectiveQueue.front().obj;
  896. }
  897. void CGeniusAI::yourTurn()
  898. {
  899. static boost::mutex mutex;
  900. boost::mutex::scoped_lock lock(mutex);
  901. m_cb->waitTillRealize = false;
  902. static int seed = rand();
  903. srand(seed);
  904. // if (m_cb->getDate() == 1) {
  905. // // startFirstTurn();
  906. //
  907. // // m_cb->endTurn();
  908. // // return;
  909. // }
  910. // //////////////TODO: replace with updates. Also add suspected objects list./////////
  911. // knownVisitableObjects.clear();
  912. // int3 pos = m_cb->getMapSize();
  913. // for (int x = 0; x < pos.x; x++) {
  914. // for (int y = 0; y < pos.y; y++) {
  915. // for (int z = 0; z < pos.z; z++)
  916. // tileRevealed(int3(x,y,z));
  917. // }
  918. // }
  919. // ///////////////////////////////////////////////////////////////////////////////////
  920. //
  921. // reportResources();
  922. //
  923. // trueGameState = HypotheticalGameState(*this);
  924. // AIObjective * objective;
  925. // while ((objective = getBestObjective()) != NULL)
  926. // objective->fulfill(*this,trueGameState);
  927. //
  928. // seed = rand();
  929. m_cb->endTurn();
  930. m_cb->waitTillRealize = false;
  931. }
  932. void CGeniusAI::startFirstTurn()
  933. {
  934. HypotheticalGameState hgs(*this);
  935. const CGTownInstance * town = m_cb->getTownInfo(0,0);
  936. const CGHeroInstance * heroInst = m_cb->getHeroInfo(0,0);
  937. TownObjective(hgs,
  938. AIObjective::recruitHero,
  939. &hgs.townModels.front(),
  940. 0,
  941. this).fulfill(*this, hgs);
  942. m_cb->swapGarrisonHero(town);
  943. hgs.update(*this);
  944. for (int i = 0; i < hgs.townModels.front().creaturesToRecruit.size(); i++) {
  945. if (hgs.townModels.front().creaturesToRecruit[i].first == 0)
  946. continue;
  947. int ID = hgs.townModels.front().creaturesToRecruit[i].second.back();
  948. const CCreature *creature = VLC->creh->creatures[ID];
  949. bool canAfford = true;
  950. for (int ii = 0; ii < creature->cost.size(); ii++) {
  951. if (creature->cost[ii] > hgs.resourceAmounts[ii])
  952. canAfford = false; // Can we afford at least one creature?
  953. }
  954. if (!canAfford)
  955. continue;
  956. TownObjective(hgs,AIObjective::recruitCreatures,&hgs.townModels.front(),i,this).fulfill(*this,hgs);
  957. }
  958. hgs.update(*this);
  959. HypotheticalGameState::HeroModel* hero;
  960. for (int i = 0; i < hgs.heroModels.size(); i++) {
  961. if (hgs.heroModels[i].h->id == heroInst->id)
  962. HeroObjective(hgs, AIObjective::visit, town, hero = &hgs.heroModels[i], this).fulfill(*this,hgs);
  963. }
  964. hgs.update(*this);
  965. // m_cb->swapGarrisonHero(town);
  966. //TODO: choose the strongest hero.
  967. }
  968. void CGeniusAI::heroKilled(const CGHeroInstance* hero)
  969. {
  970. }
  971. void CGeniusAI::heroCreated(const CGHeroInstance* hero)
  972. {
  973. }
  974. void CGeniusAI::tileRevealed(int3 pos)
  975. {
  976. std::vector<const CGObjectInstance*> objects = m_cb->getVisitableObjs(pos);
  977. for (std::vector < const CGObjectInstance* >::iterator o = objects.begin();
  978. o != objects.end();
  979. o++) {
  980. if ((*o)->id != -1)
  981. knownVisitableObjects.insert(*o);
  982. }
  983. objects = m_cb->getFlaggableObjects(pos);
  984. for (std::vector<const CGObjectInstance*>::iterator
  985. o = objects.begin();
  986. o != objects.end();
  987. o++)
  988. if ((*o)->id != -1)
  989. knownVisitableObjects.insert(*o);
  990. }
  991. // eg. ship built in shipyard
  992. void CGeniusAI::newObject(const CGObjectInstance* obj)
  993. {
  994. knownVisitableObjects.insert(obj);
  995. }
  996. void CGeniusAI::objectRemoved(const CGObjectInstance *obj) //eg. collected resource, picked artifact, beaten hero
  997. {
  998. std::set<AIObjectContainer>::iterator o = knownVisitableObjects.find(obj);
  999. if (o != knownVisitableObjects.end())
  1000. knownVisitableObjects.erase(o);
  1001. }
  1002. void CGeniusAI::tileHidden(int3 pos)
  1003. {
  1004. }
  1005. void CGeniusAI::heroMoved(const TryMoveHero& TMH)
  1006. {
  1007. // DbgBox("** CGeniusAI::heroMoved **");
  1008. }
  1009. void CGeniusAI::heroGotLevel(const CGHeroInstance *hero,
  1010. int pskill,
  1011. std::vector<ui16>& skills,
  1012. boost::function<void(ui32)>& callback)
  1013. {
  1014. callback(rand() % skills.size());
  1015. }
  1016. void geniusai::CGeniusAI::showGarrisonDialog(const CArmedInstance* up,
  1017. const CGHeroInstance* down,
  1018. bool removableUnits,
  1019. boost::function<void()>& onEnd)
  1020. {
  1021. onEnd();
  1022. }
  1023. void geniusai::CGeniusAI::playerBlocked(int reason)
  1024. {
  1025. if (reason == 0) // Battle is coming...
  1026. m_state.setn(UPCOMING_BATTLE);
  1027. }
  1028. void geniusai::CGeniusAI::battleResultsApplied()
  1029. {
  1030. assert(m_state.get() == ENDING_BATTLE);
  1031. m_state.setn(NO_BATTLE);
  1032. }
  1033. // TODO: Shouldn't the parameters be made const (apart from cancel)?
  1034. void CGeniusAI::showBlockingDialog(const std::string& text,
  1035. const std::vector<Component> &components,
  1036. ui32 askID,
  1037. const int soundID,
  1038. bool selection,
  1039. bool cancel)
  1040. {
  1041. m_cb->selectionMade(cancel ? false : true, askID);
  1042. }
  1043. /**
  1044. * occurs AFTER every action taken by any stack or by the hero
  1045. */
  1046. void CGeniusAI::actionFinished(const BattleAction* action)
  1047. {
  1048. std::string message("\t\tCGeniusAI::actionFinished - type(");
  1049. message += boost::lexical_cast<std::string>((unsigned)action->actionType);
  1050. message += "), side(";
  1051. message += boost::lexical_cast<std::string>((unsigned)action->side);
  1052. message += ")";
  1053. DbgBox(message.c_str());
  1054. }
  1055. /**
  1056. * occurs BEFORE every action taken by any stack or by the hero
  1057. */
  1058. void CGeniusAI::actionStarted(const BattleAction *action)
  1059. {
  1060. std::string message("\t\tCGeniusAI::actionStarted - type(");
  1061. message += boost::lexical_cast<std::string>((unsigned)action->actionType);
  1062. message += "), side(";
  1063. message += boost::lexical_cast<std::string>((unsigned)action->side);
  1064. message += ")";
  1065. DbgBox(message.c_str());
  1066. }
  1067. /**
  1068. * called when stack is performing attack
  1069. */
  1070. void CGeniusAI::battleAttack(BattleAttack* ba)
  1071. {
  1072. DbgBox("\t\t\tCGeniusAI::battleAttack");
  1073. }
  1074. /**
  1075. * called when stack receives damage (after battleAttack())
  1076. */
  1077. void CGeniusAI::battleStacksAttacked(std::set<BattleStackAttacked>& bsa)
  1078. {
  1079. DbgBox("\t\t\tCGeniusAI::battleStacksAttacked");
  1080. }
  1081. /**
  1082. * called by engine when battle starts; side=0 - left, side=1 - right
  1083. */
  1084. void CGeniusAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side)
  1085. {
  1086. // TODO: Battle logic what...
  1087. assert(!m_battleLogic);
  1088. // We have been informed that battle will start (or we are neutral AI)
  1089. assert( (playerID > PLAYER_LIMIT) || (m_state.get() == UPCOMING_BATTLE) );
  1090. m_state.setn(ONGOING_BATTLE);
  1091. m_battleLogic = new BattleAI::CBattleLogic(m_cb, army1, army2, tile, hero1,
  1092. hero2, side);
  1093. DbgBox("** CGeniusAI::battleStart **");
  1094. }
  1095. /**
  1096. *
  1097. */
  1098. void CGeniusAI::battleEnd(BattleResult* br)
  1099. {
  1100. switch (br->winner) {
  1101. case 0: std::cout << "The winner is the attacker." << std::endl;break;
  1102. case 1: std::cout << "The winner is the defender." << std::endl;break;
  1103. case 2: std::cout << "It's a draw." << std::endl;break;
  1104. };
  1105. cout << "lost ";
  1106. for (std::map<ui32,si32>::iterator i = br->casualties[0].begin();\
  1107. i != br->casualties[0].end();
  1108. i++)
  1109. cout << i->second << " " << VLC->creh->creatures[i->first]->namePl << endl;
  1110. delete m_battleLogic;
  1111. m_battleLogic = NULL;
  1112. assert(m_state.get() == ONGOING_BATTLE);
  1113. m_state.setn(ENDING_BATTLE);
  1114. DbgBox("** CGeniusAI::battleEnd **");
  1115. }
  1116. /*
  1117. * Called at the beggining of each turn, round = -1 is the tactic phase,
  1118. * round = 0 is the first "normal" turn.
  1119. */
  1120. void CGeniusAI::battleNewRound(int round)
  1121. {
  1122. std::string message("\tCGeniusAI::battleNewRound - ");
  1123. message += boost::lexical_cast<std::string>(round);
  1124. DbgBox(message.c_str());
  1125. m_battleLogic->SetCurrentTurn(round);
  1126. }
  1127. /**
  1128. *
  1129. */
  1130. void CGeniusAI::battleStackMoved(int ID, int dest, int distance, bool end)
  1131. {
  1132. std::string message("\t\t\tCGeniusAI::battleStackMoved ID(");
  1133. message += boost::lexical_cast<std::string>(ID);
  1134. message += "), dest(";
  1135. message += boost::lexical_cast<std::string>(dest);
  1136. message += ")";
  1137. DbgBox(message.c_str());
  1138. }
  1139. /**
  1140. *
  1141. */
  1142. void CGeniusAI::battleSpellCast(BattleSpellCast *sc)
  1143. {
  1144. DbgBox("\t\t\tCGeniusAI::battleSpellCast");
  1145. }
  1146. /**
  1147. * called when battlefield is prepared, prior the battle beginning
  1148. */
  1149. void CGeniusAI::battlefieldPrepared(int battlefieldType,
  1150. std::vector<CObstacle*> obstacles)
  1151. {
  1152. DbgBox("CGeniusAI::battlefieldPrepared");
  1153. }
  1154. /**
  1155. *
  1156. */
  1157. void CGeniusAI::battleStackMoved(int ID,
  1158. int dest,
  1159. bool startMoving,
  1160. bool endMoving)
  1161. {
  1162. DbgBox("\t\t\tCGeniusAI::battleStackMoved");
  1163. }
  1164. /**
  1165. *
  1166. */
  1167. void CGeniusAI::battleStackAttacking(int ID, int dest)
  1168. {
  1169. DbgBox("\t\t\tCGeniusAI::battleStackAttacking");
  1170. }
  1171. /**
  1172. *
  1173. */
  1174. void CGeniusAI::battleStackIsAttacked(int ID,
  1175. int dmg,
  1176. int killed,
  1177. int IDby,
  1178. bool byShooting)
  1179. {
  1180. DbgBox("\t\t\tCGeniusAI::battleStackIsAttacked");
  1181. }
  1182. /**
  1183. * called when it's turn of that stack
  1184. */
  1185. BattleAction CGeniusAI::activeStack(int stackID)
  1186. {
  1187. std::string message("\t\t\tCGeniusAI::activeStack stackID(");
  1188. message += boost::lexical_cast<std::string>(stackID);
  1189. message += ")";
  1190. DbgBox(message.c_str());
  1191. BattleAction bact = m_battleLogic->MakeDecision(stackID);
  1192. assert(m_cb->battleGetStackByID(bact.stackNumber));
  1193. return bact;
  1194. };