StupidAI.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. #include "stdafx.h"
  2. #include "StupidAI.h"
  3. #include "../../lib/BattleState.h"
  4. #include "../../CCallback.h"
  5. #include <boost/foreach.hpp>
  6. #include <boost/bind.hpp>
  7. #include "../../lib/CCreatureHandler.h"
  8. #include <algorithm>
  9. //#include <boost/thread.hpp>
  10. #include "../../lib/CHeroHandler.h"
  11. #include "../../lib/VCMI_Lib.h"
  12. #include "../../lib/CSpellHandler.h"
  13. CBattleCallback * cbc;
  14. CStupidAI::CStupidAI(void)
  15. : side(-1), cb(NULL)
  16. {
  17. print("created");
  18. }
  19. CStupidAI::~CStupidAI(void)
  20. {
  21. print("destroyed");
  22. }
  23. void CStupidAI::init( CBattleCallback * CB )
  24. {
  25. print("init called, saving ptr to IBattleCallback");
  26. cbc = cb = CB;
  27. }
  28. void CStupidAI::actionFinished( const BattleAction *action )
  29. {
  30. print("actionFinished called");
  31. }
  32. void CStupidAI::actionStarted( const BattleAction *action )
  33. {
  34. print("actionStarted called");
  35. }
  36. struct EnemyInfo
  37. {
  38. const CStack * s;
  39. int adi, adr;
  40. std::vector<THex> attackFrom; //for melee fight
  41. EnemyInfo(const CStack * _s) : s(_s)
  42. {}
  43. void calcDmg(const CStack * ourStack)
  44. {
  45. TDmgRange retal, dmg = cbc->battleEstimateDamage(ourStack, s, &retal);
  46. adi = (dmg.first + dmg.second) / 2;
  47. adr = (retal.first + retal.second) / 2;
  48. }
  49. bool operator==(const EnemyInfo& ei) const
  50. {
  51. return s == ei.s;
  52. }
  53. };
  54. bool isMoreProfitable(const EnemyInfo &ei1, const EnemyInfo& ei2)
  55. {
  56. return (ei1.adi-ei1.adr) < (ei2.adi - ei2.adr);
  57. }
  58. int distToNearestNeighbour(THex hex, const std::vector<int> & dists, THex *chosenHex = NULL)
  59. {
  60. int ret = 1000000;
  61. BOOST_FOREACH(THex n, hex.neighbouringTiles())
  62. {
  63. if(dists[n] >= 0 && dists[n] < ret)
  64. {
  65. ret = dists[n];
  66. if(chosenHex)
  67. *chosenHex = n;
  68. }
  69. }
  70. return ret;
  71. }
  72. bool isCloser(const EnemyInfo & ei1, const EnemyInfo & ei2, const std::vector<int> & dists)
  73. {
  74. return distToNearestNeighbour(ei1.s->position, dists) < distToNearestNeighbour(ei2.s->position, dists);
  75. }
  76. static bool willSecondHexBlockMoreEnemyShooters(const THex &h1, const THex &h2)
  77. {
  78. int shooters[2] = {0}; //count of shooters on hexes
  79. for(int i = 0; i < 2; i++)
  80. BOOST_FOREACH(THex neighbour, (i ? h2 : h1).neighbouringTiles())
  81. if(const CStack *s = cbc->battleGetStackByPos(neighbour))
  82. if(s->getCreature()->isShooting())
  83. shooters[i]++;
  84. return shooters[0] < shooters[1];
  85. }
  86. BattleAction CStupidAI::activeStack( const CStack * stack )
  87. {
  88. //boost::this_thread::sleep(boost::posix_time::seconds(2));
  89. print("activeStack called");
  90. std::vector<THex> avHexes = cb->battleGetAvailableHexes(stack, false);
  91. std::vector<int> dists = cb->battleGetDistances(stack);
  92. std::vector<EnemyInfo> enemiesShootable, enemiesReachable, enemiesUnreachable;
  93. // const CStack *firstEnemy = cb->battleGetStacks(CBattleCallback::ONLY_ENEMY).front();
  94. // if(cb->battleCanCastThisSpell(VLC->spellh->spells[Spells::FORGETFULNESS]) == SpellCasting::OK)
  95. // castSpell(Spells::FORGETFULNESS, firstEnemy->position);
  96. //
  97. // const CStack *firstEnemy = cb->battleGetStacks(CBattleCallback::ONLY_MINE).front();
  98. // if(cb->battleCanCastThisSpell(VLC->spellh->spells[Spells::AIR_SHIELD]) == SpellCasting::OK)
  99. // castSpell(Spells::AIR_SHIELD, firstEnemy->position);
  100. BOOST_FOREACH(const CStack *s, cb->battleGetStacks(CBattleCallback::ONLY_ENEMY))
  101. {
  102. if(cb->battleCanShoot(stack, s->position))
  103. {
  104. enemiesShootable.push_back(s);
  105. }
  106. else
  107. {
  108. BOOST_FOREACH(THex hex, avHexes)
  109. {
  110. if(CStack::isMeleeAttackPossible(stack, s, hex))
  111. {
  112. std::vector<EnemyInfo>::iterator i = std::find(enemiesReachable.begin(), enemiesReachable.end(), s);
  113. if(i == enemiesReachable.end())
  114. {
  115. enemiesReachable.push_back(s);
  116. i = enemiesReachable.begin() + (enemiesReachable.size() - 1);
  117. }
  118. i->attackFrom.push_back(hex);
  119. }
  120. }
  121. if(!vstd::contains(enemiesReachable, s))
  122. enemiesUnreachable.push_back(s);
  123. }
  124. }
  125. if(enemiesShootable.size())
  126. {
  127. const EnemyInfo &ei= *std::max_element(enemiesShootable.begin(), enemiesShootable.end(), isMoreProfitable);
  128. return BattleAction::makeShotAttack(stack, ei.s);
  129. }
  130. else if(enemiesReachable.size())
  131. {
  132. const EnemyInfo &ei= *std::max_element(enemiesReachable.begin(), enemiesReachable.end(), &isMoreProfitable);
  133. return BattleAction::makeMeleeAttack(stack, ei.s, *std::max_element(ei.attackFrom.begin(), ei.attackFrom.end(), &willSecondHexBlockMoreEnemyShooters));
  134. }
  135. else
  136. {
  137. const EnemyInfo &ei= *std::min_element(enemiesUnreachable.begin(), enemiesUnreachable.end(), boost::bind(isCloser, _1, _2, boost::ref(dists)));
  138. if(distToNearestNeighbour(ei.s->position, dists) < BFIELD_SIZE)
  139. {
  140. return goTowards(stack, ei.s->position);
  141. }
  142. }
  143. return BattleAction::makeDefend(stack);
  144. }
  145. void CStupidAI::battleAttack(const BattleAttack *ba)
  146. {
  147. print("battleAttack called");
  148. }
  149. void CStupidAI::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa)
  150. {
  151. print("battleStacksAttacked called");
  152. }
  153. void CStupidAI::battleEnd(const BattleResult *br)
  154. {
  155. print("battleEnd called");
  156. }
  157. // void CStupidAI::battleResultsApplied()
  158. // {
  159. // print("battleResultsApplied called");
  160. // }
  161. void CStupidAI::battleNewRoundFirst(int round)
  162. {
  163. print("battleNewRoundFirst called");
  164. }
  165. void CStupidAI::battleNewRound(int round)
  166. {
  167. print("battleNewRound called");
  168. }
  169. void CStupidAI::battleStackMoved(const CStack * stack, std::vector<THex> dest, int distance)
  170. {
  171. print("battleStackMoved called");;
  172. }
  173. void CStupidAI::battleSpellCast(const BattleSpellCast *sc)
  174. {
  175. print("battleSpellCast called");
  176. }
  177. void CStupidAI::battleStacksEffectsSet(const SetStackEffect & sse)
  178. {
  179. print("battleStacksEffectsSet called");
  180. }
  181. void CStupidAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side)
  182. {
  183. print("battleStart called");
  184. side = Side;
  185. printOpeningReport();
  186. }
  187. void CStupidAI::battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom)
  188. {
  189. print("battleStacksHealedRes called");
  190. }
  191. void CStupidAI::battleNewStackAppeared(const CStack * stack)
  192. {
  193. print("battleNewStackAppeared called");
  194. }
  195. void CStupidAI::battleObstaclesRemoved(const std::set<si32> & removedObstacles)
  196. {
  197. print("battleObstaclesRemoved called");
  198. }
  199. void CStupidAI::battleCatapultAttacked(const CatapultAttack & ca)
  200. {
  201. print("battleCatapultAttacked called");
  202. }
  203. void CStupidAI::battleStacksRemoved(const BattleStacksRemoved & bsr)
  204. {
  205. print("battleStacksRemoved called");
  206. }
  207. void CStupidAI::print(const std::string &text) const
  208. {
  209. tlog0 << "CStupidAI [" << this <<"]: " << text << std::endl;
  210. }
  211. BattleAction CStupidAI::goTowards(const CStack * stack, THex hex)
  212. {
  213. THex realDest = hex;
  214. THex predecessors[BFIELD_SIZE];
  215. std::vector<int> dists = cb->battleGetDistances(stack, hex);
  216. if(distToNearestNeighbour(hex, dists, &realDest) > BFIELD_SIZE)
  217. {
  218. print("goTowards: Cannot reach");
  219. return BattleAction::makeDefend(stack);
  220. }
  221. dists = cb->battleGetDistances(stack, realDest, predecessors);
  222. std::vector<THex> avHexes = cb->battleGetAvailableHexes(stack, false);
  223. if(!avHexes.size())
  224. {
  225. print("goTowards: Stack cannot move! That's " + stack->nodeName());
  226. return BattleAction::makeDefend(stack);
  227. }
  228. while(1)
  229. {
  230. assert(realDest.isValid());
  231. if(vstd::contains(avHexes, hex))
  232. return BattleAction::makeMove(stack, hex);
  233. hex = predecessors[hex];
  234. }
  235. }
  236. void CStupidAI::printOpeningReport()
  237. {
  238. TStacks myStacks = cb->battleGetStacks(CBattleCallback::ONLY_MINE);
  239. tlog5 << "My side: " << side << std::endl;
  240. if(const CGHeroInstance *h = cb->battleGetFightingHero(side))
  241. {
  242. tlog5 << boost::format("I have a hero named %s (Type ID=%d)\n") % h->name % h->type->ID;
  243. tlog5 << boost::format("Hero skills: Attack %d, Defense %d, Spell Power %d, Knowledge %d, Mana %d/%d\n")
  244. % h->Attack() % h->Defense() % h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)
  245. % h->getPrimSkillLevel(PrimarySkill::KNOWLEDGE) % h->mana % h->manaLimit();
  246. tlog5 << "Number of known spells: " << h->spells.size() << std::endl;
  247. }
  248. else
  249. tlog5 << "I do not have a hero.\n";
  250. tlog5 << "I have " << myStacks.size() << " stacks. They are:\n";
  251. for(int i = 0; i < myStacks.size(); i++)
  252. {
  253. const CStack *s = myStacks.at(i);
  254. tlog5 << format("%2d) Stack of %4d %s.\n\tAttack:\t\t%4d, \n\tDefense:\t%4d, \n\tHP:\t\t%4d\n\tDamage:\t\t%4d-%d\n")
  255. % (i+1) % s->count % s->getCreature()->namePl % s->Attack() % s->Defense() % s->MaxHealth() % s->getMinDamage() % s->getMaxDamage();
  256. }
  257. }
  258. void CStupidAI::castSpell(int spellID, int destinationTile, bool safe/* = true*/)
  259. {
  260. const CGHeroInstance *h = cb->battleGetFightingHero(side);
  261. if(!h)
  262. {
  263. tlog1 << "A hero is required for casting spells!\n";
  264. return;
  265. }
  266. SpellCasting::ESpellCastProblem canCast = safe ? cb->battleCanCastThisSpell(VLC->spellh->spells[spellID]) : SpellCasting::OK;
  267. if(canCast != SpellCasting::OK)
  268. {
  269. tlog1 << "Spell cannot be cast (problem=" << canCast << ")!\n";
  270. return;
  271. }
  272. BattleAction ba;
  273. ba.actionType = BattleAction::HERO_SPELL;
  274. ba.destinationTile = destinationTile;
  275. ba.side = side;
  276. ba.stackNumber = -(side+1); //-1 dla lewego bohatera, -2 dla prawego
  277. ba.additionalInfo = spellID;
  278. cb->battleMakeAction(&ba);
  279. }
  280. void CStupidAI::yourTacticPhase(int distance)
  281. {
  282. print("yourTacticPhase called");
  283. const CStack *someEnemy = cb->battleGetStacks(CBattleInfoCallback::ONLY_ENEMY).front();
  284. BOOST_FOREACH(const CStack *someStack, cb->battleGetStacks(CBattleCallback::ONLY_MINE))
  285. {
  286. BattleAction move;
  287. if(cb->battleCanShoot(someStack, someEnemy->position))
  288. move = BattleAction::makeMove(someStack, someStack->position + THex::RIGHT);
  289. else
  290. move = BattleAction::makeMove(someStack, someStack->position + THex::TOP_RIGHT);
  291. tlog0 << "Moving " << someStack->nodeName() << " to " << move.destinationTile << std::endl;
  292. cb->battleMakeTacticAction(&move);
  293. }
  294. BattleAction endTactics = BattleAction::makeEndOFTacticPhase(side);
  295. cb->battleMakeTacticAction(&endTactics); //wazne - trzeba zakonczyc faze taktyczna!
  296. }