CArmedInstance.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. * CArmedInstance.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 "CArmedInstance.h"
  12. #include "../CTownHandler.h"
  13. #include "../CCreatureHandler.h"
  14. #include "../CGeneralTextHandler.h"
  15. #include "../CGameState.h"
  16. #include "../CPlayerState.h"
  17. void CArmedInstance::randomizeArmy(int type)
  18. {
  19. for (auto & elem : stacks)
  20. {
  21. int & randID = elem.second->idRand;
  22. if(randID >= 0)
  23. {
  24. int level = randID / 2;
  25. bool upgrade = randID % 2;
  26. elem.second->setType((*VLC->townh)[type]->town->creatures[level][upgrade]);
  27. randID = -1;
  28. }
  29. assert(elem.second->valid(false));
  30. assert(elem.second->armyObj == this);
  31. }
  32. return;
  33. }
  34. // Take Angelic Alliance troop-mixing freedom of non-evil units into account.
  35. CSelector CArmedInstance::nonEvilAlignmentMixSelector = Selector::type()(Bonus::NONEVIL_ALIGNMENT_MIX);
  36. CArmedInstance::CArmedInstance()
  37. :CArmedInstance(false)
  38. {
  39. }
  40. CArmedInstance::CArmedInstance(bool isHypotetic)
  41. :CBonusSystemNode(isHypotetic), nonEvilAlignmentMix(this, nonEvilAlignmentMixSelector)
  42. {
  43. battle = nullptr;
  44. }
  45. void CArmedInstance::updateMoraleBonusFromArmy()
  46. {
  47. if(!validTypes(false)) //object not randomized, don't bother
  48. return;
  49. auto b = getExportedBonusList().getFirst(Selector::sourceType()(Bonus::ARMY).And(Selector::type()(Bonus::MORALE)));
  50. if(!b)
  51. {
  52. b = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, 0, -1);
  53. addNewBonus(b);
  54. }
  55. //number of alignments and presence of undead
  56. std::set<TFaction> factions;
  57. bool hasUndead = false;
  58. const std::string undeadCacheKey = "type_UNDEAD";
  59. static const CSelector undeadSelector = Selector::type()(Bonus::UNDEAD);
  60. for(auto slot : Slots())
  61. {
  62. const CStackInstance * inst = slot.second;
  63. const CCreature * creature = VLC->creh->objects[inst->getCreatureID()];
  64. factions.insert(creature->faction);
  65. // Check for undead flag instead of faction (undead mummies are neutral)
  66. hasUndead |= inst->hasBonus(undeadSelector, undeadCacheKey);
  67. }
  68. size_t factionsInArmy = factions.size(); //town garrison seems to take both sets into account
  69. if (nonEvilAlignmentMix.getHasBonus())
  70. {
  71. size_t mixableFactions = 0;
  72. for(TFaction f : factions)
  73. {
  74. if ((*VLC->townh)[f]->alignment != EAlignment::EVIL)
  75. mixableFactions++;
  76. }
  77. if (mixableFactions > 0)
  78. factionsInArmy -= mixableFactions - 1;
  79. }
  80. std::string description;
  81. if(factionsInArmy == 1)
  82. {
  83. b->val = +1;
  84. description = VLC->generaltexth->arraytxt[115]; //All troops of one alignment +1
  85. description = description.substr(0, description.size()-3);//trim "+1"
  86. }
  87. else if (!factions.empty()) // no bonus from empty garrison
  88. {
  89. b->val = 2 - (si32)factionsInArmy;
  90. description = boost::str(boost::format(VLC->generaltexth->arraytxt[114]) % factionsInArmy % b->val); //Troops of %d alignments %d
  91. description = b->description.substr(0, description.size()-2);//trim value
  92. }
  93. boost::algorithm::trim(description);
  94. b->description = description;
  95. CBonusSystemNode::treeHasChanged();
  96. //-1 modifier for any Undead unit in army
  97. const ui8 UNDEAD_MODIFIER_ID = -2;
  98. auto undeadModifier = getExportedBonusList().getFirst(Selector::source(Bonus::ARMY, UNDEAD_MODIFIER_ID));
  99. if(hasUndead)
  100. {
  101. if(!undeadModifier)
  102. {
  103. undeadModifier = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, -1, UNDEAD_MODIFIER_ID, VLC->generaltexth->arraytxt[116]);
  104. undeadModifier->description = undeadModifier->description.substr(0, undeadModifier->description.size()-2);//trim value
  105. addNewBonus(undeadModifier);
  106. }
  107. }
  108. else if(undeadModifier)
  109. removeBonus(undeadModifier);
  110. }
  111. void CArmedInstance::armyChanged()
  112. {
  113. updateMoraleBonusFromArmy();
  114. }
  115. CBonusSystemNode * CArmedInstance::whereShouldBeAttached(CGameState *gs)
  116. {
  117. if(tempOwner < PlayerColor::PLAYER_LIMIT)
  118. return gs->getPlayerState(tempOwner);
  119. else
  120. return &gs->globalEffects;
  121. }
  122. CBonusSystemNode * CArmedInstance::whatShouldBeAttached()
  123. {
  124. return this;
  125. }