CBattleInterface.cpp 41 KB

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