CCreatureWindow.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. #include "CCreatureWindow.h"
  2. #include "../lib/CCreatureSet.h"
  3. #include "CGameInfo.h"
  4. #include "../lib/CGeneralTextHandler.h"
  5. #include "../lib/BattleState.h"
  6. #include "../CCallback.h"
  7. #include <SDL.h>
  8. #include "SDL_Extensions.h"
  9. #include "CBitmapHandler.h"
  10. #include "CDefHandler.h"
  11. #include "Graphics.h"
  12. #include "AdventureMapButton.h"
  13. #include "CPlayerInterface.h"
  14. #include "CConfigHandler.h"
  15. #include <boost/algorithm/string/replace.hpp>
  16. #include <boost/assign/std/vector.hpp>
  17. #include <boost/assign/list_of.hpp>
  18. #include <boost/lexical_cast.hpp>
  19. #include <boost/format.hpp>
  20. #include <boost/bind.hpp>
  21. #include <boost/foreach.hpp>
  22. #include <boost/tuple/tuple.hpp>
  23. using namespace CSDL_Ext;
  24. /*
  25. * CCreatureWindow.cpp, part of VCMI engine
  26. *
  27. * Authors: listed in file AUTHORS in main folder
  28. *
  29. * License: GNU General Public License v2.0 or later
  30. * Full text of license available in license.txt file, in main folder
  31. *
  32. */
  33. CCreatureWindow::CCreatureWindow (const CStack &stack, int Type)
  34. : type(Type)
  35. {
  36. OBJ_CONSTRUCTION_CAPTURING_ALL;
  37. init(stack.base, &stack, dynamic_cast<const CGHeroInstance*>(stack.base->armyObj));
  38. }
  39. CCreatureWindow::CCreatureWindow (const CStackInstance &stack, int Type)
  40. : type(Type)
  41. {
  42. OBJ_CONSTRUCTION_CAPTURING_ALL;
  43. init(&stack, &stack, dynamic_cast<const CGHeroInstance*>(stack.armyObj));
  44. }
  45. CCreatureWindow::CCreatureWindow(int Cid, int Type, int creatureCount)
  46. :type(Type)
  47. {
  48. OBJ_CONSTRUCTION_CAPTURING_ALL;
  49. CStackInstance * stack = new CStackInstance(Cid, creatureCount); //TODO: simplify?
  50. init(stack, CGI->creh->creatures[Cid], NULL);
  51. delete stack;
  52. }
  53. void CCreatureWindow::init(const CStackInstance *stack, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner)
  54. {
  55. c = stack->type;
  56. if(!stackNode) stackNode = c;
  57. //Basic graphics - need to calculate size
  58. CBonusSystemNode node = CBonusSystemNode() ;
  59. node.bonuses = stackNode->getBonuses(Selector::durationType(Bonus::PERMANENT));
  60. BonusList bl;
  61. while (node.bonuses.size())
  62. {
  63. Bonus * b = node.bonuses.front();
  64. bl.push_back (new Bonus(*b));
  65. bl.back()->val = node.valOfBonuses(Selector::typeSybtype(b->type, b->subtype)); //merge multiple bonuses into one
  66. node.bonuses.remove_if (Selector::typeSybtype(b->type, b->subtype)); //remove used bonuses
  67. }
  68. typedef boost::tuple<std::string,std::string, std::string> skillLine; //jeez
  69. std::vector<skillLine> descriptions; //quick, yet slow solution
  70. std::string text, text2, bonusGfx;
  71. BOOST_FOREACH(Bonus* b, bl)
  72. {
  73. text = stack->bonusToString(b, false);
  74. if (text.size())
  75. {
  76. text2 = stack->bonusToString(b, true);
  77. bonusGfx = stack->bonusToGraphics(b); // may be empty
  78. descriptions.push_back(boost::tuple<std::string,std::string, std::string>(text, text2, bonusGfx));
  79. }
  80. }
  81. int bonusRows = std::min ((int)((descriptions.size() + 1) / 2), (conf.cc.resy - 230) / 60);
  82. amin(bonusRows, 4);
  83. amax(bonusRows, 1);
  84. //TODO: Scroll them
  85. bitmap = new CPicture("CreWin" + boost::lexical_cast<std::string>(bonusRows) + ".pcx"); //1 to 4 rows for now
  86. bitmap->colorizeAndConvert(LOCPLINT->playerID);
  87. pos = bitmap->center();
  88. //Buttons
  89. ok = new AdventureMapButton("",CGI->generaltexth->zelp[445].second, boost::bind(&CCreatureWindow::close,this), 489, 148, "hsbtns.def", SDLK_RETURN);
  90. if (type <= BATTLE) //in battle or info window
  91. {
  92. upgrade = NULL;
  93. dismiss = NULL;
  94. }
  95. anim = new CCreaturePic(22, 48, c);
  96. count = boost::lexical_cast<std::string>(stack->count);
  97. if (count.size()) //TODO
  98. printTo(count, 117, 174, FONT_SMALL, tytulowy,*bitmap);
  99. printAtMiddle(c->namePl, 180, 30, FONT_SMALL, tytulowy,*bitmap); //creature name
  100. //Stats
  101. morale = new MoraleLuckBox(true, genRect(42, 42, 335, 100));
  102. morale->set(stack);
  103. luck = new MoraleLuckBox(false, genRect(42, 42, 387, 100));
  104. luck->set(stack);
  105. printLine(0, CGI->generaltexth->primarySkillNames[0], c->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK));
  106. printLine(1, CGI->generaltexth->primarySkillNames[1], c->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE));
  107. if(c->shots)
  108. printLine(2, CGI->generaltexth->allTexts[198], c->shots);
  109. //TODO
  110. int dmgMultiply = 1;
  111. if(heroOwner && stackNode->hasBonusOfType(Bonus::SIEGE_WEAPON))
  112. dmgMultiply += heroOwner->Attack();
  113. printLine(3, CGI->generaltexth->allTexts[199], stackNode->getMinDamage() * dmgMultiply, stackNode->getMaxDamage() * dmgMultiply, true);
  114. printLine(4, CGI->generaltexth->allTexts[388], c->valOfBonuses(Bonus::STACK_HEALTH), stackNode->valOfBonuses(Bonus::STACK_HEALTH));
  115. printLine(6, CGI->generaltexth->zelp[441].first, c->valOfBonuses(Bonus::STACKS_SPEED), stackNode->valOfBonuses(Bonus::STACKS_SPEED));
  116. new CPicture(graphics->pskillsm->ourImages[4].bitmap, 335, 50, false); //exp icon - Print it always?
  117. if (type) //not in fort window
  118. {
  119. if (STACK_EXP)
  120. {
  121. int rank = std::min(stack->getExpRank(), 10); //hopefully nobody adds more
  122. printAtMiddle("Rank " + boost::lexical_cast<std::string>(stack->getExpRank()), 436, 62, FONT_MEDIUM, tytulowy,*bitmap);
  123. printAtMiddle(boost::lexical_cast<std::string>(stack->experience), 436, 82, FONT_SMALL, zwykly,*bitmap);
  124. if (type > BATTLE) //we need it only on adv. map
  125. {
  126. int tier = stack->type->level;
  127. if (!iswith(tier, 1, 7))
  128. tier = 0;
  129. int number;
  130. std::string expText = CGI->generaltexth->zcrexp[324];
  131. boost::replace_first (expText, "%s", c->namePl);
  132. boost::replace_first (expText, "%s", CGI->generaltexth->zcrexp[rank]);
  133. boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(rank));
  134. boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(stack->experience));
  135. number = CGI->creh->expRanks[tier][rank] - stack->experience;
  136. boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number));
  137. number = CGI->creh->maxExpPerBattle[tier]; //percent
  138. boost::replace_first (expText, "%i%", boost::lexical_cast<std::string>(number));
  139. number *= CGI->creh->expRanks[tier].back() / 100; //actual amount
  140. boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number));
  141. boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(stack->count)); //Number of Creatures in stack
  142. int expmin = std::max(CGI->creh->expRanks[tier][std::max(rank-1, 0)], (ui32)1);
  143. number = (stack->count * (stack->experience - expmin)) / expmin; //Maximum New Recruits without losing current Rank
  144. boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //TODO
  145. boost::replace_first (expText, "%.2f", boost::lexical_cast<std::string>(1)); //TODO Experience Multiplier
  146. number = CGI->creh->expAfterUpgrade;
  147. boost::replace_first (expText, "%.2f", boost::lexical_cast<std::string>(number) + "%"); //Upgrade Multiplier
  148. expmin = CGI->creh->expRanks[tier][9];
  149. int expmax = CGI->creh->expRanks[tier][10];
  150. number = expmax - expmin;
  151. boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number));
  152. number = (stack->count * (expmax - expmin)) / expmin;
  153. boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number));
  154. //» S t a c k E x p e r i e n c e D e t a i l s «
  155. //
  156. //Creature Type ................... : %s
  157. //Experience Rank ................. : %s (%i)
  158. //Experience Points ............... : %i
  159. //Experience Points to Next Rank .. : %i
  160. //Maximum Experience per Battle ... : %i%% (%i)
  161. //Number of Creatures in stack .... : %i
  162. //Maximum New Recruits
  163. // without losing current Rank .... : %i
  164. //Experience Multiplier ........... : %.2f
  165. //Upgrade Multiplier .............. : %.2f
  166. //Experience after Rank 10 ........ : %i
  167. //Maximum New Recruits to remain at
  168. // Rank 10 if at Maximum Experience : %i
  169. expArea = new LRClickableAreaWText(Rect(334, 49, 160, 44), "" , expText );
  170. }
  171. }
  172. if (STACK_ARTIFACT && type > BATTLE)
  173. {
  174. //SDL_Rect rect = genRect(44,44,465,98);
  175. //creatureArtifact = new CArtPlace(NULL);
  176. //creatureArtifact->pos = rect;
  177. //creatureArtifact->ourOwner = NULL; //hmm?
  178. leftArtRoll = new AdventureMapButton(std::string(), std::string(), boost::bind (&CCreatureWindow::scrollArt, this, -1), 437, 98, "hsbtns3.def", SDLK_LEFT);
  179. rightArtRoll = new AdventureMapButton(std::string(), std::string(), boost::bind (&CCreatureWindow::scrollArt, this, +1), 516, 98, "hsbtns5.def", SDLK_RIGHT);
  180. }
  181. else
  182. creatureArtifact = NULL;
  183. }
  184. if(const CStack *battleStack = dynamic_cast<const CStack*>(stackNode)) //only during battle
  185. {
  186. //spell effects
  187. int printed=0; //how many effect pics have been printed
  188. std::vector<si32> spells = battleStack->activeSpells();
  189. BOOST_FOREACH(si32 effect, spells)
  190. {
  191. blitAt(graphics->spellEffectsPics->ourImages[effect + 1].bitmap, 20 + 52 * printed, 184, *bitmap);
  192. if (++printed >= 10) //we can fit only 10 effects
  193. break;
  194. }
  195. //print current health
  196. printLine (5, CGI->generaltexth->allTexts[200], battleStack->firstHPleft);
  197. }
  198. //All bonuses - abilities
  199. int i = 0, j = 0;
  200. std::string gfxName;
  201. BOOST_FOREACH(skillLine p, descriptions)
  202. {
  203. int offsetx = 257*j;
  204. int offsety = 60*i + (bonusRows > 1 ? 1 : 0); //lack of precision :<
  205. printAt(p.get<0>(), 84 + offsetx, 238 + offsety, FONT_SMALL, tytulowy, *bitmap);
  206. printAt(p.get<1>(), 84 + offsetx, 258 + offsety, FONT_SMALL, zwykly, *bitmap);
  207. gfxName = p.get<2>();
  208. if (gfxName.size())
  209. {
  210. CPicture * bonusGfx = new CPicture(gfxName, 22 + offsetx, 232 + offsety);
  211. bonusGraphics.push_back(bonusGfx);
  212. }
  213. if (++j > 1) //next line
  214. {
  215. ++i;
  216. j = 0;
  217. }
  218. }
  219. //AUIDAT.DEF
  220. }
  221. CCreatureWindow::CCreatureWindow(const CStackInstance &st, int Type, boost::function<void()> Upg, boost::function<void()> Dsm, UpgradeInfo *ui)
  222. : type(Type), dsm(Dsm), dismiss(0), upgrade(0), ok(0)
  223. {
  224. OBJ_CONSTRUCTION_CAPTURING_ALL;
  225. init(&st, &st,dynamic_cast<const CGHeroInstance*>(st.armyObj));
  226. //print abilities text - if r-click popup
  227. if(type)
  228. {
  229. if(Upg && ui)
  230. {
  231. bool enough = true;
  232. for(std::set<std::pair<int,int> >::iterator i=ui->cost[0].begin(); i!=ui->cost[0].end(); i++) //calculate upgrade cost
  233. {
  234. BLOCK_CAPTURING;
  235. if(LOCPLINT->cb->getResourceAmount(i->first) < i->second*st.count)
  236. enough = false;
  237. upgResCost.push_back(new SComponent(SComponent::resource,i->first,i->second*st.count));
  238. }
  239. if(enough)
  240. {
  241. CFunctionList<void()> fs;
  242. fs += Upg;
  243. fs += boost::bind(&CCreatureWindow::close,this);
  244. CFunctionList<void()> cfl;
  245. cfl = boost::bind(&CPlayerInterface::showYesNoDialog, LOCPLINT, CGI->generaltexth->allTexts[207], boost::ref(upgResCost), fs, 0, false);
  246. upgrade = new AdventureMapButton("",CGI->generaltexth->zelp[446].second,cfl,385, 148,"IVIEWCR.DEF",SDLK_u);
  247. }
  248. else
  249. {
  250. upgrade = new AdventureMapButton("",CGI->generaltexth->zelp[446].second,boost::function<void()>(),385, 148,"IVIEWCR.DEF");
  251. upgrade->callback.funcs.clear();
  252. upgrade->setOffset(2);
  253. }
  254. }
  255. if(Dsm)
  256. {
  257. CFunctionList<void()> fs[2];
  258. //on dismiss confirmed
  259. fs[0] += Dsm; //dismiss
  260. fs[0] += boost::bind(&CCreatureWindow::close,this);//close this window
  261. CFunctionList<void()> cfl;
  262. cfl = boost::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],std::vector<SComponent*>(),fs[0],fs[1],false);
  263. dismiss = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,cfl,333, 148,"IVIEWCR2.DEF",SDLK_d);
  264. }
  265. }
  266. }
  267. void CCreatureWindow::printLine(int nr, const std::string &text, int baseVal, int val/*=-1*/, bool range/*=false*/)
  268. {
  269. printAt(text, 162, 48 + nr*19, FONT_SMALL, zwykly, *bitmap);
  270. std::string hlp;
  271. if(range && baseVal != val)
  272. hlp = boost::str(boost::format("%d - %d") % baseVal % val);
  273. else if(baseVal != val && val>=0)
  274. hlp = boost::str(boost::format("%d (%d)") % baseVal % val);
  275. else
  276. hlp = boost::lexical_cast<std::string>(baseVal);
  277. printTo(hlp, 325, 64 + nr*19, FONT_SMALL, zwykly, *bitmap);
  278. }
  279. //void CCreatureWindow::activate()
  280. //{
  281. // CIntObject::activate();
  282. // if(type < 3)
  283. // activateRClick();
  284. //}
  285. void CCreatureWindow::scrollArt(int dir)
  286. {
  287. }
  288. void CCreatureWindow::clickRight(tribool down, bool previousState)
  289. {
  290. if(down)
  291. return;
  292. if (type < 3)
  293. close();
  294. }
  295. void CCreatureWindow::close()
  296. {
  297. GH.popIntTotally(this);
  298. }
  299. CCreatureWindow::~CCreatureWindow()
  300. {
  301. for (int i=0; i<upgResCost.size(); ++i)
  302. delete upgResCost[i];
  303. }