CBattleInterface.cpp 40 KB

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