2
0

base.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /*
  2. * base.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 "callback/CBattleCallback.h"
  12. #include "networkPacks/PacksForClientBattle.h"
  13. #include "networkPacks/SetStackEffect.h"
  14. #include "spells/CSpellHandler.h"
  15. #include "vcmi/Environment.h"
  16. #include "BAI/v13/BAI.h"
  17. #include "base.h"
  18. namespace MMAI::BAI
  19. {
  20. // static
  21. std::shared_ptr<Base>
  22. Base::Create(Schema::IModel * model, const std::shared_ptr<Environment> & env, const std::shared_ptr<CBattleCallback> & cb, bool enableSpellsUsage)
  23. {
  24. std::shared_ptr<Base> res;
  25. auto version = model->getVersion();
  26. if(version == 13)
  27. res = std::make_shared<V13::BAI>(model, version, env, cb);
  28. else
  29. throw std::runtime_error("Unsupported schema version: " + std::to_string(version));
  30. res->init(enableSpellsUsage);
  31. return res;
  32. }
  33. Base::Base(Schema::IModel * model, int version, const std::shared_ptr<Environment> & env, const std::shared_ptr<CBattleCallback> & cb)
  34. : model(model), version(version), name("BAI-v" + std::to_string(version)), colorname(cb->getPlayerID()->toString()), env(env), cb(cb)
  35. {
  36. std::ostringstream oss;
  37. // Store the memory address and include it in logging
  38. const auto * ptr = static_cast<const void *>(this);
  39. oss << ptr;
  40. addrstr = oss.str();
  41. const char * envvar = std::getenv("MMAI_VERBOSE");
  42. verbose = envvar != nullptr && strcmp(envvar, "1") == 0;
  43. }
  44. /*
  45. * These methods MUST be overridden by derived BAI (e.g. BAI::V1)
  46. * Their base implementation is is for logging purposes only.
  47. */
  48. void Base::activeStack(const BattleID & bid, const CStack * astack)
  49. {
  50. debug("*** activeStack ***");
  51. trace("activeStack called for " + astack->nodeName());
  52. };
  53. void Base::yourTacticPhase(const BattleID & bid, int distance)
  54. {
  55. debug("*** yourTacticPhase ***");
  56. };
  57. /*
  58. * These methods MAY be overriden by derived BAI (e.g. BAI::V1)
  59. * Their implementation here is a no-op.
  60. */
  61. void Base::init(bool enableSpellsUsage_)
  62. {
  63. enableSpellsUsage = enableSpellsUsage_;
  64. debug("*** init ***");
  65. }
  66. void Base::actionFinished(const BattleID & bid, const BattleAction & action)
  67. {
  68. debug("*** actionFinished ***");
  69. }
  70. void Base::actionStarted(const BattleID & bid, const BattleAction & action)
  71. {
  72. debug("*** actionStarted ***");
  73. }
  74. void Base::battleAttack(const BattleID & bid, const BattleAttack * ba)
  75. {
  76. debug("*** battleAttack ***");
  77. }
  78. void Base::battleCatapultAttacked(const BattleID & bid, const CatapultAttack & ca)
  79. {
  80. debug("*** battleCatapultAttacked ***");
  81. }
  82. void Base::battleEnd(const BattleID & bid, const BattleResult * br, QueryID queryID)
  83. {
  84. debug("*** battleEnd ***");
  85. }
  86. void Base::battleGateStateChanged(const BattleID & bid, const EGateState state)
  87. {
  88. debug("*** battleGateStateChanged ***");
  89. trace("New gate state: %d", EI(state));
  90. }
  91. void Base::battleLogMessage(const BattleID & bid, const std::vector<MetaString> & lines)
  92. {
  93. debug("*** battleLogMessage ***");
  94. if(verbose)
  95. {
  96. std::string res = "Messages:";
  97. for(const auto & line : lines)
  98. {
  99. std::string formatted = line.toString();
  100. boost::algorithm::trim(formatted);
  101. res = res + "\n\t* " + formatted;
  102. }
  103. std::cout << "MMAI_VERBOSE: " << res << "\n";
  104. }
  105. }
  106. void Base::battleNewRound(const BattleID & bid)
  107. {
  108. debug("*** battleNewRound ***");
  109. }
  110. void Base::battleNewRoundFirst(const BattleID & bid)
  111. {
  112. debug("*** battleNewRoundFirst ***");
  113. }
  114. void Base::battleObstaclesChanged(const BattleID & bid, const std::vector<ObstacleChanges> & obstacles)
  115. {
  116. debug("*** battleObstaclesChanged ***");
  117. }
  118. void Base::battleSpellCast(const BattleID & bid, const BattleSpellCast * sc)
  119. {
  120. debug("*** battleSpellCast ***");
  121. if(verbose)
  122. {
  123. std::string res = "Spellcast info:";
  124. auto battle = cb->getBattle(bid);
  125. const auto * caster = battle->battleGetStackByID(sc->casterStack, false);
  126. res += "\n\t* spell: " + sc->spellID.toSpell()->identifier;
  127. res += "\n\t* castByHero=" + std::to_string(sc->castByHero);
  128. res += "\n\t* casterStack=" + (caster ? caster->getDescription() : "");
  129. res += "\n\t* activeCast=" + std::to_string(sc->activeCast);
  130. res += "\n\t* side=" + std::to_string(EI(sc->side));
  131. res += "\n\t* tile=" + std::to_string(sc->tile.toInt());
  132. res += "\n\t* affected:";
  133. for(const auto & cid : sc->affectedCres)
  134. res += "\n\t > " + battle->battleGetStackByID(cid, false)->getDescription();
  135. res += "\n\t* resisted:";
  136. for(const auto & cid : sc->resistedCres)
  137. res += "\n\t > " + battle->battleGetStackByID(cid, false)->getDescription();
  138. res += "\n\t* reflected:";
  139. for(const auto & cid : sc->reflectedCres)
  140. res += "\n\t > " + battle->battleGetStackByID(cid, false)->getDescription();
  141. std::cout << "MMAI_VERBOSE: " << res << "\n";
  142. }
  143. }
  144. void Base::battleStackMoved(const BattleID & bid, const CStack * stack, const BattleHexArray & dest, int distance, bool teleport)
  145. {
  146. debug("*** battleStackMoved ***");
  147. if(verbose)
  148. {
  149. auto battle = cb->getBattle(bid);
  150. std::string fmt = "Movement info:";
  151. fmt += "\n\t* stack description=%s";
  152. fmt += "\n\t* stack owner=%s";
  153. fmt += "\n\t* dest[0]=%d (Hex#%d, y=%d, x=%d)";
  154. fmt += "\n\t* distance=%d";
  155. fmt += "\n\t* teleport=%d";
  156. auto bh0 = dest.at(dest.size() - 1);
  157. auto hexid0 = bh0.getX() - 1 + (bh0.getY() * 15);
  158. auto x0 = bh0.getX() - 1;
  159. auto y0 = bh0.getY();
  160. auto res = boost::format(fmt) % stack->getDescription() % stack->getOwner().toString() % bh0 % hexid0 % y0 % x0 % distance % teleport;
  161. std::cout << "MMAI_VERBOSE: " << boost::str(res) << "\n";
  162. }
  163. }
  164. void Base::battleStacksAttacked(const BattleID & bid, const std::vector<BattleStackAttacked> & bsa, bool ranged)
  165. {
  166. debug("*** battleStacksAttacked ***");
  167. }
  168. void Base::battleStacksEffectsSet(const BattleID & bid, const SetStackEffect & sse)
  169. {
  170. debug("*** battleStacksEffectsSet ***");
  171. if(verbose)
  172. {
  173. auto battle = cb->getBattle(bid);
  174. std::string res = "Effects set:";
  175. for(const auto & [unitid, bonuses] : sse.toAdd)
  176. {
  177. const auto & cstack = battle->battleGetStackByID(unitid);
  178. res += "\n\t* stack=" + (cstack ? cstack->getDescription() : "");
  179. for(const auto & bonus : bonuses)
  180. {
  181. res += "\n\t > add bonus=" + bonus.description.toString();
  182. }
  183. }
  184. for(const auto & [unitid, bonuses] : sse.toRemove)
  185. {
  186. const auto & cstack = battle->battleGetStackByID(unitid);
  187. res += "\n\t* stack=" + (cstack ? cstack->getDescription() : "");
  188. for(const auto & bonus : bonuses)
  189. {
  190. res += "\n\t > remove bonus=" + bonus.description.toString();
  191. }
  192. }
  193. for(const auto & [unitid, bonuses] : sse.toUpdate)
  194. {
  195. const auto & cstack = battle->battleGetStackByID(unitid);
  196. res += "\n\t* stack=" + (cstack ? cstack->getDescription() : "");
  197. for(const auto & bonus : bonuses)
  198. {
  199. res += "\n\t > update bonus=" + bonus.description.toString();
  200. }
  201. }
  202. std::cout << "MMAI_VERBOSE: " << res << "\n";
  203. }
  204. }
  205. void Base::battleStart(
  206. const BattleID & bid,
  207. const CCreatureSet * army1,
  208. const CCreatureSet * army2,
  209. int3 tile,
  210. const CGHeroInstance * hero1,
  211. const CGHeroInstance * hero2,
  212. BattleSide side,
  213. bool replayAllowed
  214. )
  215. {
  216. debug("*** battleStart ***");
  217. }
  218. // XXX: positive morale triggers an effect
  219. // negative morale just skips turn
  220. void Base::battleTriggerEffect(const BattleID & bid, const BattleTriggerEffect & bte)
  221. {
  222. debug("*** battleTriggerEffect ***");
  223. if(verbose)
  224. {
  225. auto battle = cb->getBattle(bid);
  226. const auto * cstack = battle->battleGetStackByID(bte.stackID);
  227. std::string res = "Effect triggered:";
  228. res += "\n\t* bonus id=" + std::to_string(EI(bte.effect));
  229. res += "\n\t* bonus value=" + std::to_string(bte.val);
  230. res += "\n\t* stack=" + (cstack ? cstack->getDescription() : "");
  231. std::cout << "MMAI_VERBOSE: " << res << "\n";
  232. }
  233. }
  234. void Base::battleUnitsChanged(const BattleID & bid, const std::vector<UnitChanges> & changes)
  235. {
  236. debug("*** battleUnitsChanged ***");
  237. if(verbose)
  238. {
  239. std::string res = "Changes:";
  240. for(const auto & change : changes)
  241. {
  242. res += "\n\t* operation=" + std::to_string(EI(change.operation));
  243. res += "\n\t* healthDelta=" + std::to_string(change.healthDelta);
  244. }
  245. std::cout << "MMAI_VERBOSE: " << res << "\n";
  246. }
  247. }
  248. }