Actors.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /*
  2. * AINodeStorage.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 "Actors.h"
  12. #include "../../../CCallback.h"
  13. #include "../../../lib/mapping/CMap.h"
  14. #include "../../../lib/mapObjects/MapObjects.h"
  15. #include "../Goals/VisitHero.h"
  16. class ExchangeAction : public ISpecialAction
  17. {
  18. private:
  19. const CGHeroInstance * target;
  20. const CGHeroInstance * source;
  21. public:
  22. ExchangeAction(const CGHeroInstance * target, const CGHeroInstance * source)
  23. :target(target), source(source)
  24. { }
  25. virtual Goals::TSubgoal whatToDo(const HeroPtr & hero) const override
  26. {
  27. return Goals::sptr(Goals::VisitHero(target->id.getNum()).sethero(hero));
  28. }
  29. };
  30. ChainActor::ChainActor(const CGHeroInstance * hero, int chainMask)
  31. :hero(hero), isMovable(true), chainMask(chainMask), creatureSet(hero), carrierParent(nullptr), otherParent(nullptr)
  32. {
  33. baseActor = static_cast<HeroActor *>(this);
  34. initialPosition = hero->visitablePos();
  35. layer = hero->boat ? EPathfindingLayer::SAIL : EPathfindingLayer::LAND;
  36. initialMovement = hero->movement;
  37. initialTurn = 0;
  38. armyValue = hero->getTotalStrength();
  39. }
  40. ChainActor::ChainActor(const ChainActor * carrier, const ChainActor * other, const CCreatureSet * heroArmy)
  41. :hero(carrier->hero), isMovable(true), creatureSet(heroArmy), initialPosition(-1),
  42. carrierParent(carrier), otherParent(other), chainMask(carrier->chainMask | other->chainMask)
  43. {
  44. baseActor = static_cast<HeroActor *>(this);
  45. armyValue = heroArmy->getArmyStrength();
  46. }
  47. HeroActor::HeroActor(const CGHeroInstance * hero, int chainMask)
  48. :ChainActor(hero, chainMask)
  49. {
  50. setupSpecialActors();
  51. }
  52. HeroActor::HeroActor(const ChainActor * carrier, const ChainActor * other)
  53. :ChainActor(
  54. carrier,
  55. other,
  56. pickBestCreatures(carrier->creatureSet, other->creatureSet))
  57. {
  58. setupSpecialActors();
  59. exchangeAction.reset(new ExchangeAction(carrier->hero, other->hero));
  60. }
  61. std::shared_ptr<ISpecialAction> ChainActor::getExchangeAction() const
  62. {
  63. return baseActor->exchangeAction;
  64. }
  65. void ChainActor::setBaseActor(HeroActor * base)
  66. {
  67. baseActor = base;
  68. hero = base->hero;
  69. layer = base->layer;
  70. initialMovement = base->initialMovement;
  71. initialTurn = base->initialTurn;
  72. armyValue = base->armyValue;
  73. chainMask = base->chainMask;
  74. creatureSet = base->creatureSet;
  75. }
  76. void HeroActor::setupSpecialActors()
  77. {
  78. auto allActors = std::vector<ChainActor *>{ this };
  79. for(int i = 1; i <= SPECIAL_ACTORS_COUNT; i++)
  80. {
  81. ChainActor & specialActor = specialActors[i - 1];
  82. specialActor.setBaseActor(this);
  83. specialActor.allowBattle = (i & 1) > 0;
  84. specialActor.allowSpellCast = (i & 2) > 0;
  85. specialActor.allowUseResources = (i & 4) > 0;
  86. allActors.push_back(&specialActor);
  87. }
  88. for(int i = 0; i <= SPECIAL_ACTORS_COUNT; i++)
  89. {
  90. ChainActor * actor = allActors[i];
  91. actor->battleActor = allActors[i | 1];
  92. actor->castActor = allActors[i | 2];
  93. actor->resourceActor = allActors[i | 4];
  94. }
  95. }
  96. ChainActor * ChainActor::exchange(const ChainActor * other) const
  97. {
  98. return baseActor->exchange(this, other);
  99. }
  100. bool ChainActor::canExchange(const ChainActor * other) const
  101. {
  102. return baseActor->canExchange(other->baseActor);
  103. }
  104. namespace vstd
  105. {
  106. template <class M, class Key, class F>
  107. typename M::mapped_type & getOrCompute(M &m, Key const& k, F f)
  108. {
  109. typedef typename M::mapped_type V;
  110. std::pair<typename M::iterator, bool> r = m.insert(typename M::value_type(k, V()));
  111. V &v = r.first->second;
  112. if(r.second)
  113. f(v);
  114. return v;
  115. }
  116. }
  117. bool HeroActor::canExchange(const HeroActor * other)
  118. {
  119. return vstd::getOrCompute(canExchangeCache, other, [&](bool & result) {
  120. result = (chainMask & other->chainMask) == 0
  121. && howManyReinforcementsCanGet(creatureSet, other->creatureSet) > armyValue / 10;
  122. });
  123. }
  124. ChainActor * HeroActor::exchange(const ChainActor * specialActor, const ChainActor * other)
  125. {
  126. HeroActor * result;
  127. const HeroActor * otherBase = other->getBaseActor();
  128. if(vstd::contains(exchangeMap, otherBase))
  129. result = exchangeMap.at(otherBase);
  130. else
  131. {
  132. // TODO: decide where to release this CCreatureSet and HeroActor. Probably custom ~ctor?
  133. result = new HeroActor(specialActor, other);
  134. exchangeMap[otherBase] = result;
  135. }
  136. if(specialActor == this)
  137. return result;
  138. int index = vstd::find_pos_if(specialActors, [specialActor](const ChainActor & actor) -> bool {
  139. return &actor == specialActor;
  140. });
  141. return &result->specialActors[index];
  142. }
  143. CCreatureSet * HeroActor::pickBestCreatures(const CCreatureSet * army1, const CCreatureSet * army2) const
  144. {
  145. CCreatureSet * target = new CCreatureSet();
  146. const CCreatureSet * armies[] = { army1, army2 };
  147. //we calculate total strength for each creature type available in armies
  148. std::map<const CCreature *, int> creToPower;
  149. for(auto armyPtr : armies)
  150. {
  151. for(auto & i : armyPtr->Slots())
  152. {
  153. creToPower[i.second->type] += i.second->getPower();
  154. }
  155. }
  156. //TODO - consider more than just power (ie morale penalty, hero specialty in certain stacks, etc)
  157. int armySize = creToPower.size();
  158. vstd::amin(armySize, GameConstants::ARMY_SIZE);
  159. for(int i = 0; i < armySize && !creToPower.empty(); i++) //pick the creatures from which we can get most power, as many as dest can fit
  160. {
  161. typedef const std::pair<const CCreature *, int> & CrePowerPair;
  162. auto creIt = boost::max_element(creToPower, [](CrePowerPair lhs, CrePowerPair rhs)
  163. {
  164. return lhs.second < rhs.second;
  165. });
  166. target->addToSlot(SlotID(i), creIt->first->idNumber, TQuantity(creIt->second));
  167. creToPower.erase(creIt);
  168. }
  169. return target;
  170. }