CCreatureSet.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. #define VCMI_DLL
  2. #include "CCreatureSet.h"
  3. #include "../hch/CCreatureHandler.h"
  4. #include "VCMI_Lib.h"
  5. #include <assert.h>
  6. #include "../hch/CObjectHandler.h"
  7. #include "IGameCallback.h"
  8. #include "CGameState.h"
  9. #include "../hch/CGeneralTextHandler.h"
  10. #include "../hch/CSpellHandler.h"
  11. #include <boost/lexical_cast.hpp>
  12. #include <boost/algorithm/string/replace.hpp>
  13. const CStackInstance CCreatureSet::operator[](TSlot slot) const
  14. {
  15. TSlots::const_iterator i = slots.find(slot);
  16. if (i != slots.end())
  17. return i->second;
  18. else
  19. throw std::string("That slot is empty!");
  20. }
  21. const CCreature* CCreatureSet::getCreature(TSlot slot) const /*workaround of map issue */
  22. {
  23. TSlots::const_iterator i = slots.find(slot);
  24. if (i != slots.end())
  25. return i->second.type;
  26. else
  27. return NULL;
  28. }
  29. bool CCreatureSet::setCreature(TSlot slot, TCreature type, TQuantity quantity) /*slots 0 to 6 */
  30. {
  31. slots[slot] = CStackInstance(type, quantity); //brutal force
  32. if (quantity == 0)
  33. slots.erase(slot);
  34. if (slots.size() > ARMY_SIZE)
  35. return false;
  36. else
  37. return true;
  38. }
  39. TSlot CCreatureSet::getSlotFor(TCreature creature, ui32 slotsAmount/*=7*/) const /*returns -1 if no slot available */
  40. {
  41. for(TSlots::const_iterator i=slots.begin(); i!=slots.end(); ++i)
  42. {
  43. if(i->second.type->idNumber == creature)
  44. {
  45. return i->first; //if there is already such creature we return its slot id
  46. }
  47. }
  48. for(ui32 i=0; i<slotsAmount; i++)
  49. {
  50. if(slots.find(i) == slots.end())
  51. {
  52. return i; //return first free slot
  53. }
  54. }
  55. return -1; //no slot available
  56. }
  57. int CCreatureSet::getAmount(TSlot slot) const
  58. {
  59. TSlots::const_iterator i = slots.find(slot);
  60. if (i != slots.end())
  61. return i->second.count;
  62. else
  63. return 0; //TODO? consider issuing a warning
  64. }
  65. bool CCreatureSet::mergableStacks(std::pair<TSlot, TSlot> &out, TSlot preferable /*= -1*/) const /*looks for two same stacks, returns slot positions */
  66. {
  67. //try to match creature to our preferred stack
  68. if(preferable >= 0 && vstd::contains(slots, preferable))
  69. {
  70. const CCreature *cr = slots.find(preferable)->second.type;
  71. for(TSlots::const_iterator j=slots.begin(); j!=slots.end(); ++j)
  72. {
  73. if(cr == j->second.type && j->first != preferable)
  74. {
  75. out.first = preferable;
  76. out.second = j->first;
  77. return true;
  78. }
  79. }
  80. }
  81. for(TSlots::const_iterator i=slots.begin(); i!=slots.end(); ++i)
  82. {
  83. for(TSlots::const_iterator j=slots.begin(); j!=slots.end(); ++j)
  84. {
  85. if(i->second.type == j->second.type && i->first != j->first)
  86. {
  87. out.first = i->first;
  88. out.second = j->first;
  89. return true;
  90. }
  91. }
  92. }
  93. return false;
  94. }
  95. void CCreatureSet::sweep()
  96. {
  97. for(TSlots::iterator i=slots.begin(); i!=slots.end(); ++i)
  98. {
  99. if(!i->second.count)
  100. {
  101. slots.erase(i);
  102. sweep();
  103. break;
  104. }
  105. }
  106. }
  107. void CCreatureSet::addToSlot(TSlot slot, TCreature cre, TQuantity count, bool allowMerging/* = true*/)
  108. {
  109. assert(slot >= 0);
  110. const CCreature *c = VLC->creh->creatures[cre];
  111. assert(!vstd::contains(slots, slot) || (slots[slot].type == c && allowMerging)); //that slot was empty or contained same type creature
  112. slots[slot].type = c;
  113. slots[slot].count += count;
  114. //TODO
  115. const CArmedInstance *armedObj = dynamic_cast<const CArmedInstance *>(this);
  116. if(armedObj && !slots[slot].armyObj)
  117. slots[slot].armyObj = armedObj;
  118. }
  119. void CCreatureSet::addToSlot(TSlot slot, const CStackInstance &stack, bool allowMerging/* = true*/)
  120. {
  121. assert(stack.type == VLC->creh->creatures[stack.type->idNumber]);
  122. addToSlot(slot, stack.type->idNumber, stack.count, allowMerging );
  123. }
  124. bool CCreatureSet::validTypes(bool allowUnrandomized /*= false*/) const
  125. {
  126. for(TSlots::const_iterator i=slots.begin(); i!=slots.end(); ++i)
  127. {
  128. bool isRand = (i->second.idRand != -1);
  129. if(!isRand)
  130. {
  131. assert(i->second.type);
  132. assert(i->second.type == VLC->creh->creatures[i->second.type->idNumber]);
  133. }
  134. else
  135. assert(allowUnrandomized);
  136. }
  137. return true;
  138. }
  139. bool CCreatureSet::slotEmpty(TSlot slot) const
  140. {
  141. return !vstd::contains(slots, slot);
  142. }
  143. bool CCreatureSet::needsLastStack() const
  144. {
  145. return false;
  146. }
  147. int CCreatureSet::getArmyStrength() const
  148. {
  149. int ret = 0;
  150. for(TSlots::const_iterator i = slots.begin(); i != slots.end(); i++)
  151. ret += i->second.type->AIValue * i->second.count;
  152. return ret;
  153. }
  154. ui64 CCreatureSet::getPower (TSlot slot) const
  155. {
  156. return getCreature(slot)->AIValue * getAmount(slot);
  157. }
  158. std::string CCreatureSet::getRoughAmount (TSlot slot) const
  159. {
  160. return VLC->generaltexth->arraytxt[174 + 3*CCreature::getQuantityID(getAmount(slot))];
  161. }
  162. int CCreatureSet::stacksCount() const
  163. {
  164. return slots.size();
  165. }
  166. void CCreatureSet::addStack(TSlot slot, const CStackInstance &stack)
  167. {
  168. addToSlot(slot, stack, false);
  169. }
  170. void CCreatureSet::setFormation(bool tight)
  171. {
  172. formation = tight;
  173. }
  174. void CCreatureSet::setStackCount(TSlot slot, TQuantity count)
  175. {
  176. assert(vstd::contains(slots, slot));
  177. assert(count > 0);
  178. slots[slot].count = count;
  179. }
  180. void CCreatureSet::clear()
  181. {
  182. slots.clear();
  183. }
  184. const CStackInstance& CCreatureSet::getStack(TSlot slot) const
  185. {
  186. assert(vstd::contains(slots, slot));
  187. return slots.find(slot)->second;
  188. }
  189. void CCreatureSet::eraseStack(TSlot slot)
  190. {
  191. assert(vstd::contains(slots, slot));
  192. slots.erase(slot);
  193. }
  194. bool CCreatureSet::contains(const CStackInstance *stack) const
  195. {
  196. if(!stack)
  197. return false;
  198. for(TSlots::const_iterator i = slots.begin(); i != slots.end(); ++i)
  199. if(&i->second == stack)
  200. return true;
  201. return false;
  202. }
  203. CStackInstance::CStackInstance()
  204. {
  205. init();
  206. }
  207. CStackInstance::CStackInstance(TCreature id, TQuantity Count, const CArmedInstance *ArmyObj)
  208. {
  209. init();
  210. setType(id);
  211. count = Count;
  212. armyObj = ArmyObj;
  213. }
  214. CStackInstance::CStackInstance(const CCreature *cre, TQuantity Count)
  215. {
  216. init();
  217. type = cre;
  218. count = Count;
  219. }
  220. void CStackInstance::init()
  221. {
  222. experience = 0;
  223. count = 0;
  224. type = NULL;
  225. idRand = -1;
  226. armyObj = NULL;
  227. nodeType = STACK;
  228. }
  229. int CStackInstance::getQuantityID() const
  230. {
  231. return CCreature::getQuantityID(count);
  232. }
  233. void CStackInstance::setType(int creID)
  234. {
  235. type = VLC->creh->creatures[creID];
  236. }
  237. void CStackInstance::getParents(TCNodes &out, const CBonusSystemNode *source /*= NULL*/) const
  238. {
  239. out.insert(type);
  240. if(source && source != this) //we should be root, if not - do not inherit anything
  241. return;
  242. if(armyObj)
  243. out.insert(armyObj);
  244. else
  245. out.insert(&IObjectInterface::cb->gameState()->globalEffects);
  246. }
  247. std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
  248. {
  249. std::map<TBonusType, std::pair<std::string, std::string>>::iterator it = VLC->creh->stackBonuses.find(bonus->type);
  250. if (it != VLC->creh->stackBonuses.end())
  251. {
  252. std::string text;
  253. if (description) //long ability description
  254. {
  255. text = it->second.second;
  256. switch (bonus->type)
  257. {
  258. //no additional modifiers needed
  259. case Bonus::FLYING:
  260. case Bonus::UNLIMITED_RETALIATIONS:
  261. case Bonus::SHOOTER:
  262. case Bonus::FREE_SHOOTING:
  263. case Bonus::NO_SHOTING_PENALTY:
  264. case Bonus::NO_MELEE_PENALTY:
  265. case Bonus::NO_DISTANCE_PENALTY:
  266. case Bonus::NO_OBSTACLES_PENALTY:
  267. case Bonus::JOUSTING: //TODO: percent bonus?
  268. case Bonus::RETURN_AFTER_STRIKE:
  269. case Bonus::BLOCKS_RETALIATION:
  270. case Bonus::TWO_HEX_ATTACK_BREATH:
  271. case Bonus::THREE_HEADED_ATTACK:
  272. case Bonus::ATTACKS_ALL_ADJACENT:
  273. case Bonus::FULL_HP_REGENERATION:
  274. case Bonus::LIFE_DRAIN: //TODO: chance, hp percentage?
  275. case Bonus::SELF_MORALE:
  276. case Bonus::SELF_LUCK:
  277. case Bonus::FEAR:
  278. case Bonus::FEARLESS:
  279. case Bonus::CHARGE_IMMUNITY:
  280. case Bonus::HEALER:
  281. case Bonus::CATAPULT:
  282. case Bonus::DRAGON_NATURE:
  283. case Bonus::NON_LIVING:
  284. case Bonus::UNDEAD:
  285. break;
  286. //One numeric value
  287. //case Bonus::STACKS_SPEED: //Do we need description for creature stats?
  288. //case Bonus::STACK_HEALTH:
  289. case Bonus::MAGIC_RESISTANCE:
  290. case Bonus::SPELL_DAMAGE_REDUCTION:
  291. case Bonus::LEVEL_SPELL_IMMUNITY:
  292. case Bonus::CHANGES_SPELL_COST_FOR_ALLY:
  293. case Bonus::CHANGES_SPELL_COST_FOR_ENEMY:
  294. case Bonus::MANA_CHANNELING:
  295. case Bonus::MANA_DRAIN:
  296. case Bonus::HP_REGENERATION:
  297. case Bonus::ADDITIONAL_RETALIATION:
  298. case Bonus::DOUBLE_DAMAGE_CHANCE:
  299. case Bonus::ENEMY_DEFENCE_REDUCTION:
  300. case Bonus::MAGIC_MIRROR:
  301. case Bonus::DARKNESS: //Darkness Dragons any1?
  302. boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bonus->val));
  303. break;
  304. //Complex descriptions
  305. case Bonus::HATE: //TODO: customize damage percent
  306. boost::algorithm::replace_first(text, "%s", VLC->creh->creatures[bonus->subtype]->namePl);
  307. break;
  308. case Bonus::SPELL_IMMUNITY:
  309. boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype].name);
  310. break;
  311. case Bonus::SPELL_AFTER_ATTACK:
  312. boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bonus->additionalInfo % 100));
  313. boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype].name);
  314. break;
  315. default:
  316. {}//TODO: allow custom bonus types... someday, somehow
  317. }
  318. }
  319. else //short name
  320. {
  321. text = it->second.first;
  322. switch (bonus->type)
  323. {
  324. case Bonus::HATE:
  325. boost::algorithm::replace_first(text, "%s", VLC->creh->creatures[bonus->subtype]->namePl);
  326. break;
  327. case Bonus::LEVEL_SPELL_IMMUNITY:
  328. boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bonus->val));
  329. break;
  330. case Bonus::SPELL_IMMUNITY:
  331. case Bonus::SPELL_AFTER_ATTACK:
  332. boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype].name);
  333. break;
  334. }
  335. }
  336. return text;
  337. }
  338. else
  339. return "";
  340. }
  341. std::string CStackInstance::getQuantityTXT(bool capitalized /*= true*/) const
  342. {
  343. return VLC->generaltexth->arraytxt[174 + getQuantityID()*3 + 2 - capitalized];
  344. }