PageRenderTime 78ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/src/freecnc/game/unitanimations.cpp

https://bitbucket.org/comrad/freecnc
C++ | 492 lines | 415 code | 56 blank | 21 comment | 107 complexity | e7b5636cc89ef5187bc1cc57e8394677 MD5 | raw file
  1. #include <cmath>
  2. #include "map.h"
  3. #include "../freecnc.h"
  4. #include "path.h"
  5. #include "projectileanim.h"
  6. #include "talkback.h"
  7. #include "unit.h"
  8. #include "unitandstructurepool.h"
  9. #include "unitorstructure.h"
  10. #include "unitanimations.h"
  11. #include "weaponspool.h"
  12. using std::runtime_error;
  13. UnitAnimEvent::UnitAnimEvent(unsigned int p, Unit* un) : ActionEvent(p)
  14. {
  15. //logger->debug("UAE cons: this:%p un:%p\n",this,un);
  16. this->un = un;
  17. un->referTo();
  18. }
  19. void UnitAnimEvent::finish()
  20. {
  21. if (scheduled) {
  22. p::aequeue->scheduleEvent(scheduled);
  23. }
  24. }
  25. UnitAnimEvent::~UnitAnimEvent()
  26. {
  27. //logger->debug("UAE dest: this:%p un:%p sch:%p\n",this,un,scheduled);
  28. un->unrefer();
  29. }
  30. void UnitAnimEvent::setSchedule(shared_ptr<UnitAnimEvent> e)
  31. {
  32. //logger->debug("Scheduling an event. (this: %p, e: %p)\n",this,e);
  33. if (scheduled) {
  34. scheduled->setSchedule();
  35. scheduled->stop();
  36. }
  37. scheduled = e;
  38. }
  39. void UnitAnimEvent::setSchedule()
  40. {
  41. scheduled.reset();
  42. }
  43. MoveAnimEvent::MoveAnimEvent(unsigned int p, Unit* un) : UnitAnimEvent(p,un)
  44. {
  45. //logger->debug("MoveAnim cons (this %p un %p)\n",this,un);
  46. stopping = false;
  47. blocked = false;
  48. range = 0;
  49. this->dest = un->getTargetCell();
  50. this->un = un;
  51. path = NULL;
  52. newpos = 0xffff;
  53. istep = 0;
  54. moved_half = true;
  55. waiting = false;
  56. pathinvalid = true;
  57. }
  58. MoveAnimEvent::~MoveAnimEvent()
  59. {
  60. delete path;
  61. }
  62. void MoveAnimEvent::finish()
  63. {
  64. if (waiting) {
  65. return;
  66. }
  67. if (un->moveanim.get() == this)
  68. un->moveanim.reset();
  69. //logger->debug("MoveAnim dest (this %p un %p dest %u)\n",this,un,dest);
  70. if( !moved_half && newpos != 0xffff) {
  71. p::uspool->abortMove(un,newpos);
  72. }
  73. if (un->walkanim) {
  74. un->walkanim->stop();
  75. }
  76. if (un->turnanim1) {
  77. un->turnanim1->stop();
  78. }
  79. if (un->turnanim2) {
  80. un->turnanim2->stop();
  81. }
  82. UnitAnimEvent::finish();
  83. }
  84. bool MoveAnimEvent::run()
  85. {
  86. char uxoff, uyoff;
  87. unsigned char oldsubpos;
  88. waiting = false;
  89. if( !un->isAlive() ) {
  90. return false;
  91. }
  92. if( path == NULL ) {
  93. p::uspool->setCostCalcOwnerAndType(un->owner, 0);
  94. path = new Path(un->getPos(), dest, range);
  95. if( !path->empty() ) {
  96. return startMoveOne(false);
  97. } else {
  98. if (un->attackanim) {
  99. un->attackanim->stop();
  100. }
  101. }
  102. return false;
  103. }
  104. if( blocked ) {
  105. blocked = false;
  106. return startMoveOne(true);
  107. }
  108. /* if distance left is smaller than xmod we're ready */
  109. un->xoffset += xmod;
  110. un->yoffset += ymod;
  111. if( !moved_half && (abs(un->xoffset) >= 12 || abs(un->yoffset) >= 12) ) {
  112. oldsubpos = un->subpos;
  113. un->subpos = p::uspool->postMove(un, newpos);
  114. un->cellpos = newpos;
  115. un->xoffset = -un->xoffset;
  116. un->yoffset = -un->yoffset;
  117. if( un->type->isInfantry() ) {
  118. un->infgrp->GetSubposOffsets(oldsubpos, un->subpos, &uxoff, &uyoff);
  119. un->xoffset += uxoff;
  120. un->yoffset += uyoff;
  121. xmod = 0;
  122. ymod = 0;
  123. if( un->xoffset < 0 )
  124. xmod = 1;
  125. else if( un->xoffset > 0 )
  126. xmod = -1;
  127. if( un->yoffset < 0 )
  128. ymod = 1;
  129. else if( un->yoffset > 0 )
  130. ymod = -1;
  131. }
  132. moved_half = true;
  133. }
  134. if( abs(un->xoffset) < abs(xmod) )
  135. xmod = 0;
  136. if( abs(un->yoffset) < abs(ymod) )
  137. ymod = 0;
  138. if( xmod == 0 && ymod == 0 ) {
  139. un->xoffset = 0;
  140. un->yoffset = 0;
  141. return moveDone();
  142. }
  143. return true;
  144. }
  145. bool MoveAnimEvent::startMoveOne(bool wasblocked)
  146. {
  147. unsigned char face;
  148. newpos = p::uspool->preMove(un, path->top(), &xmod, &ymod);
  149. if( newpos == 0xffff ) {
  150. delete path;
  151. path = NULL;
  152. p::uspool->setCostCalcOwnerAndType(un->owner, 0);
  153. path = new Path(un->getPos(), dest, range);
  154. pathinvalid = false;
  155. if( path->empty() ) {
  156. xmod = 0;
  157. ymod = 0;
  158. return true;
  159. }
  160. newpos = p::uspool->preMove(un, path->top(), &xmod, &ymod);
  161. if( newpos == 0xffff ) {
  162. if (wasblocked) {
  163. xmod = 0;
  164. ymod = 0;
  165. if (un->attackanim != NULL) {
  166. un->attackanim->stop();
  167. }
  168. this->stop();
  169. return true;
  170. } else {
  171. /* TODO: tell the blocking unit to move here */
  172. blocked = true;
  173. if (un->walkanim != NULL) {
  174. un->walkanim->stop();
  175. }
  176. return true;
  177. }
  178. }
  179. }
  180. face = (32-(path->top() << 2))&0x1f;
  181. path->pop();
  182. moved_half = false;
  183. if (((UnitType *)un->getType())->isInfantry()) {
  184. if (un->walkanim != NULL) {
  185. un->walkanim->changedir(face);
  186. } else {
  187. un->walkanim.reset(new WalkAnimEvent(((UnitType *)un->getType())->getSpeed(), un, face, 0));
  188. p::aequeue->scheduleEvent(un->walkanim);
  189. }
  190. return true;
  191. }
  192. unsigned char curface = (un->getImageNum(0)&0x1f);
  193. unsigned char delta = (abs(curface-face))&0x1f;
  194. if( (un->getImageNum(0)&0x1f) != face ) {
  195. if( (delta < 5) || (delta > 27) ) {
  196. un->turn(face,0);
  197. return true;
  198. } else {
  199. waiting = true;
  200. un->turn(face,0);
  201. un->turnanim1->setSchedule(un->moveanim);
  202. }
  203. if (un->getType()->getNumLayers() > 1) {
  204. un->turn(face,1);
  205. }
  206. } else {
  207. return true;
  208. }
  209. return false;
  210. }
  211. bool MoveAnimEvent::moveDone()
  212. {
  213. un->xoffset = 0;
  214. un->yoffset = 0;
  215. if (pathinvalid) {
  216. delete path;
  217. p::uspool->setCostCalcOwnerAndType(un->owner, 0);
  218. path = new Path(un->getPos(), dest, range);
  219. pathinvalid = false;
  220. }
  221. if( !path->empty() && !stopping ) {
  222. return startMoveOne(false);
  223. }
  224. if( dest != un->getPos() && !stopping ) {
  225. delete path;
  226. p::uspool->setCostCalcOwnerAndType(un->owner, 0);
  227. path = new Path(un->getPos(), dest, range);
  228. pathinvalid = false;
  229. }
  230. if( path->empty() || stopping ) {
  231. return false;
  232. }
  233. return startMoveOne(false);
  234. }
  235. void MoveAnimEvent::stop()
  236. {
  237. stopping = true;
  238. }
  239. void MoveAnimEvent::update()
  240. {
  241. //logger->debug("Move updating\n");
  242. dest = un->getTargetCell();
  243. pathinvalid = true;
  244. stopping = false;
  245. range = 0;
  246. }
  247. WalkAnimEvent::WalkAnimEvent(unsigned int p, Unit *un, unsigned char dir, unsigned char layer) : UnitAnimEvent(p,un)
  248. {
  249. //fprintf(stderr,"debug: WalkAnim constructor\n");
  250. this->un = un;
  251. this->dir = dir;
  252. this->layer = layer;
  253. stopping = false;
  254. istep = 0;
  255. calcbaseimage();
  256. }
  257. void WalkAnimEvent::finish()
  258. {
  259. un->setImageNum(dir>>2,layer);
  260. if (un->walkanim.get() == this)
  261. un->walkanim.reset();
  262. UnitAnimEvent::finish();
  263. }
  264. bool WalkAnimEvent::run()
  265. {
  266. unsigned char layerface;
  267. if (!stopping) {
  268. layerface = baseimage + istep;
  269. // XXX: Assumes 6 frames to loop over
  270. istep = (istep + 1)%6;
  271. un->setImageNum(layerface,layer);
  272. return true;
  273. }
  274. return false;
  275. }
  276. void WalkAnimEvent::calcbaseimage()
  277. {
  278. // XXX: this is really nasty, will be taken care of after the rewrite
  279. baseimage = 16 + 3*(dir/2);
  280. }
  281. TurnAnimEvent::TurnAnimEvent(unsigned int p, Unit *un, unsigned char dir, unsigned char layer) : UnitAnimEvent(p,un)
  282. {
  283. //logger->debug("Turn cons (t%p u%p d%i l%i)\n",this,un,dir,layer);
  284. unsigned char layerface;
  285. this->un = un;
  286. this->dir = dir;
  287. this->layer = layer;
  288. stopping = false;
  289. layerface = un->getImageNum(layer)&0x1f;
  290. if( ((layerface-dir)&0x1f) < ((dir-layerface)&0x1f) ) {
  291. turnmod = -(((UnitType *)un->getType())->getTurnMod());
  292. } else {
  293. turnmod = (((UnitType *)un->getType())->getTurnMod());
  294. }
  295. }
  296. void TurnAnimEvent::finish()
  297. {
  298. //logger->debug("TurnAnim dest\n");
  299. if (layer == 0) {
  300. if (un->turnanim1.get() == this)
  301. un->turnanim1.reset();
  302. } else {
  303. if (un->turnanim2.get() == this)
  304. un->turnanim2.reset();
  305. }
  306. UnitAnimEvent::finish();
  307. }
  308. bool TurnAnimEvent::run()
  309. {
  310. unsigned char layerface;
  311. //logger->debug("TurnAnim run (s%i)\n",stopping);
  312. if (stopping) {
  313. return false;
  314. }
  315. layerface = un->getImageNum(layer)&0x1f;
  316. if( abs((layerface-dir)&0x1f) > abs(turnmod) ) {
  317. layerface += turnmod;
  318. layerface &= 0x1f;
  319. } else
  320. layerface = dir;
  321. un->setImageNum(layerface,layer);
  322. if( layerface == dir || !un->isAlive()) {
  323. return false;
  324. }
  325. return true;
  326. }
  327. UAttackAnimEvent::UAttackAnimEvent(unsigned int p, Unit *un) : UnitAnimEvent(p,un)
  328. {
  329. //logger->debug("UAttack cons\n");
  330. this->un = un;
  331. this->target = un->getTarget();
  332. stopping = false;
  333. waiting = 0;
  334. target->referTo();
  335. }
  336. UAttackAnimEvent::~UAttackAnimEvent()
  337. {
  338. //logger->debug("UAttack dest\n");
  339. target->unrefer();
  340. }
  341. void UAttackAnimEvent::finish()
  342. {
  343. if (waiting != 0) {
  344. return;
  345. }
  346. if (un->attackanim.get() == this)
  347. un->attackanim.reset();
  348. UnitAnimEvent::finish();
  349. }
  350. void UAttackAnimEvent::update()
  351. {
  352. //logger->debug("UAtk updating\n");
  353. target->unrefer();
  354. target = un->getTarget();
  355. target->referTo();
  356. stopping = false;
  357. }
  358. void UAttackAnimEvent::stop()
  359. {
  360. assert(un);
  361. stopping = true;
  362. if (un->attackanim.get() == this)
  363. un->attackanim.reset();
  364. }
  365. bool UAttackAnimEvent::run()
  366. {
  367. unsigned int distance;
  368. int xtiles, ytiles;
  369. unsigned short atkpos;
  370. float alpha;
  371. unsigned char facing;
  372. //logger->debug("attack run t%p u%p\n",this,un);
  373. waiting = 0;
  374. if( !un->isAlive() || stopping ) {
  375. return false;
  376. }
  377. if( !target->isAlive() || stopping) {
  378. if ( !target->isAlive() ) {
  379. un->doRandTalk(TB_postkill);
  380. }
  381. return false;
  382. }
  383. atkpos = un->getTargetCell();
  384. xtiles = un->cellpos % p::ccmap->getWidth() - atkpos % p::ccmap->getWidth();
  385. ytiles = un->cellpos / p::ccmap->getWidth() - atkpos / p::ccmap->getWidth();
  386. distance = abs(xtiles)>abs(ytiles)?abs(xtiles):abs(ytiles);
  387. if( distance > un->type->getWeapon()->getRange() /* weapons range */ ) {
  388. setDelay(0);
  389. waiting = 3;
  390. un->move(atkpos,false);
  391. un->moveanim->setRange(un->type->getWeapon()->getRange());
  392. un->moveanim->setSchedule(un->attackanim);
  393. return false;
  394. }
  395. //Make sure we're facing the right way
  396. if( xtiles == 0 ) {
  397. if( ytiles < 0 ) {
  398. alpha = -M_PI_2;
  399. } else {
  400. alpha = M_PI_2;
  401. }
  402. } else {
  403. alpha = atan((float)ytiles/(float)xtiles);
  404. if( xtiles < 0 ) {
  405. alpha = M_PI+alpha;
  406. }
  407. }
  408. facing = (40-(char)(alpha*16/M_PI))&0x1f;
  409. if (un->type->isInfantry()) {
  410. if (facing != (un->getImageNum(0)&0x1f)) {
  411. un->setImageNum(facing>>2,0);
  412. }
  413. } else if (un->type->getNumLayers() > 1 ) {
  414. if (abs((int)(facing - (un->getImageNum(1)&0x1f))) > un->type->getROT()) {
  415. setDelay(0);
  416. waiting = 2;
  417. un->turn(facing,1);
  418. un->turnanim2->setSchedule(un->attackanim);
  419. return false;
  420. }
  421. } else {
  422. if (abs((int)(facing - un->getImageNum(0)&0x1f)) > un->type->getROT()) {
  423. setDelay(0);
  424. waiting = 1;
  425. un->turn(facing,0);
  426. un->turnanim1->setSchedule(un->attackanim);
  427. return false;
  428. }
  429. }
  430. // We can shoot
  431. un->type->getWeapon()->fire(un, target->getBPos(un->getPos()), target->getSubpos());
  432. // set delay to reloadtime
  433. setDelay(un->type->getWeapon()->getReloadTime());
  434. waiting = 4;
  435. return true;
  436. }