CGeniusAI.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. #include "CGeniusAI.h"
  2. #include <iostream>
  3. #include "../../hch/CBuildingHandler.h"
  4. using namespace std;
  5. using namespace GeniusAI;
  6. #if defined (_MSC_VER) && (_MSC_VER >= 1020) || (__MINGW32__)
  7. #include <windows.h>
  8. #endif
  9. void DbgBox(const char *msg, bool messageBox)
  10. {
  11. #if defined PRINT_DEBUG
  12. #if defined _DEBUG
  13. //#if 0
  14. # if defined (_MSC_VER) && (_MSC_VER >= 1020)
  15. if (messageBox)
  16. {
  17. MessageBoxA(NULL, msg, "Debug message", MB_OK | MB_ICONASTERISK);
  18. }
  19. # endif
  20. std::cout << msg << std::endl;
  21. #endif
  22. #endif
  23. }
  24. CGeniusAI::CGeniusAI()
  25. : m_generalAI(), turn(0), m_state(NO_BATTLE), firstTurn(true)
  26. {
  27. }
  28. CGeniusAI::~CGeniusAI()
  29. {
  30. }
  31. void CGeniusAI::init(ICallback *CB)
  32. {
  33. m_cb = CB;
  34. m_generalAI.init(CB);
  35. human = false;
  36. playerID = m_cb->getMyColor();
  37. serialID = m_cb->getMySerial();
  38. std::string info = std::string("GeniusAI initialized for player ") + boost::lexical_cast<std::string>(playerID);
  39. m_battleLogic = NULL;
  40. DbgBox(info.c_str());
  41. }
  42. unsigned long randomFromInt(unsigned long in)
  43. {
  44. return (in*214013+2531011);
  45. }
  46. void CGeniusAI::reportResources()
  47. {
  48. std::cout << "AI Player " <<m_cb->getMySerial()<< " with " << m_cb->howManyHeroes(true) << " heroes. " << std::endl;
  49. std::cout << m_cb->getResourceAmount(0) << " wood. ";
  50. std::cout << m_cb->getResourceAmount(1) << " mercury. ";
  51. std::cout << m_cb->getResourceAmount(2) << " ore. ";
  52. std::cout << m_cb->getResourceAmount(3) << " sulfer. ";
  53. std::cout << m_cb->getResourceAmount(4) << " cristal. ";
  54. std::cout << m_cb->getResourceAmount(5) << " gems. ";
  55. std::cout << m_cb->getResourceAmount(6) << " gold.";
  56. std::cout << std::endl;
  57. }
  58. void CGeniusAI::addHeroObjectives(CGeniusAI::HypotheticalGameState::HeroModel &h, CGeniusAI::HypotheticalGameState &hgs)
  59. {
  60. int3 hpos, destination;
  61. CPath path;
  62. hpos = h.pos;
  63. int movement = h.remainingMovement;
  64. for(std::set<AIObjectContainer>::const_iterator i = hgs.knownVisitableObjects.begin(); i != hgs.knownVisitableObjects.end();i++)
  65. {
  66. // if(i->o->ID==54||i->o->ID==34) //creatures, another hero
  67. // continue;
  68. if(i->o->ID==53) //mine
  69. if(i->o->getOwner()==m_cb->getMyColor())//don't visit if you own, there's almost no point(maybe to leave guards or because the hero's trapped).
  70. continue;
  71. destination = i->o->getSightCenter();
  72. if(hpos.z==destination.z)
  73. if(m_cb->getPath(hpos,destination,h.h,path))
  74. {
  75. path.convert(0);
  76. if(path.nodes[0].dist<movement)
  77. {
  78. AIObjective::Type tp = AIObjective::visit;
  79. HeroObjective ho(tp,i->o,&h);
  80. std::set<HeroObjective>::iterator found = currentHeroObjectives.find(ho);
  81. if(found==currentHeroObjectives.end())
  82. currentHeroObjectives.insert(ho);
  83. else
  84. found->whoCanAchieve.push_back(&h);
  85. }
  86. }
  87. }
  88. }
  89. void CGeniusAI::addTownObjectives(HypotheticalGameState::TownModel &t, HypotheticalGameState & hgs)
  90. {
  91. //recruitHero
  92. //recruitCreatures
  93. //upgradeCreatures
  94. //buildBuilding
  95. if(hgs.heroModels.size()<3&&hgs.resourceAmounts[6]>=2500) //recruitHero
  96. {
  97. if(!t.visitingHero)
  98. {
  99. for(int i =0; i < hgs.AvailableHeroesToBuy.size();i++)
  100. if(hgs.AvailableHeroesToBuy[i]->army.slots.size()>1)//only buy heros with units
  101. {
  102. TownObjective to(AIObjective::recruitHero,&t,0);
  103. currentTownObjectives.insert(to);
  104. }
  105. }
  106. }
  107. /* for(int i = 0; i < t.t->creatures.size() ;i++)
  108. {
  109. if(t.t->creatures[i].second.empty()) continue;
  110. int ID = t.t->creatures[i].second.back();
  111. const CCreature *creature = m_cb->getCCreatureByID(ID);
  112. cout << "town has " << t.t->creatures[i].first << " "<< creature->namePl << " (AI Strength " << creature->AIValue << ")." << endl;
  113. }
  114. //buildBuilding
  115. std::map<int, CBuilding *> thisTownsBuildings = m_cb->getCBuildingsByID(t.t);
  116. for(std::map<int, CBuilding *>::iterator i = thisTownsBuildings.begin(); i != thisTownsBuildings.end();i++)
  117. cout << "structure "<< i->first << ", " << i->second->Name() << ", build?= " << m_cb->canBuildStructure(t.t,i->first) << endl;
  118. */
  119. }
  120. void CGeniusAI::TownObjective::fulfill(CGeniusAI & cg,HypotheticalGameState &hgs)
  121. {
  122. cg.m_cb->waitTillRealize = true;
  123. switch(type)
  124. {
  125. case recruitHero:
  126. cg.m_cb->recruitHero(whichTown->t,hgs.AvailableHeroesToBuy[which]);
  127. hgs.heroModels.push_back(hgs.AvailableHeroesToBuy[which]);
  128. whichTown->visitingHero = true;
  129. //TODO: sub 2500 gold from hgs here
  130. }
  131. cg.m_cb->waitTillRealize = false;
  132. }
  133. void CGeniusAI::HeroObjective::fulfill(CGeniusAI & cg,HypotheticalGameState & hgs)
  134. {
  135. cg.m_cb->waitTillRealize = true;
  136. switch(type)
  137. {
  138. case visit:
  139. HypotheticalGameState::HeroModel * h = whoCanAchieve[rand()%whoCanAchieve.size()];
  140. int3 hpos, destination;
  141. CPath path;
  142. hpos = h->pos;
  143. //std::cout << "trying to visit " << object->hoverName << std::endl;
  144. destination = object->getSightCenter();
  145. if(cg.m_cb->getPath(hpos,destination,h->h,path))
  146. {
  147. path.convert(0);
  148. //wait over, battle over too. hero might be killed. check.
  149. for(int i = path.nodes.size()-2;i>=0&&(cg.m_cb->getHeroSerial(h->h) >= 0);i--)
  150. {
  151. cg.m_cb->moveHero(h->h,path.nodes[i].coord);
  152. if(cg.m_state.get() != NO_BATTLE)
  153. cg.m_state.waitUntil(NO_BATTLE);//wait for battle end
  154. }
  155. h->remainingMovement-=path.nodes[0].dist;
  156. if(object->blockVisit)
  157. h->pos = path.nodes[1].coord;
  158. else
  159. h->pos=destination;
  160. std::set<AIObjectContainer>::iterator i = hgs.knownVisitableObjects.find(AIObjectContainer(object));
  161. if(i!=hgs.knownVisitableObjects.end())
  162. hgs.knownVisitableObjects.erase(i);
  163. }
  164. }
  165. cg.m_cb->waitTillRealize = false;
  166. }
  167. void CGeniusAI::fillObjectiveQueue(HypotheticalGameState & hgs)
  168. {
  169. objectiveQueue.clear();
  170. currentHeroObjectives.clear();
  171. currentTownObjectives.clear();
  172. for(std::vector <CGeniusAI::HypotheticalGameState::HeroModel>::iterator i = hgs.heroModels.begin(); i != hgs.heroModels.end(); i++)
  173. addHeroObjectives(*i,hgs);
  174. for(std::vector <CGeniusAI::HypotheticalGameState::TownModel>::iterator i = hgs.townModels.begin(); i != hgs.townModels.end(); i++)
  175. addTownObjectives(*i,hgs);
  176. for(std::set<CGeniusAI::HeroObjective>::iterator i = currentHeroObjectives.begin(); i != currentHeroObjectives.end(); i++)
  177. objectiveQueue.push_back(AIObjectivePtrCont(&(*i)));
  178. for(std::set<CGeniusAI::TownObjective>::iterator i = currentTownObjectives.begin(); i != currentTownObjectives.end(); i++)
  179. objectiveQueue.push_back(AIObjectivePtrCont(&(*i)));
  180. }
  181. CGeniusAI::AIObjective * CGeniusAI::getBestObjective()
  182. {
  183. trueGameState = HypotheticalGameState(*this);
  184. fillObjectiveQueue(trueGameState);
  185. if(!objectiveQueue.empty())
  186. return max_element(objectiveQueue.begin(),objectiveQueue.end())->obj;
  187. return NULL;
  188. }
  189. void CGeniusAI::yourTurn()
  190. {
  191. static int seed = rand();
  192. srand(seed);
  193. if(firstTurn)
  194. {
  195. //m_cb->sendMessage("vcmieagles");
  196. //m_cb->sendMessage("vcmiformenos");
  197. //m_cb->sendMessage("vcmiformenos");
  198. firstTurn = false;
  199. }
  200. //////////////TODO: replace with updates. Also add suspected objects list./////////
  201. knownVisitableObjects.clear();
  202. int3 pos = m_cb->getMapSize();
  203. for(int x = 0;x<pos.x;x++)
  204. for(int y = 0;y<pos.y;y++)
  205. for(int z = 0;z<pos.z;z++)
  206. tileRevealed(int3(x,y,z));
  207. ///////////////////////////////////////////////////////////////////////////////////
  208. // reportResources();
  209. turn++;
  210. AIObjective * objective;
  211. while((objective = getBestObjective())!=NULL)
  212. objective->fulfill(*this,trueGameState);
  213. seed = rand();
  214. m_cb->endTurn();
  215. }
  216. void CGeniusAI::heroKilled(const CGHeroInstance * hero)
  217. {
  218. }
  219. void CGeniusAI::heroCreated(const CGHeroInstance *hero)
  220. {
  221. }
  222. void CGeniusAI::tileRevealed(int3 pos)
  223. {
  224. std::vector < const CGObjectInstance * > objects = m_cb->getVisitableObjs(pos);
  225. for(std::vector < const CGObjectInstance * >::iterator o = objects.begin();o!=objects.end();o++)
  226. knownVisitableObjects.insert(*o);
  227. objects = m_cb->getFlaggableObjects(pos);
  228. for(std::vector < const CGObjectInstance * >::iterator o = objects.begin();o!=objects.end();o++)
  229. knownVisitableObjects.insert(*o);
  230. }
  231. void CGeniusAI::newObject(const CGObjectInstance * obj) //eg. ship built in shipyard
  232. {
  233. knownVisitableObjects.insert(obj);
  234. }
  235. void CGeniusAI::objectRemoved(const CGObjectInstance *obj) //eg. collected resource, picked artifact, beaten hero
  236. {
  237. std::set <AIObjectContainer>::iterator o = knownVisitableObjects.find(obj);
  238. if(o!=knownVisitableObjects.end())
  239. knownVisitableObjects.erase(o);
  240. }
  241. void CGeniusAI::tileHidden(int3 pos)
  242. {
  243. }
  244. void CGeniusAI::heroMoved(const TryMoveHero &TMH)
  245. {
  246. //DbgBox("** CGeniusAI::heroMoved **");
  247. }
  248. void CGeniusAI::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback)
  249. {
  250. callback(rand() % skills.size());
  251. }
  252. void GeniusAI::CGeniusAI::showGarrisonDialog( const CArmedInstance *up, const CGHeroInstance *down, boost::function<void()> &onEnd )
  253. {
  254. onEnd();
  255. }
  256. void GeniusAI::CGeniusAI::playerBlocked( int reason )
  257. {
  258. if(reason == 0) //battle is coming...
  259. {
  260. m_state.setn(UPCOMING_BATTLE);
  261. }
  262. }
  263. void GeniusAI::CGeniusAI::battleResultsApplied()
  264. {
  265. assert(m_state.get() == ENDING_BATTLE);
  266. m_state.setn(NO_BATTLE);
  267. }
  268. void CGeniusAI::showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel)
  269. {
  270. m_cb->selectionMade(cancel ? 0 : 1, askID);
  271. }
  272. /**
  273. * occurs AFTER every action taken by any stack or by the hero
  274. */
  275. void CGeniusAI::actionFinished(const BattleAction *action)
  276. {
  277. std::string message("\t\tCGeniusAI::actionFinished - type(");
  278. message += boost::lexical_cast<std::string>((unsigned)action->actionType);
  279. message += "), side(";
  280. message += boost::lexical_cast<std::string>((unsigned)action->side);
  281. message += ")";
  282. DbgBox(message.c_str());
  283. }
  284. /**
  285. * occurs BEFORE every action taken by any stack or by the hero
  286. */
  287. void CGeniusAI::actionStarted(const BattleAction *action)
  288. {
  289. std::string message("\t\tCGeniusAI::actionStarted - type(");
  290. message += boost::lexical_cast<std::string>((unsigned)action->actionType);
  291. message += "), side(";
  292. message += boost::lexical_cast<std::string>((unsigned)action->side);
  293. message += ")";
  294. DbgBox(message.c_str());
  295. }
  296. /**
  297. * called when stack is performing attack
  298. */
  299. void CGeniusAI::battleAttack(BattleAttack *ba)
  300. {
  301. DbgBox("\t\t\tCGeniusAI::battleAttack");
  302. }
  303. /**
  304. * called when stack receives damage (after battleAttack())
  305. */
  306. void CGeniusAI::battleStacksAttacked(std::set<BattleStackAttacked> & bsa)
  307. {
  308. DbgBox("\t\t\tCGeniusAI::battleStacksAttacked");
  309. }
  310. /**
  311. * called by engine when battle starts; side=0 - left, side=1 - right
  312. */
  313. void CGeniusAI::battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side)
  314. {
  315. assert(!m_battleLogic);
  316. assert(playerID > PLAYER_LIMIT || m_state.get() == UPCOMING_BATTLE); //we have been informed that battle will start (or we are neutral AI)
  317. m_state.setn(ONGOING_BATTLE);
  318. m_battleLogic = new BattleAI::CBattleLogic(m_cb, army1, army2, tile, hero1, hero2, side);
  319. DbgBox("** CGeniusAI::battleStart **");
  320. }
  321. /**
  322. *
  323. */
  324. void CGeniusAI::battleEnd(BattleResult *br)
  325. {
  326. /*switch(br->winner)
  327. {
  328. case 0: std::cout << "The winner is the attacker." << std::endl;break;
  329. case 1: std::cout << "The winner is the defender." << std::endl;break;
  330. case 2: std::cout << "It's a draw." << std::endl;break;
  331. };*/
  332. delete m_battleLogic;
  333. m_battleLogic = NULL;
  334. assert(m_state.get() == ONGOING_BATTLE);
  335. m_state.setn(ENDING_BATTLE);
  336. DbgBox("** CGeniusAI::battleEnd **");
  337. }
  338. /**
  339. * called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
  340. */
  341. void CGeniusAI::battleNewRound(int round)
  342. {
  343. std::string message("\tCGeniusAI::battleNewRound - ");
  344. message += boost::lexical_cast<std::string>(round);
  345. DbgBox(message.c_str());
  346. m_battleLogic->SetCurrentTurn(round);
  347. }
  348. /**
  349. *
  350. */
  351. void CGeniusAI::battleStackMoved(int ID, int dest, int distance, bool end)
  352. {
  353. std::string message("\t\t\tCGeniusAI::battleStackMoved ID(");
  354. message += boost::lexical_cast<std::string>(ID);
  355. message += "), dest(";
  356. message += boost::lexical_cast<std::string>(dest);
  357. message += ")";
  358. DbgBox(message.c_str());
  359. }
  360. /**
  361. *
  362. */
  363. void CGeniusAI::battleSpellCast(SpellCast *sc)
  364. {
  365. DbgBox("\t\t\tCGeniusAI::battleSpellCast");
  366. }
  367. /**
  368. * called when battlefield is prepared, prior the battle beginning
  369. */
  370. void CGeniusAI::battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles)
  371. {
  372. DbgBox("CGeniusAI::battlefieldPrepared");
  373. }
  374. /**
  375. *
  376. */
  377. void CGeniusAI::battleStackMoved(int ID, int dest, bool startMoving, bool endMoving)
  378. {
  379. DbgBox("\t\t\tCGeniusAI::battleStackMoved");
  380. }
  381. /**
  382. *
  383. */
  384. void CGeniusAI::battleStackAttacking(int ID, int dest)
  385. {
  386. DbgBox("\t\t\tCGeniusAI::battleStackAttacking");
  387. }
  388. /**
  389. *
  390. */
  391. void CGeniusAI::battleStackIsAttacked(int ID, int dmg, int killed, int IDby, bool byShooting)
  392. {
  393. DbgBox("\t\t\tCGeniusAI::battleStackIsAttacked");
  394. }
  395. /**
  396. * called when it's turn of that stack
  397. */
  398. BattleAction CGeniusAI::activeStack(int stackID)
  399. {
  400. std::string message("\t\t\tCGeniusAI::activeStack stackID(");
  401. message += boost::lexical_cast<std::string>(stackID);
  402. message += ")";
  403. DbgBox(message.c_str());
  404. return m_battleLogic->MakeDecision(stackID);
  405. };