CBattleInterface.cpp 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323
  1. #include "CBattleInterface.h"
  2. #include "CGameInfo.h"
  3. #include "hch/CLodHandler.h"
  4. #include "SDL_Extensions.h"
  5. #include "CAdvmapInterface.h"
  6. #include "AdventureMapButton.h"
  7. #include "hch/CObjectHandler.h"
  8. #include "hch/CHeroHandler.h"
  9. #include "hch/CDefHandler.h"
  10. #include "CCursorHandler.h"
  11. #include "CCallback.h"
  12. #include "CGameState.h"
  13. #include "hch/CGeneralTextHandler.h"
  14. #include "client/CCreatureAnimation.h"
  15. #include "client/Graphics.h"
  16. #include <queue>
  17. #include <sstream>
  18. #include "lib/CondSh.h"
  19. #ifndef __GNUC__
  20. const double M_PI = 3.14159265358979323846;
  21. #else
  22. #define _USE_MATH_DEFINES
  23. #include <cmath>
  24. #endif
  25. extern SDL_Surface * screen;
  26. extern TTF_Font * GEOR13;
  27. extern SDL_Color zwykly;
  28. SDL_Surface * CBattleInterface::cellBorder, * CBattleInterface::cellShade;
  29. CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2)
  30. : printCellBorders(true), attackingHeroInstance(hero1), defendingHeroInstance(hero2), animCount(0), activeStack(-1), givenCommand(NULL), attackingInfo(NULL), myTurn(false)
  31. {
  32. givenCommand = new CondSh<BattleAction *>(NULL);
  33. //initializing armies
  34. this->army1 = army1;
  35. this->army2 = army2;
  36. std::map<int, CStack> stacks = LOCPLINT->cb->battleGetStacks();
  37. for(std::map<int, CStack>::iterator b=stacks.begin(); b!=stacks.end(); ++b)
  38. {
  39. std::pair <int, int> coords = CBattleHex::getXYUnitAnim(b->second.position, b->second.owner == attackingHeroInstance->tempOwner, b->second.creature);
  40. creAnims[b->second.ID] = (new CCreatureAnimation(b->second.creature->animDefName));
  41. creAnims[b->second.ID]->setType(2);
  42. creAnims[b->second.ID]->pos = genRect(creAnims[b->second.ID]->fullHeight, creAnims[b->second.ID]->fullWidth, coords.first, coords.second);
  43. creDir[b->second.ID] = b->second.owner==attackingHeroInstance->tempOwner;
  44. }
  45. //preparing menu background and terrain
  46. std::vector< std::string > & backref = graphics->battleBacks[ LOCPLINT->cb->battleGetBattlefieldType() ];
  47. background = BitmapHandler::loadBitmap(backref[ rand() % backref.size()] );
  48. menu = BitmapHandler::loadBitmap("CBAR.BMP");
  49. graphics->blueToPlayersAdv(menu, hero1->tempOwner);
  50. //preparing graphics for displaying amounts of creatures
  51. amountBasic = BitmapHandler::loadBitmap("CMNUMWIN.BMP");
  52. amountNormal = BitmapHandler::loadBitmap("CMNUMWIN.BMP");
  53. CSDL_Ext::alphaTransform(amountNormal);
  54. for(int g=0; g<amountNormal->format->palette->ncolors; ++g)
  55. {
  56. if((amountNormal->format->palette->colors+g)->b != 132 &&
  57. (amountNormal->format->palette->colors+g)->g != 231 &&
  58. (amountNormal->format->palette->colors+g)->r != 255) //it's not yellow border
  59. {
  60. (amountNormal->format->palette->colors+g)->r = (float)((amountNormal->format->palette->colors+g)->r) * 0.54f;
  61. (amountNormal->format->palette->colors+g)->g = (float)((amountNormal->format->palette->colors+g)->g) * 0.19f;
  62. (amountNormal->format->palette->colors+g)->b = (float)((amountNormal->format->palette->colors+g)->b) * 0.93f;
  63. }
  64. }
  65. ////blitting menu background and terrain
  66. blitAt(background, 0, 0);
  67. blitAt(menu, 0, 556);
  68. CSDL_Ext::update();
  69. //preparing buttons and console
  70. bOptions = new AdventureMapButton (std::string(), std::string(), boost::bind(&CBattleInterface::bOptionsf,this), 3, 561, "icm003.def", false, NULL, false);
  71. bSurrender = new AdventureMapButton (std::string(), std::string(), boost::bind(&CBattleInterface::bSurrenderf,this), 54, 561, "icm001.def", false, NULL, false);
  72. bFlee = new AdventureMapButton (std::string(), std::string(), boost::bind(&CBattleInterface::bFleef,this), 105, 561, "icm002.def", false, NULL, false);
  73. bAutofight = new AdventureMapButton (std::string(), std::string(), boost::bind(&CBattleInterface::bAutofightf,this), 157, 561, "icm004.def", false, NULL, false);
  74. bSpell = new AdventureMapButton (std::string(), std::string(), boost::bind(&CBattleInterface::bSpellf,this), 645, 561, "icm005.def", false, NULL, false);
  75. bWait = new AdventureMapButton (std::string(), std::string(), boost::bind(&CBattleInterface::bWaitf,this), 696, 561, "icm006.def", false, NULL, false);
  76. bDefence = new AdventureMapButton (std::string(), std::string(), boost::bind(&CBattleInterface::bDefencef,this), 747, 561, "icm007.def", false, NULL, false);
  77. bConsoleUp = new AdventureMapButton (std::string(), std::string(), boost::bind(&CBattleInterface::bConsoleUpf,this), 624, 561, "ComSlide.def", false, NULL, false);
  78. bConsoleDown = new AdventureMapButton (std::string(), std::string(), boost::bind(&CBattleInterface::bConsoleDownf,this), 624, 580, "ComSlide.def", false, NULL, false);
  79. bConsoleDown->bitmapOffset = 2;
  80. console = new CBattleConsole();
  81. console->pos.x = 211;
  82. console->pos.y = 560;
  83. console->pos.w = 406;
  84. console->pos.h = 38;
  85. //loading hero animations
  86. if(hero1) // attacking hero
  87. {
  88. attackingHero = new CBattleHero(graphics->battleHeroes[hero1->type->heroType], 0, 0, false, hero1->tempOwner);
  89. attackingHero->pos = genRect(attackingHero->dh->ourImages[0].bitmap->h, attackingHero->dh->ourImages[0].bitmap->w, -40, 0);
  90. }
  91. else
  92. {
  93. attackingHero = NULL;
  94. }
  95. if(hero2) // defending hero
  96. {
  97. defendingHero = new CBattleHero(graphics->battleHeroes[hero2->type->heroType], 0, 0, true, hero2->tempOwner);
  98. defendingHero->pos = genRect(defendingHero->dh->ourImages[0].bitmap->h, defendingHero->dh->ourImages[0].bitmap->w, 690, 0);
  99. }
  100. else
  101. {
  102. defendingHero = NULL;
  103. }
  104. //preparing cells and hexes
  105. cellBorder = BitmapHandler::loadBitmap("CCELLGRD.BMP");
  106. CSDL_Ext::alphaTransform(cellBorder);
  107. cellShade = BitmapHandler::loadBitmap("CCELLSHD.BMP");
  108. CSDL_Ext::alphaTransform(cellShade);
  109. for(int h=0; h<187; ++h)
  110. {
  111. bfield[h].myNumber = h;
  112. int x = 14 + ((h/17)%2==0 ? 22 : 0) + 44*(h%17);
  113. int y = 86 + 42 * (h/17);
  114. bfield[h].pos = genRect(cellShade->h, cellShade->w, x, y);
  115. bfield[h].accesible = true;
  116. bfield[h].myInterface = this;
  117. }
  118. //locking occupied positions on batlefield
  119. for(std::map<int, CStack>::iterator it = stacks.begin(); it!=stacks.end(); ++it) //stacks gained at top of this function
  120. {
  121. bfield[it->second.position].accesible = false;
  122. }
  123. //loading projectiles for units
  124. for(std::map<int, CStack>::iterator g = stacks.begin(); g != stacks.end(); ++g)
  125. {
  126. if(g->second.creature->isShooting() && CGI->creh->idToProjectile[g->second.creature->idNumber] != std::string())
  127. {
  128. idToProjectile[g->second.creature->idNumber] = CDefHandler::giveDef(CGI->creh->idToProjectile[g->second.creature->idNumber]);
  129. if(idToProjectile[g->second.creature->idNumber]->ourImages.size() > 2) //add symmetric images
  130. {
  131. for(int k = idToProjectile[g->second.creature->idNumber]->ourImages.size()-2; k > 1; --k)
  132. {
  133. Cimage ci;
  134. ci.bitmap = CSDL_Ext::rotate01(idToProjectile[g->second.creature->idNumber]->ourImages[k].bitmap);
  135. ci.groupNumber = 0;
  136. ci.imName = std::string();
  137. idToProjectile[g->second.creature->idNumber]->ourImages.push_back(ci);
  138. }
  139. }
  140. for(int s=0; s<idToProjectile[g->second.creature->idNumber]->ourImages.size(); ++s) //alpha transforming
  141. {
  142. CSDL_Ext::alphaTransform(idToProjectile[g->second.creature->idNumber]->ourImages[s].bitmap);
  143. }
  144. }
  145. }
  146. }
  147. CBattleInterface::~CBattleInterface()
  148. {
  149. SDL_FreeSurface(background);
  150. SDL_FreeSurface(menu);
  151. SDL_FreeSurface(amountBasic);
  152. SDL_FreeSurface(amountNormal);
  153. delete bOptions;
  154. delete bSurrender;
  155. delete bFlee;
  156. delete bAutofight;
  157. delete bSpell;
  158. delete bWait;
  159. delete bDefence;
  160. delete bConsoleUp;
  161. delete bConsoleDown;
  162. delete console;
  163. delete givenCommand;
  164. delete attackingHero;
  165. delete defendingHero;
  166. SDL_FreeSurface(cellBorder);
  167. SDL_FreeSurface(cellShade);
  168. for(std::map< int, CCreatureAnimation * >::iterator g=creAnims.begin(); g!=creAnims.end(); ++g)
  169. delete g->second;
  170. for(std::map< int, CDefHandler * >::iterator g=idToProjectile.begin(); g!=idToProjectile.end(); ++g)
  171. delete g->second;
  172. }
  173. void CBattleInterface::activate()
  174. {
  175. subInt = NULL;
  176. bOptions->activate();
  177. bSurrender->activate();
  178. bFlee->activate();
  179. bAutofight->activate();
  180. bSpell->activate();
  181. bWait->activate();
  182. bDefence->activate();
  183. bConsoleUp->activate();
  184. bConsoleDown->activate();
  185. for(int b=0; b<187; ++b)
  186. {
  187. bfield[b].activate();
  188. }
  189. }
  190. void CBattleInterface::deactivate()
  191. {
  192. bOptions->deactivate();
  193. bSurrender->deactivate();
  194. bFlee->deactivate();
  195. bAutofight->deactivate();
  196. bSpell->deactivate();
  197. bWait->deactivate();
  198. bDefence->deactivate();
  199. bConsoleUp->deactivate();
  200. bConsoleDown->deactivate();
  201. for(int b=0; b<187; ++b)
  202. {
  203. bfield[b].deactivate();
  204. }
  205. }
  206. void CBattleInterface::show(SDL_Surface * to)
  207. {
  208. std::map<int, CStack> stacks = LOCPLINT->cb->battleGetStacks(); //used in a few places
  209. ++animCount;
  210. if(!to) //"evaluating" to
  211. to = screen;
  212. //showing background
  213. blitAt(background, 0, 0, to);
  214. if(printCellBorders) //printing cell borders
  215. {
  216. for(int i=0; i<11; ++i) //rows
  217. {
  218. for(int j=0; j<15; ++j) //columns
  219. {
  220. int x = 58 + (i%2==0 ? 22 : 0) + 44*j;
  221. int y = 86 + 42 * i;
  222. CSDL_Ext::blit8bppAlphaTo24bpp(cellBorder, NULL, to, &genRect(cellBorder->h, cellBorder->w, x, y));
  223. }
  224. }
  225. }
  226. //printing hovered cell
  227. for(int b=0; b<187; ++b)
  228. {
  229. if(bfield[b].strictHovered && bfield[b].hovered)
  230. {
  231. int x = 14 + ((b/17)%2==0 ? 22 : 0) + 44*(b%17);
  232. int y = 86 + 42 * (b/17);
  233. CSDL_Ext::blit8bppAlphaTo24bpp(cellShade, NULL, to, &genRect(cellShade->h, cellShade->w, x, y));
  234. }
  235. }
  236. //showing selected unit's range
  237. if(activeStack != -1 && creAnims[activeStack]->getType() != 0) //don't show if unit is moving
  238. {
  239. showRange(to, activeStack);
  240. }
  241. //showing menu background and console
  242. blitAt(menu, 0, 556, to);
  243. console->show(to);
  244. //showing buttons
  245. bOptions->show(to);
  246. bSurrender->show(to);
  247. bFlee->show(to);
  248. bAutofight->show(to);
  249. bSpell->show(to);
  250. bWait->show(to);
  251. bDefence->show(to);
  252. bConsoleUp->show(to);
  253. bConsoleDown->show(to);
  254. //showing hero animations
  255. if(attackingHero)
  256. attackingHero->show(to);
  257. if(defendingHero)
  258. defendingHero->show(to);
  259. ////showing units //a lot of work...
  260. std::vector<int> stackAliveByHex[187];
  261. //double loop because dead stacks should be printed first
  262. for(std::map<int, CStack>::iterator j=stacks.begin(); j!=stacks.end(); ++j)
  263. {
  264. if(j->second.alive)
  265. stackAliveByHex[j->second.position].push_back(j->second.ID);
  266. }
  267. std::vector<int> stackDeadByHex[187];
  268. for(std::map<int, CStack>::iterator j=stacks.begin(); j!=stacks.end(); ++j)
  269. {
  270. if(!j->second.alive)
  271. stackDeadByHex[j->second.position].push_back(j->second.ID);
  272. }
  273. attackingShowHelper(); // handle attack animation
  274. for(int b=0; b<187; ++b) //showing dead stacks
  275. {
  276. for(int v=0; v<stackDeadByHex[b].size(); ++v)
  277. {
  278. creAnims[stackDeadByHex[b][v]]->nextFrame(to, creAnims[stackDeadByHex[b][v]]->pos.x, creAnims[stackDeadByHex[b][v]]->pos.y, creDir[stackDeadByHex[b][v]], (animCount%4==0 || creAnims[stackDeadByHex[b][v]]->getType()!=2) && stacks[stackDeadByHex[b][v]].alive, stackDeadByHex[b][v]==activeStack); //increment always when moving, never if stack died
  279. //printing amount
  280. if(stacks[stackDeadByHex[b][v]].amount > 0) //don't print if stack is not alive
  281. {
  282. int xAdd = stacks[stackDeadByHex[b][v]].attackerOwned ? 220 : 202;
  283. CSDL_Ext::blit8bppAlphaTo24bpp(amountNormal, NULL, to, &genRect(amountNormal->h, amountNormal->w, creAnims[stackDeadByHex[b][v]]->pos.x + xAdd, creAnims[stackDeadByHex[b][v]]->pos.y + 260));
  284. std::stringstream ss;
  285. ss<<stacks[stackDeadByHex[b][v]].amount;
  286. CSDL_Ext::printAtMiddleWB(ss.str(), creAnims[stackDeadByHex[b][v]]->pos.x + xAdd + 14, creAnims[stackDeadByHex[b][v]]->pos.y + 260 + 4, GEOR13, 20, zwykly, to);
  287. }
  288. }
  289. }
  290. for(int b=0; b<187; ++b) //showing alive stacks
  291. {
  292. for(int v=0; v<stackAliveByHex[b].size(); ++v)
  293. {
  294. creAnims[stackAliveByHex[b][v]]->nextFrame(to, creAnims[stackAliveByHex[b][v]]->pos.x, creAnims[stackAliveByHex[b][v]]->pos.y, creDir[stackAliveByHex[b][v]], (animCount%4==0) && stacks[stackAliveByHex[b][v]].alive, stackAliveByHex[b][v]==activeStack); //increment always when moving, never if stack died
  295. //printing amount
  296. if(stacks[stackAliveByHex[b][v]].amount > 0) //don't print if stack is not alive
  297. {
  298. int xAdd = stacks[stackAliveByHex[b][v]].attackerOwned ? 220 : 202;
  299. CSDL_Ext::blit8bppAlphaTo24bpp(amountNormal, NULL, to, &genRect(amountNormal->h, amountNormal->w, creAnims[stackAliveByHex[b][v]]->pos.x + xAdd, creAnims[stackAliveByHex[b][v]]->pos.y + 260));
  300. std::stringstream ss;
  301. ss<<stacks[stackAliveByHex[b][v]].amount;
  302. CSDL_Ext::printAtMiddleWB(ss.str(), creAnims[stackAliveByHex[b][v]]->pos.x + xAdd + 14, creAnims[stackAliveByHex[b][v]]->pos.y + 260 + 4, GEOR13, 20, zwykly, to);
  303. }
  304. }
  305. }
  306. //units shown
  307. projectileShowHelper(to);//showing projectiles
  308. }
  309. bool CBattleInterface::reverseCreature(int number, int hex, bool wideTrick)
  310. {
  311. if(creAnims[number]==NULL)
  312. return false; //there is no such creature
  313. creAnims[number]->setType(8);
  314. for(int g=0; g<creAnims[number]->framesInGroup(8); ++g)
  315. {
  316. show();
  317. CSDL_Ext::update();
  318. SDL_framerateDelay(LOCPLINT->mainFPSmng);
  319. if((animCount+1)%4)
  320. creAnims[number]->incrementFrame();
  321. }
  322. creDir[number] = !creDir[number];
  323. CStack curs = *LOCPLINT->cb->battleGetStackByID(number);
  324. std::pair <int, int> coords = CBattleHex::getXYUnitAnim(hex, creDir[number], curs.creature);
  325. creAnims[number]->pos.x = coords.first;
  326. //creAnims[number]->pos.y = coords.second;
  327. if(wideTrick && curs.creature->isDoubleWide())
  328. {
  329. if(!creDir[number])
  330. creAnims[number]->pos.x -= 44;
  331. }
  332. creAnims[number]->setType(7);
  333. for(int g=0; g<creAnims[number]->framesInGroup(7); ++g)
  334. {
  335. show();
  336. CSDL_Ext::update();
  337. SDL_framerateDelay(LOCPLINT->mainFPSmng);
  338. }
  339. creAnims[number]->setType(2);
  340. return true;
  341. }
  342. void CBattleInterface::bOptionsf()
  343. {
  344. }
  345. void CBattleInterface::bSurrenderf()
  346. {
  347. }
  348. void CBattleInterface::bFleef()
  349. {
  350. giveCommand(4,0,0);
  351. CGI->curh->changeGraphic(0, 0);
  352. }
  353. void CBattleInterface::bAutofightf()
  354. {
  355. }
  356. void CBattleInterface::bSpellf()
  357. {
  358. }
  359. void CBattleInterface::bWaitf()
  360. {
  361. }
  362. void CBattleInterface::bDefencef()
  363. {
  364. giveCommand(3,0,activeStack);
  365. }
  366. void CBattleInterface::bConsoleUpf()
  367. {
  368. console->scrollUp();
  369. }
  370. void CBattleInterface::bConsoleDownf()
  371. {
  372. console->scrollDown();
  373. }
  374. void CBattleInterface::newStack(CStack stack)
  375. {
  376. creAnims[stack.ID] = new CCreatureAnimation(stack.creature->animDefName);
  377. creAnims[stack.ID]->setType(2);
  378. creDir[stack.ID] = stack.owner==attackingHeroInstance->tempOwner;
  379. }
  380. void CBattleInterface::stackRemoved(CStack stack)
  381. {
  382. delete creAnims[stack.ID];
  383. creAnims.erase(stack.ID);
  384. }
  385. void CBattleInterface::stackKilled(int ID, int dmg, int killed, int IDby, bool byShooting)
  386. {
  387. if(creAnims[ID]->getType() != 2)
  388. {
  389. return; //something went wrong
  390. }
  391. if(byShooting) //delay hit animation
  392. {
  393. CStack attacker = *LOCPLINT->cb->battleGetStackByID(IDby);
  394. while(true)
  395. {
  396. bool found = false;
  397. for(std::list<SProjectileInfo>::const_iterator it = projectiles.begin(); it!=projectiles.end(); ++it)
  398. {
  399. if(it->creID == attacker.creature->idNumber)
  400. {
  401. found = true;
  402. break;
  403. }
  404. }
  405. if(!found)
  406. break;
  407. else
  408. {
  409. show();
  410. CSDL_Ext::update();
  411. SDL_framerateDelay(LOCPLINT->mainFPSmng);
  412. }
  413. }
  414. }
  415. creAnims[ID]->setType(5); //death
  416. for(int i=0; i<creAnims[ID]->framesInGroup(5); ++i)
  417. {
  418. if(i)
  419. creAnims[ID]->incrementFrame();
  420. show();
  421. CSDL_Ext::update();
  422. SDL_framerateDelay(LOCPLINT->mainFPSmng);
  423. }
  424. printConsoleAttacked(ID, dmg, killed, IDby);
  425. }
  426. void CBattleInterface::stackActivated(int number)
  427. {
  428. //givenCommand = NULL;
  429. activeStack = number;
  430. shadedHexes = LOCPLINT->cb->battleGetAvailableHexes(number);
  431. myTurn = true;
  432. }
  433. void CBattleInterface::stackMoved(int number, int destHex, bool startMoving, bool endMoving)
  434. {
  435. //a few useful variables
  436. int curStackPos = LOCPLINT->cb->battleGetPos(number);
  437. int steps = creAnims[number]->framesInGroup(0);
  438. int hexWbase = 44, hexHbase = 42;
  439. bool twoTiles = LOCPLINT->cb->battleGetCreature(number).isDoubleWide();
  440. if(startMoving) //animation of starting move
  441. {
  442. deactivate();
  443. CGI->curh->hide();
  444. creAnims[number]->setType(20);
  445. //LOCPLINT->objsToBlit.erase(std::find(LOCPLINT->objsToBlit.begin(),LOCPLINT->objsToBlit.end(),this));
  446. for(int i=0; i<creAnims[number]->framesInGroup(20); ++i)
  447. {
  448. show();
  449. CSDL_Ext::update();
  450. SDL_framerateDelay(LOCPLINT->mainFPSmng);
  451. if((animCount+1)%4)
  452. creAnims[number]->incrementFrame();
  453. }
  454. }
  455. int mutPos = BattleInfo::mutualPosition(curStackPos, destHex);
  456. {
  457. switch(mutPos) //reverse unit if necessary
  458. {
  459. case 0: case 4: case 5:
  460. if(creDir[number] == true)
  461. reverseCreature(number, curStackPos, twoTiles);
  462. break;
  463. case 1: case 2: case 3:
  464. if(creDir[number] == false)
  465. reverseCreature(number, curStackPos, twoTiles);
  466. break;
  467. }
  468. //moving instructions
  469. creAnims[number]->setType(0);
  470. for(int i=0; i<steps; ++i)
  471. {
  472. switch(mutPos)
  473. {
  474. case 0:
  475. creAnims[number]->pos.x -= hexWbase/(2*steps);
  476. creAnims[number]->pos.y -= hexHbase/steps;
  477. break;
  478. case 1:
  479. creAnims[number]->pos.x += hexWbase/(2*steps);
  480. creAnims[number]->pos.y -= hexHbase/steps;
  481. break;
  482. case 2:
  483. creAnims[number]->pos.x += hexWbase/steps;
  484. break;
  485. case 3:
  486. creAnims[number]->pos.x += hexWbase/(2*steps);
  487. creAnims[number]->pos.y += hexHbase/steps;
  488. break;
  489. case 4:
  490. creAnims[number]->pos.x -= hexWbase/(2*steps);
  491. creAnims[number]->pos.y += hexHbase/steps;
  492. break;
  493. case 5:
  494. creAnims[number]->pos.x -= hexWbase/steps;
  495. break;
  496. }
  497. show();
  498. CSDL_Ext::update();
  499. SDL_framerateDelay(LOCPLINT->mainFPSmng);
  500. if((animCount+1)%4)
  501. creAnims[number]->incrementFrame();
  502. }
  503. }
  504. if(endMoving) //animation of ending move
  505. {
  506. creAnims[number]->setType(21);
  507. for(int i=0; i<creAnims[number]->framesInGroup(21); ++i)
  508. {
  509. show();
  510. CSDL_Ext::update();
  511. SDL_framerateDelay(LOCPLINT->mainFPSmng);
  512. if((animCount+1)%4)
  513. creAnims[number]->incrementFrame();
  514. }
  515. creAnims[number]->setType(2); //resetting to default
  516. activate();
  517. CGI->curh->show();
  518. }
  519. CStack curs = *LOCPLINT->cb->battleGetStackByID(number);
  520. if(endMoving) //resetting to default
  521. {
  522. if(creDir[number] != (curs.owner == attackingHeroInstance->tempOwner))
  523. reverseCreature(number, destHex, twoTiles);
  524. }
  525. std::pair <int, int> coords = CBattleHex::getXYUnitAnim(destHex, creDir[number], curs.creature);
  526. creAnims[number]->pos.x = coords.first;
  527. if(!endMoving && twoTiles && (creDir[number] != (curs.owner == attackingHeroInstance->tempOwner))) //big creature is reversed
  528. creAnims[number]->pos.x -= 44;
  529. creAnims[number]->pos.y = coords.second;
  530. }
  531. void CBattleInterface::stackIsAttacked(int ID, int dmg, int killed, int IDby, bool byShooting)
  532. {
  533. if(creAnims[ID]->getType() != 2)
  534. {
  535. return; //something went wrong
  536. }
  537. if(byShooting) //delay hit animation
  538. {
  539. CStack attacker = *LOCPLINT->cb->battleGetStackByID(IDby);
  540. while(true)
  541. {
  542. bool found = false;
  543. for(std::list<SProjectileInfo>::const_iterator it = projectiles.begin(); it!=projectiles.end(); ++it)
  544. {
  545. if(it->creID == attacker.creature->idNumber)
  546. {
  547. found = true;
  548. break;
  549. }
  550. }
  551. if(!found)
  552. break;
  553. else
  554. {
  555. show();
  556. CSDL_Ext::update();
  557. SDL_framerateDelay(LOCPLINT->mainFPSmng);
  558. }
  559. }
  560. }
  561. creAnims[ID]->setType(3); //getting hit
  562. for(int i=0; i<creAnims[ID]->framesInGroup(3); ++i)
  563. {
  564. show();
  565. CSDL_Ext::update();
  566. SDL_framerateDelay(LOCPLINT->mainFPSmng);
  567. if((animCount+1)%4)
  568. creAnims[ID]->incrementFrame();
  569. }
  570. creAnims[ID]->setType(2);
  571. printConsoleAttacked(ID, dmg, killed, IDby);
  572. }
  573. void CBattleInterface::stackAttacking(int ID, int dest)
  574. {
  575. if(attackingInfo != NULL)
  576. {
  577. return; //something went wrong
  578. }
  579. CStack aStack = *LOCPLINT->cb->battleGetStackByID(ID); //attacking stack
  580. if(aStack.creature->isDoubleWide())
  581. {
  582. switch(BattleInfo::mutualPosition(aStack.position, dest)) //attack direction
  583. {
  584. case 0:
  585. //reverseCreature(ID, aStack.position, true);
  586. break;
  587. case 1:
  588. break;
  589. case 2:
  590. break;
  591. case 3:
  592. break;
  593. case 4:
  594. //reverseCreature(ID, aStack.position, true);
  595. break;
  596. case 5:
  597. reverseCreature(ID, aStack.position, true);
  598. break;
  599. }
  600. }
  601. else //else for if(aStack.creature->isDoubleWide())
  602. {
  603. switch(BattleInfo::mutualPosition(aStack.position, dest)) //attack direction
  604. {
  605. case 0:
  606. reverseCreature(ID, aStack.position, true);
  607. break;
  608. case 1:
  609. break;
  610. case 2:
  611. break;
  612. case 3:
  613. break;
  614. case 4:
  615. reverseCreature(ID, aStack.position, true);
  616. break;
  617. case 5:
  618. reverseCreature(ID, aStack.position, true);
  619. break;
  620. }
  621. }
  622. attackingInfo = new CAttHelper;
  623. attackingInfo->dest = dest;
  624. attackingInfo->frame = 0;
  625. attackingInfo->ID = ID;
  626. attackingInfo->reversing = false;
  627. attackingInfo->shooting = false;
  628. switch(BattleInfo::mutualPosition(aStack.position, dest)) //attack direction
  629. {
  630. case 0:
  631. attackingInfo->maxframe = creAnims[ID]->framesInGroup(11);
  632. break;
  633. case 1:
  634. attackingInfo->maxframe = creAnims[ID]->framesInGroup(11);
  635. break;
  636. case 2:
  637. attackingInfo->maxframe = creAnims[ID]->framesInGroup(12);
  638. break;
  639. case 3:
  640. attackingInfo->maxframe = creAnims[ID]->framesInGroup(13);
  641. break;
  642. case 4:
  643. attackingInfo->maxframe = creAnims[ID]->framesInGroup(13);
  644. break;
  645. case 5:
  646. attackingInfo->maxframe = creAnims[ID]->framesInGroup(12);
  647. break;
  648. }
  649. }
  650. void CBattleInterface::newRound(int number)
  651. {
  652. console->addText(CGI->generaltexth->allTexts[412]);
  653. }
  654. void CBattleInterface::giveCommand(ui8 action, ui16 tile, ui32 stack, si32 additional)
  655. {
  656. BattleAction * ba = new BattleAction(); //is deleted in CPlayerInterface::activeStack()
  657. ba->actionType = action;
  658. ba->destinationTile = tile;
  659. ba->stackNumber = stack;
  660. ba->additionalInfo = additional;
  661. givenCommand->setn(ba);
  662. myTurn = false;
  663. activeStack = -1;
  664. }
  665. void CBattleInterface::hexLclicked(int whichOne)
  666. {
  667. if((whichOne%17)!=0 && (whichOne%17)!=16) //if player is trying to attack enemey unit or move creature stack
  668. {
  669. if(!myTurn)
  670. return; //we are not permit to do anything
  671. CStack* dest = LOCPLINT->cb->battleGetStackByPos(whichOne); //creature at destination tile; -1 if there is no one
  672. if(!dest || !dest->alive) //no creature at that tile
  673. {
  674. if(std::find(shadedHexes.begin(),shadedHexes.end(),whichOne)!=shadedHexes.end())// and it's in our range
  675. giveCommand(2,whichOne,activeStack);
  676. }
  677. else if(dest->owner != attackingHeroInstance->tempOwner
  678. && LOCPLINT->cb->battleCanShoot(activeStack, whichOne)) //shooting
  679. {
  680. giveCommand(7,whichOne,activeStack);
  681. }
  682. else if(dest->owner != attackingHeroInstance->tempOwner) //attacking
  683. {
  684. std::vector<int> n = BattleInfo::neighbouringTiles(whichOne);
  685. for(int i=0;i<n.size();i++)
  686. {
  687. //TODO: now we are using first available tile, but in the future we should add possibility of choosing from which tile we want to attack
  688. if(vstd::contains(shadedHexes,n[i]))
  689. {
  690. giveCommand(6,n[i],activeStack,whichOne);
  691. return;
  692. }
  693. }
  694. }
  695. }
  696. }
  697. void CBattleInterface::stackIsShooting(int ID, int dest)
  698. {
  699. if(attackingInfo != NULL)
  700. {
  701. return; //something went wrong
  702. }
  703. //projectile
  704. float projectileAngle; //in radians; if positive, projectiles goes up
  705. float straightAngle = 0.2f; //maximal angle in radians between straight horizontal line and shooting line for which shot is considered to be straight (absoulte value)
  706. int fromHex = LOCPLINT->cb->battleGetPos(ID);
  707. projectileAngle = atan2(float(abs(dest - fromHex)/17), float(abs(dest - fromHex)%17));
  708. if(fromHex < dest)
  709. projectileAngle = -projectileAngle;
  710. SProjectileInfo spi;
  711. spi.creID = LOCPLINT->cb->battleGetStackByID(ID)->creature->idNumber;
  712. spi.step = 0;
  713. spi.frameNum = 0;
  714. spi.spin = CGI->creh->idToProjectileSpin[spi.creID];
  715. std::pair<int, int> xycoord = CBattleHex::getXYUnitAnim(LOCPLINT->cb->battleGetPos(ID), true, &LOCPLINT->cb->battleGetCreature(ID));
  716. std::pair<int, int> destcoord = CBattleHex::getXYUnitAnim(dest, false, &LOCPLINT->cb->battleGetCreature(ID));
  717. destcoord.first += 250; destcoord.second += 210; //TODO: find a better place to shoot
  718. if(projectileAngle > straightAngle) //upper shot
  719. {
  720. spi.x = xycoord.first + 200 + LOCPLINT->cb->battleGetCreature(ID).upperRightMissleOffsetX;
  721. spi.y = xycoord.second + 150 - LOCPLINT->cb->battleGetCreature(ID).upperRightMissleOffsetY;
  722. }
  723. else if(projectileAngle < -straightAngle) //lower shot
  724. {
  725. spi.x = xycoord.first + 200 + LOCPLINT->cb->battleGetCreature(ID).lowerRightMissleOffsetX;
  726. spi.y = xycoord.second + 150 - LOCPLINT->cb->battleGetCreature(ID).lowerRightMissleOffsetY;
  727. }
  728. else //straight shot
  729. {
  730. spi.x = xycoord.first + 200 + LOCPLINT->cb->battleGetCreature(ID).rightMissleOffsetX;
  731. spi.y = xycoord.second + 150 - LOCPLINT->cb->battleGetCreature(ID).rightMissleOffsetY;
  732. }
  733. spi.lastStep = sqrt((float)((destcoord.first - spi.x)*(destcoord.first - spi.x) + (destcoord.second - spi.y) * (destcoord.second - spi.y))) / 40;
  734. spi.dx = (destcoord.first - spi.x) / spi.lastStep;
  735. spi.dy = (destcoord.second - spi.y) / spi.lastStep;
  736. //set starting frame
  737. if(spi.spin)
  738. {
  739. spi.frameNum = 0;
  740. }
  741. else
  742. {
  743. spi.frameNum = ((M_PI/2.0f - projectileAngle) / (2.0f *M_PI) + 1/((float)(2*(idToProjectile[spi.creID]->ourImages.size()-1)))) * (idToProjectile[spi.creID]->ourImages.size()-1);
  744. }
  745. //set delay
  746. spi.animStartDelay = CGI->creh->creatures[spi.creID].attackClimaxFrame;
  747. projectiles.push_back(spi);
  748. //attack aniamtion
  749. attackingInfo = new CAttHelper;
  750. attackingInfo->dest = dest;
  751. attackingInfo->frame = 0;
  752. attackingInfo->ID = ID;
  753. attackingInfo->reversing = false;
  754. attackingInfo->shooting = true;
  755. if(projectileAngle > straightAngle) //upper shot
  756. attackingInfo->shootingGroup = 14;
  757. else if(projectileAngle < -straightAngle) //lower shot
  758. attackingInfo->shootingGroup = 15;
  759. else //straight shot
  760. attackingInfo->shootingGroup = 16;
  761. attackingInfo->maxframe = creAnims[ID]->framesInGroup(attackingInfo->shootingGroup);
  762. }
  763. void CBattleInterface::showRange(SDL_Surface * to, int ID)
  764. {
  765. for(int i=0; i<shadedHexes.size(); ++i)
  766. {
  767. CSDL_Ext::blit8bppAlphaTo24bpp(CBattleInterface::cellShade, NULL, to, &bfield[shadedHexes[i]].pos);
  768. }
  769. }
  770. void CBattleInterface::attackingShowHelper()
  771. {
  772. if(attackingInfo && !attackingInfo->reversing)
  773. {
  774. if(attackingInfo->frame == 0)
  775. {
  776. CStack aStack = *LOCPLINT->cb->battleGetStackByID(attackingInfo->ID); //attacking stack
  777. if(attackingInfo->shooting)
  778. {
  779. creAnims[attackingInfo->ID]->setType(attackingInfo->shootingGroup);
  780. }
  781. else
  782. {
  783. if(aStack.creature->isDoubleWide())
  784. {
  785. switch(BattleInfo::mutualPosition(aStack.position, attackingInfo->dest)) //attack direction
  786. {
  787. case 0:
  788. creAnims[attackingInfo->ID]->setType(10);
  789. break;
  790. case 1:
  791. creAnims[attackingInfo->ID]->setType(10);
  792. break;
  793. case 2:
  794. creAnims[attackingInfo->ID]->setType(11);
  795. break;
  796. case 3:
  797. creAnims[attackingInfo->ID]->setType(12);
  798. break;
  799. case 4:
  800. creAnims[attackingInfo->ID]->setType(12);
  801. break;
  802. case 5:
  803. creAnims[attackingInfo->ID]->setType(11);
  804. break;
  805. }
  806. }
  807. else //else for if(aStack.creature->isDoubleWide())
  808. {
  809. switch(BattleInfo::mutualPosition(aStack.position, attackingInfo->dest)) //attack direction
  810. {
  811. case 0:
  812. creAnims[attackingInfo->ID]->setType(10);
  813. break;
  814. case 1:
  815. creAnims[attackingInfo->ID]->setType(10);
  816. break;
  817. case 2:
  818. creAnims[attackingInfo->ID]->setType(11);
  819. break;
  820. case 3:
  821. creAnims[attackingInfo->ID]->setType(12);
  822. break;
  823. case 4:
  824. creAnims[attackingInfo->ID]->setType(12);
  825. break;
  826. case 5:
  827. creAnims[attackingInfo->ID]->setType(11);
  828. break;
  829. }
  830. }
  831. }
  832. }
  833. else if(attackingInfo->frame == (attackingInfo->maxframe - 1))
  834. {
  835. attackingInfo->reversing = true;
  836. CStack aStack = *LOCPLINT->cb->battleGetStackByID(attackingInfo->ID); //attacking stack
  837. if(aStack.creature->isDoubleWide())
  838. {
  839. switch(BattleInfo::mutualPosition(aStack.position, attackingInfo->dest)) //attack direction
  840. {
  841. case 0:
  842. //reverseCreature(ID, aStack.position, true);
  843. break;
  844. case 1:
  845. break;
  846. case 2:
  847. break;
  848. case 3:
  849. break;
  850. case 4:
  851. //reverseCreature(ID, aStack.position, true);
  852. break;
  853. case 5:
  854. reverseCreature(attackingInfo->ID, aStack.position, true);
  855. break;
  856. }
  857. }
  858. else //else for if(aStack.creature->isDoubleWide())
  859. {
  860. switch(BattleInfo::mutualPosition(aStack.position, attackingInfo->dest)) //attack direction
  861. {
  862. case 0:
  863. reverseCreature(attackingInfo->ID, aStack.position, true);
  864. break;
  865. case 1:
  866. break;
  867. case 2:
  868. break;
  869. case 3:
  870. break;
  871. case 4:
  872. reverseCreature(attackingInfo->ID, aStack.position, true);
  873. break;
  874. case 5:
  875. reverseCreature(attackingInfo->ID, aStack.position, true);
  876. break;
  877. }
  878. }
  879. attackingInfo->reversing = false;
  880. creAnims[attackingInfo->ID]->setType(2);
  881. delete attackingInfo;
  882. attackingInfo = NULL;
  883. }
  884. if(attackingInfo)
  885. {
  886. attackingInfo->frame++;
  887. }
  888. }
  889. }
  890. void CBattleInterface::printConsoleAttacked(int ID, int dmg, int killed, int IDby)
  891. {
  892. char tabh[200];
  893. CStack attacker = *LOCPLINT->cb->battleGetStackByID(IDby);
  894. CStack defender = *LOCPLINT->cb->battleGetStackByID(ID);
  895. int end = sprintf(tabh, CGI->generaltexth->allTexts[attacker.amount > 1 ? 377 : 376].c_str(),
  896. (attacker.amount > 1 ? attacker.creature->namePl.c_str() : attacker.creature->nameSing.c_str()),
  897. dmg);
  898. if(killed > 0)
  899. {
  900. if(killed > 1)
  901. {
  902. sprintf(tabh + end, CGI->generaltexth->allTexts[379].c_str(), killed, defender.creature->namePl.c_str());
  903. }
  904. else //killed == 1
  905. {
  906. sprintf(tabh + end, CGI->generaltexth->allTexts[378].c_str(), defender.creature->nameSing.c_str());
  907. }
  908. }
  909. console->addText(std::string(tabh));
  910. }
  911. void CBattleInterface::projectileShowHelper(SDL_Surface * to)
  912. {
  913. if(to == NULL)
  914. to = screen;
  915. std::list< std::list<SProjectileInfo>::iterator > toBeDeleted;
  916. for(std::list<SProjectileInfo>::iterator it=projectiles.begin(); it!=projectiles.end(); ++it)
  917. {
  918. if(it->animStartDelay>0)
  919. {
  920. --(it->animStartDelay);
  921. continue;
  922. }
  923. SDL_Rect dst;
  924. dst.h = idToProjectile[it->creID]->ourImages[it->frameNum].bitmap->h;
  925. dst.w = idToProjectile[it->creID]->ourImages[it->frameNum].bitmap->w;
  926. dst.x = it->x;
  927. dst.y = it->y;
  928. CSDL_Ext::blit8bppAlphaTo24bpp(idToProjectile[it->creID]->ourImages[it->frameNum].bitmap, NULL, to, &dst);
  929. //actualizing projectile
  930. ++it->step;
  931. if(it->step == it->lastStep)
  932. {
  933. toBeDeleted.insert(toBeDeleted.end(), it);
  934. }
  935. else
  936. {
  937. it->x += it->dx;
  938. it->y += it->dy;
  939. if(it->spin)
  940. {
  941. ++(it->frameNum);
  942. it->frameNum %= idToProjectile[it->creID]->ourImages.size();
  943. }
  944. }
  945. }
  946. for(std::list< std::list<SProjectileInfo>::iterator >::iterator it = toBeDeleted.begin(); it!= toBeDeleted.end(); ++it)
  947. {
  948. projectiles.erase(*it);
  949. }
  950. }
  951. void CBattleHero::show(SDL_Surface *to)
  952. {
  953. //animation of flag
  954. if(flip)
  955. {
  956. CSDL_Ext::blit8bppAlphaTo24bpp(flag->ourImages[flagAnim].bitmap, NULL, screen, &genRect(flag->ourImages[flagAnim].bitmap->h, flag->ourImages[flagAnim].bitmap->w, 752, 39));
  957. }
  958. else
  959. {
  960. CSDL_Ext::blit8bppAlphaTo24bpp(flag->ourImages[flagAnim].bitmap, NULL, screen, &genRect(flag->ourImages[flagAnim].bitmap->h, flag->ourImages[flagAnim].bitmap->w, 31, 39));
  961. }
  962. {
  963. ++flagAnim;
  964. flagAnim %= flag->ourImages.size();
  965. }
  966. //animation of hero
  967. int tick=-1;
  968. for(int i=0; i<dh->ourImages.size(); ++i)
  969. {
  970. if(dh->ourImages[i].groupNumber==phase)
  971. ++tick;
  972. if(tick==image)
  973. {
  974. SDL_Rect posb = pos;
  975. CSDL_Ext::blit8bppAlphaTo24bpp(dh->ourImages[i].bitmap, NULL, to, &posb);
  976. ++image;
  977. if(dh->ourImages[i+1].groupNumber!=phase) //back to appropriate frame
  978. {
  979. image = 0;
  980. }
  981. break;
  982. }
  983. }
  984. }
  985. CBattleHero::CBattleHero(std::string defName, int phaseG, int imageG, bool flipG, unsigned char player): phase(phaseG), image(imageG), flip(flipG), flagAnim(0)
  986. {
  987. dh = CDefHandler::giveDef( defName );
  988. for(int i=0; i<dh->ourImages.size(); ++i) //transforming images
  989. {
  990. if(flip)
  991. {
  992. SDL_Surface * hlp = CSDL_Ext::rotate01(dh->ourImages[i].bitmap);
  993. SDL_FreeSurface(dh->ourImages[i].bitmap);
  994. dh->ourImages[i].bitmap = hlp;
  995. }
  996. dh->ourImages[i].bitmap = CSDL_Ext::alphaTransform(dh->ourImages[i].bitmap);
  997. }
  998. dh->alphaTransformed = true;
  999. if(flip)
  1000. flag = CDefHandler::giveDef("CMFLAGR.DEF");
  1001. else
  1002. flag = CDefHandler::giveDef("CMFLAGL.DEF");
  1003. //coloring flag and adding transparency
  1004. for(int i=0; i<flag->ourImages.size(); ++i)
  1005. {
  1006. flag->ourImages[i].bitmap = CSDL_Ext::alphaTransform(flag->ourImages[i].bitmap);
  1007. graphics->blueToPlayersAdv(flag->ourImages[i].bitmap, player);
  1008. }
  1009. }
  1010. CBattleHero::~CBattleHero()
  1011. {
  1012. delete dh;
  1013. delete flag;
  1014. }
  1015. std::pair<int, int> CBattleHex::getXYUnitAnim(int hexNum, bool attacker, CCreature * creature)
  1016. {
  1017. std::pair<int, int> ret = std::make_pair(-500, -500); //returned value
  1018. ret.second = -139 + 42 * (hexNum/17); //counting y
  1019. //counting x
  1020. if(attacker)
  1021. {
  1022. ret.first = -160 + 22 * ( ((hexNum/17) + 1)%2 ) + 44 * (hexNum % 17);
  1023. }
  1024. else
  1025. {
  1026. ret.first = -219 + 22 * ( ((hexNum/17) + 1)%2 ) + 44 * (hexNum % 17);
  1027. }
  1028. //shifting position for double - hex creatures
  1029. if(creature->isDoubleWide())
  1030. {
  1031. if(attacker)
  1032. {
  1033. ret.first -= 42;
  1034. }
  1035. else
  1036. {
  1037. ret.first += 42;
  1038. }
  1039. }
  1040. //returning
  1041. return ret;
  1042. }
  1043. void CBattleHex::activate()
  1044. {
  1045. Hoverable::activate();
  1046. MotionInterested::activate();
  1047. ClickableL::activate();
  1048. ClickableR::activate();
  1049. }
  1050. void CBattleHex::deactivate()
  1051. {
  1052. Hoverable::deactivate();
  1053. MotionInterested::deactivate();
  1054. ClickableL::deactivate();
  1055. ClickableR::deactivate();
  1056. }
  1057. void CBattleHex::hover(bool on)
  1058. {
  1059. hovered = on;
  1060. Hoverable::hover(on);
  1061. if(!on && setAlterText)
  1062. {
  1063. myInterface->console->alterTxt = std::string();
  1064. setAlterText = false;
  1065. }
  1066. }
  1067. CBattleHex::CBattleHex() : myNumber(-1), accesible(true), hovered(false), strictHovered(false), myInterface(NULL), setAlterText(false)
  1068. {
  1069. }
  1070. void CBattleHex::mouseMoved(SDL_MouseMotionEvent &sEvent)
  1071. {
  1072. if(CBattleInterface::cellShade)
  1073. {
  1074. if(CSDL_Ext::SDL_GetPixel(CBattleInterface::cellShade, sEvent.x-pos.x, sEvent.y-pos.y) == 0) //hovered pixel is outside hex
  1075. {
  1076. strictHovered = false;
  1077. }
  1078. else //hovered pixel is inside hex
  1079. {
  1080. strictHovered = true;
  1081. if(myInterface->activeStack>=0)
  1082. {
  1083. if(std::find(myInterface->shadedHexes.begin(),myInterface->shadedHexes.end(),myNumber) == myInterface->shadedHexes.end())
  1084. {
  1085. CStack *shere = LOCPLINT->cb->battleGetStackByPos(myNumber);
  1086. if(shere)
  1087. {
  1088. if(shere->owner == LOCPLINT->playerID) //our stack
  1089. CGI->curh->changeGraphic(1,5);
  1090. else if(LOCPLINT->cb->battleGetStackByID(myInterface->activeStack)->creature->isShooting()) //we can shoot enemy
  1091. CGI->curh->changeGraphic(1,3);
  1092. else //unavailable enemy
  1093. CGI->curh->changeGraphic(1,0);
  1094. }
  1095. else //empty unavailable tile
  1096. CGI->curh->changeGraphic(1,0);
  1097. }
  1098. else //available tile
  1099. {
  1100. if(LOCPLINT->cb->battleGetStackByID(myInterface->activeStack)->creature->isFlying())
  1101. CGI->curh->changeGraphic(1,2);
  1102. else
  1103. CGI->curh->changeGraphic(1,1);
  1104. }
  1105. }
  1106. }
  1107. }
  1108. if(hovered && strictHovered) //print attacked creature to console
  1109. {
  1110. if(myInterface->console->alterTxt.size() == 0 && LOCPLINT->cb->battleGetStack(myNumber) != -1 &&
  1111. LOCPLINT->cb->battleGetStackByPos(myNumber)->owner != LOCPLINT->playerID &&
  1112. LOCPLINT->cb->battleGetStackByPos(myNumber)->alive)
  1113. {
  1114. char tabh[160];
  1115. CStack attackedStack = *LOCPLINT->cb->battleGetStackByPos(myNumber);
  1116. std::string attackedName = attackedStack.amount == 1 ? attackedStack.creature->nameSing : attackedStack.creature->namePl;
  1117. sprintf(tabh, CGI->generaltexth->allTexts[220].c_str(), attackedName.c_str());
  1118. myInterface->console->alterTxt = std::string(tabh);
  1119. setAlterText = true;
  1120. }
  1121. }
  1122. else if(setAlterText)
  1123. {
  1124. myInterface->console->alterTxt = std::string();
  1125. setAlterText = false;
  1126. }
  1127. }
  1128. void CBattleHex::clickLeft(boost::logic::tribool down)
  1129. {
  1130. if(!down && hovered && strictHovered) //we've been really clicked!
  1131. {
  1132. myInterface->hexLclicked(myNumber);
  1133. }
  1134. }
  1135. void CBattleHex::clickRight(boost::logic::tribool down)
  1136. {
  1137. int stID = LOCPLINT->cb->battleGetStack(myNumber); //id of stack being on this tile
  1138. if(hovered && strictHovered && stID!=-1)
  1139. {
  1140. CStack myst = *LOCPLINT->cb->battleGetStackByID(stID); //stack info
  1141. if(!myst.alive) return;
  1142. StackState *pom = NULL;
  1143. if(down)
  1144. {
  1145. pom = new StackState();
  1146. const CGHeroInstance *h = myst.owner == myInterface->attackingHeroInstance->tempOwner ? myInterface->attackingHeroInstance : myInterface->defendingHeroInstance;
  1147. if(h)
  1148. {
  1149. pom->attackBonus = h->primSkills[0];
  1150. pom->defenseBonus = h->primSkills[1];
  1151. pom->luck = h->getCurrentLuck();
  1152. pom->morale = h->getCurrentMorale();
  1153. pom->currentHealth = myst.firstHPleft;
  1154. }
  1155. (new CCreInfoWindow(myst.creature->idNumber,0,myst.amount,pom,boost::function<void()>(),boost::function<void()>(),NULL))
  1156. ->activate();
  1157. }
  1158. delete pom;
  1159. }
  1160. }
  1161. CBattleConsole::CBattleConsole() : lastShown(-1), alterTxt("")
  1162. {
  1163. }
  1164. CBattleConsole::~CBattleConsole()
  1165. {
  1166. texts.clear();
  1167. }
  1168. void CBattleConsole::show(SDL_Surface * to)
  1169. {
  1170. if(alterTxt.size())
  1171. {
  1172. CSDL_Ext::printAtMiddleWB(alterTxt, pos.x + pos.w/2, pos.y + 10, GEOR13, 80, zwykly, to);
  1173. }
  1174. else if(texts.size())
  1175. {
  1176. if(texts.size()==1)
  1177. {
  1178. CSDL_Ext::printAtMiddleWB(texts[0], pos.x + pos.w/2, pos.y + 10, GEOR13, 80, zwykly, to);
  1179. }
  1180. else
  1181. {
  1182. CSDL_Ext::printAtMiddleWB(texts[lastShown-1], pos.x + pos.w/2, pos.y + 10, GEOR13, 80, zwykly, to);
  1183. CSDL_Ext::printAtMiddleWB(texts[lastShown], pos.x + pos.w/2, pos.y + 26, GEOR13, 80, zwykly, to);
  1184. }
  1185. }
  1186. }
  1187. bool CBattleConsole::addText(std::string text)
  1188. {
  1189. if(text.size()>70)
  1190. return false; //text too long!
  1191. int firstInToken = 0;
  1192. for(int i=0; i<text.size(); ++i) //tokenize
  1193. {
  1194. if(text[i] == 10)
  1195. {
  1196. texts.push_back( text.substr(firstInToken, i-firstInToken) );
  1197. firstInToken = i+1;
  1198. }
  1199. }
  1200. texts.push_back( text.substr(firstInToken, text.size()) );
  1201. lastShown = texts.size()-1;
  1202. return true;
  1203. }
  1204. void CBattleConsole::eraseText(unsigned int pos)
  1205. {
  1206. if(pos < texts.size())
  1207. {
  1208. texts.erase(texts.begin() + pos);
  1209. if(lastShown == texts.size())
  1210. --lastShown;
  1211. }
  1212. }
  1213. void CBattleConsole::changeTextAt(std::string text, unsigned int pos)
  1214. {
  1215. if(pos >= texts.size()) //no such pos
  1216. return;
  1217. texts[pos] = text;
  1218. }
  1219. void CBattleConsole::scrollUp(unsigned int by)
  1220. {
  1221. if(lastShown > by)
  1222. lastShown -= by;
  1223. }
  1224. void CBattleConsole::scrollDown(unsigned int by)
  1225. {
  1226. if(lastShown + by < texts.size())
  1227. lastShown += by;
  1228. }