CGPandoraBox.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*
  2. * CGPandoraBox.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 "CGPandoraBox.h"
  12. #include <vcmi/spells/Spell.h>
  13. #include <vcmi/spells/Service.h>
  14. #include "../NetPacks.h"
  15. #include "../CSoundBase.h"
  16. #include "../CSkillHandler.h"
  17. #include "../StartInfo.h"
  18. #include "../IGameCallback.h"
  19. #include "../constants/StringConstants.h"
  20. #include "../serializer/JsonSerializeFormat.h"
  21. VCMI_LIB_NAMESPACE_BEGIN
  22. void CGPandoraBox::init()
  23. {
  24. blockVisit = true;
  25. for(auto & i : configuration.info)
  26. i.reward.removeObject = true;
  27. }
  28. void CGPandoraBox::initObj(CRandomGenerator & rand)
  29. {
  30. init();
  31. CRewardableObject::initObj(rand);
  32. }
  33. void CGPandoraBox::onHeroVisit(const CGHeroInstance * h) const
  34. {
  35. auto setText = [](MetaString & text, int tId, const CGHeroInstance * h)
  36. {
  37. text.appendLocalString(EMetaText::ADVOB_TXT, tId);
  38. text.replaceRawString(h->getNameTranslated());
  39. };
  40. for(auto i : getAvailableRewards(h, Rewardable::EEventType::EVENT_FIRST_VISIT))
  41. {
  42. MetaString txt;
  43. auto & r = configuration.info[i];
  44. if(r.reward.spells.size() == 1)
  45. setText(txt, 184, h);
  46. else if(!r.reward.spells.empty())
  47. setText(txt, 188, h);
  48. if(r.reward.heroExperience || !r.reward.secondary.empty())
  49. setText(txt, 175, h);
  50. for(int ps : r.reward.primary)
  51. {
  52. if(ps)
  53. {
  54. setText(txt, 175, h);
  55. break;
  56. }
  57. }
  58. if(r.reward.manaDiff < 0)
  59. setText(txt, 176, h);
  60. if(r.reward.manaDiff > 0)
  61. setText(txt, 177, h);
  62. for(auto b : r.reward.bonuses)
  63. {
  64. if(b.type == BonusType::MORALE)
  65. {
  66. if(b.val < 0)
  67. setText(txt, 178, h);
  68. if(b.val > 0)
  69. setText(txt, 179, h);
  70. }
  71. if(b.type == BonusType::LUCK)
  72. {
  73. if(b.val < 0)
  74. setText(txt, 180, h);
  75. if(b.val > 0)
  76. setText(txt, 181, h);
  77. }
  78. }
  79. for(auto res : r.reward.resources)
  80. {
  81. if(res < 0)
  82. setText(txt, 182, h);
  83. if(res > 0)
  84. setText(txt, 183, h);
  85. }
  86. if(!r.reward.artifacts.empty())
  87. setText(txt, 183, h);
  88. if(!r.reward.creatures.empty())
  89. {
  90. MetaString loot;
  91. for(auto c : r.reward.creatures)
  92. {
  93. loot.appendRawString("%s");
  94. loot.replaceCreatureName(c);
  95. }
  96. if(r.reward.creatures.size() == 1 && r.reward.creatures[0].count == 1)
  97. txt.appendLocalString(EMetaText::ADVOB_TXT, 185);
  98. else
  99. txt.appendLocalString(EMetaText::ADVOB_TXT, 186);
  100. txt.replaceRawString(loot.buildList());
  101. txt.replaceRawString(h->getNameTranslated());
  102. }
  103. const_cast<MetaString&>(r.message) = txt;
  104. }
  105. BlockingDialog bd (true, false);
  106. bd.player = h->getOwner();
  107. bd.text.appendLocalString(EMetaText::ADVOB_TXT, 14);
  108. cb->showBlockingDialog(&bd);
  109. }
  110. void CGPandoraBox::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
  111. {
  112. if(result.winner == 0)
  113. {
  114. CRewardableObject::onHeroVisit(hero);
  115. }
  116. }
  117. void CGPandoraBox::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
  118. {
  119. if(answer)
  120. {
  121. if(stacksCount() > 0) //if pandora's box is protected by army
  122. {
  123. hero->showInfoDialog(16, 0, EInfoWindowMode::MODAL);
  124. cb->startBattleI(hero, this); //grants things after battle
  125. }
  126. else if(getAvailableRewards(hero, Rewardable::EEventType::EVENT_FIRST_VISIT).empty())
  127. {
  128. hero->showInfoDialog(15);
  129. cb->removeObject(this);
  130. }
  131. else //if it gives something without battle
  132. {
  133. CRewardableObject::onHeroVisit(hero);
  134. }
  135. }
  136. }
  137. void CGPandoraBox::serializeJsonOptions(JsonSerializeFormat & handler)
  138. {
  139. CRewardableObject::serializeJsonOptions(handler);
  140. handler.serializeString("guardMessage", message);
  141. if(!handler.saving)
  142. {
  143. //backward compatibility
  144. CCreatureSet::serializeJson(handler, "guards", 7);
  145. Rewardable::VisitInfo vinfo;
  146. vinfo.visitType = Rewardable::EEventType::EVENT_FIRST_VISIT;
  147. auto & reward = vinfo.reward;
  148. int val;
  149. handler.serializeInt("experience", reward.heroExperience, 0);
  150. handler.serializeInt("mana", reward.manaDiff, 0);
  151. handler.serializeInt("morale", val, 0);
  152. if(val)
  153. reward.bonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::MORALE, BonusSource::OBJECT, val, id);
  154. handler.serializeInt("luck", val, 0);
  155. if(val)
  156. reward.bonuses.emplace_back(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT, val, id);
  157. reward.resources.serializeJson(handler, "resources");
  158. {
  159. auto s = handler.enterStruct("primarySkills");
  160. for(int idx = 0; idx < reward.primary.size(); idx ++)
  161. handler.serializeInt(NPrimarySkill::names[idx], reward.primary[idx], 0);
  162. }
  163. handler.serializeIdArray("artifacts", reward.artifacts);
  164. handler.serializeIdArray("spells", reward.spells);
  165. handler.enterArray("creatures").serializeStruct(reward.creatures);
  166. {
  167. auto s = handler.enterStruct("secondarySkills");
  168. for(const auto & p : handler.getCurrent().Struct())
  169. {
  170. const std::string skillName = p.first;
  171. const std::string levelId = p.second.String();
  172. const int rawId = CSkillHandler::decodeSkill(skillName);
  173. if(rawId < 0)
  174. {
  175. logGlobal->error("Invalid secondary skill %s", skillName);
  176. continue;
  177. }
  178. const int level = vstd::find_pos(NSecondarySkill::levels, levelId);
  179. if(level < 0)
  180. {
  181. logGlobal->error("Invalid secondary skill level %s", levelId);
  182. continue;
  183. }
  184. reward.secondary[rawId] = level;
  185. }
  186. }
  187. configuration.info.push_back(vinfo);
  188. }
  189. }
  190. void CGEvent::init()
  191. {
  192. blockVisit = false;
  193. for(auto & i : configuration.info)
  194. i.reward.removeObject = removeAfterVisit;
  195. }
  196. void CGEvent::onHeroVisit( const CGHeroInstance * h ) const
  197. {
  198. if(availableFor.count(h->tempOwner) == 0)
  199. return;
  200. if(cb->getPlayerSettings(h->tempOwner)->isControlledByHuman())
  201. {
  202. if(humanActivate)
  203. activated(h);
  204. }
  205. else if(computerActivate)
  206. activated(h);
  207. }
  208. void CGEvent::activated( const CGHeroInstance * h ) const
  209. {
  210. if(stacksCount() > 0)
  211. {
  212. InfoWindow iw;
  213. iw.player = h->tempOwner;
  214. if(!message.empty())
  215. iw.text.appendRawString(message);
  216. else
  217. iw.text.appendLocalString(EMetaText::ADVOB_TXT, 16);
  218. cb->showInfoDialog(&iw);
  219. cb->startBattleI(h, this);
  220. }
  221. else
  222. {
  223. CRewardableObject::onHeroVisit(h);
  224. }
  225. }
  226. void CGEvent::serializeJsonOptions(JsonSerializeFormat & handler)
  227. {
  228. CGPandoraBox::serializeJsonOptions(handler);
  229. handler.serializeBool("aIActivable", computerActivate, false);
  230. handler.serializeBool("humanActivable", humanActivate, true);
  231. handler.serializeBool("removeAfterVisit", removeAfterVisit, false);
  232. handler.serializeIdArray("availableFor", availableFor);
  233. }
  234. VCMI_LIB_NAMESPACE_END