SpaceShip.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. #include "SpaceShip.h"
  2. struct Actor
  3. {
  4. Uint16 idY;
  5. Uint16 idX;
  6. };
  7. struct Laser
  8. {
  9. Uint16 idY;
  10. Uint16 idX;
  11. Uint8 r;
  12. Uint8 g;
  13. Uint8 b;
  14. Uint8 a;
  15. };
  16. SpaceShip::SpaceShip()
  17. :m_heartX(0), m_heartY(0), m_ally( false ),
  18. m_pos( {1100, 300, 42, 42} ),
  19. m_shH(0), m_shW(0), m_shape(0x0), m_solid(0x0),
  20. m_hiter(0x0),
  21. m_shieldLeft(0), m_shieldMax(0), m_shieldLast(0), m_shieldDelay(SHIELD_MAX_DELAY)
  22. {
  23. for ( int i(0); i < SHOT_NB; i++ )
  24. m_loading[i] = 0;
  25. }
  26. SpaceShip::SpaceShip( bool ally )
  27. :m_heartX(0), m_heartY(0), m_ally( ally ),
  28. m_pos( {1100, 300, 42, 42} ),
  29. m_shH(0), m_shW(0), m_shape(0x0), m_solid(0x0),
  30. m_hiter(0x0),
  31. m_shieldLeft(0), m_shieldMax(0), m_shieldLast(0), m_shieldDelay(SHIELD_MAX_DELAY)
  32. {
  33. //ctor ally setter
  34. }
  35. SpaceShip::~SpaceShip()
  36. {
  37. destroyTabs();
  38. }
  39. void SpaceShip::giveHitManager( HitManager* theHitManager )
  40. {
  41. m_hiter = theHitManager;
  42. }
  43. void SpaceShip::setPos( Sint16 x, Sint16 y )
  44. {
  45. m_pos.x = x;
  46. m_pos.y = y;
  47. }
  48. SDL_Rect* SpaceShip::getPos()
  49. {
  50. return &m_pos;
  51. }
  52. SDL_Rect SpaceShip::getHeartPos()
  53. {
  54. SDL_Rect rep;
  55. rep.x = m_pos.x + 8 * m_heartX + 4;
  56. rep.y = m_pos.y + 8 * m_heartY + 4;
  57. return rep;
  58. }
  59. bool SpaceShip::getIsAlive()
  60. {
  61. return m_solid[m_heartY][m_heartX] > 0;
  62. }
  63. SDL_Rect* SpaceShip::getHitBox()
  64. {
  65. return &m_pos;
  66. }
  67. void SpaceShip::loadShape( std::string path )
  68. {
  69. /// Reinitialisation
  70. // Déstruction structure et modèle
  71. destroyTabs();
  72. // Initialisation des dimensions
  73. m_shH = 0;
  74. m_shW = 0;
  75. m_heartY = 0;
  76. m_heartX = 0;
  77. // Initialisation du bouclier
  78. m_shieldLeft = 0;
  79. m_shieldMax = 0;
  80. m_shieldLast = 0;
  81. m_shieldDelay = SHIELD_MAX_DELAY;
  82. /// Lecture du fichier
  83. // Création du flux
  84. std::ifstream flux( path.c_str() );
  85. // Lecture du modèle
  86. std::queue<std::string> tempo ;
  87. std::string line ;
  88. while ( std::getline(flux, line) )
  89. {
  90. tempo.push( line );
  91. if ( line.length() > m_shW )
  92. m_shW = line.length();
  93. }
  94. /// Ecriture du shape ET du solid
  95. // Dimensions du vaisseau
  96. m_shH = tempo.size();
  97. m_pos.h = 8 * m_shH ;
  98. m_pos.w = 8 * m_shW ;
  99. // Création des tableaux statiques
  100. m_shape = new char*[ m_shH ];
  101. for ( int i(0); i < m_shH; i ++ )
  102. m_shape[i] = new char[ m_shW ];
  103. m_solid = new Uint8*[ m_shH ];
  104. for ( int i(0); i < m_shH; i ++ )
  105. m_solid[i] = new Uint8[ m_shW ];
  106. // Lecture des caractères
  107. for ( int i(0); i < m_shH; i++ )
  108. {
  109. line = tempo.front();
  110. for ( unsigned int j(0); j < m_shW; j++ )
  111. {
  112. if ( j < line.length() && line[j] != ' ' ) {
  113. // Présence d'une pièce
  114. m_shape[i][j] = line.c_str()[j];
  115. m_solid[i][j] = 255;
  116. // Détection du cœur
  117. if ( m_shape[i][j] == 'm' ){
  118. m_heartY = i;
  119. m_heartX = j;
  120. }
  121. }
  122. else {
  123. // Pas de bloc à cet endroit
  124. m_shape[i][j] = ' ';
  125. m_solid[i][j] = 0;
  126. }
  127. }
  128. tempo.pop();
  129. }
  130. /// Détection des actionneurs
  131. for ( int i(0); i < m_shH; i++ )
  132. {
  133. for ( unsigned int j(0); j < m_shW - 1; j++ )
  134. {
  135. // Détection d'une arme
  136. if ( m_shape[i][j] == '[' )
  137. {
  138. switch ( m_shape[i][j + 1] )
  139. {
  140. case '-':
  141. m_act[GUN_ID].push_back( { i, j + 1} );
  142. break;
  143. case '<':
  144. m_act[DISPER_ID].push_back( { i, j + 1} );
  145. break;
  146. case '|':
  147. m_act[CUTTER_ID].push_back( { i, j + 1} );
  148. break;
  149. case 'O':
  150. m_act[PHOTO_ID].push_back( { i, j + 1} );
  151. break;
  152. case '>':
  153. m_act[MISSILE_ID].push_back( { i, j + 1} );
  154. break;
  155. case '{':
  156. m_act[BREXIT_ID].push_back( { i, j + 1} );
  157. break;
  158. case '~':
  159. m_act[HECTO_ID].push_back( { i, j + 1} );
  160. break;
  161. case '=':
  162. m_act[SNIPER_ID].push_back( { i, j + 1} );
  163. break;
  164. default :
  165. break;
  166. }
  167. }
  168. // Détection d'un bouclier
  169. else if ( m_shape[i][j] == '(' && m_shape[i][j+1] == ')' )
  170. {
  171. m_shieldMax += SHIELD_1_EARN_HP;
  172. m_shieldLeft += SHIELD_1_EARN_HP;
  173. m_shieldDelay -= SHIELD_1_EARN_DELAY;
  174. m_shields.push_back( { i, j } );
  175. // Blocage du délai minimal
  176. if ( m_shieldDelay < SHIELD_MIN_DELAY )
  177. m_shieldDelay = SHIELD_MIN_DELAY;
  178. }
  179. // Détection d'un pointeur
  180. else if ( j < m_shW - 2 && m_shape[i][j] == '{' && m_shape[i][j+2] == '}' )
  181. {
  182. // Couleur
  183. Uint8 r(0), g(0), b(0);
  184. if ( m_shape[i][j+1] == 'y' )
  185. {
  186. b = 255;
  187. g = 255;
  188. }
  189. else if ( m_shape[i][j+1] == 'r' )
  190. {
  191. r = 255;
  192. }
  193. else if ( m_shape[i][j+1] == 'g' )
  194. {
  195. g = 255;
  196. }
  197. else if ( m_shape[i][j+1] == 'b' )
  198. {
  199. b = 255;
  200. }
  201. else
  202. {
  203. r = g = b = 255;
  204. }
  205. // Ajout du pointeur
  206. m_lasers.push_back( { i, j + 1, r, g, b, 128 } );
  207. }
  208. }
  209. }
  210. /// Inversion du vaisseau si il est allié
  211. if ( m_ally ){
  212. char sw_c;
  213. Uint8 sw_s;
  214. // Inversion des composants
  215. for ( unsigned int i(0); i < m_shH; i++ ) {
  216. for ( unsigned int j(0); j < m_shW / 2; j++ ) {
  217. sw_c = m_shape[i][j];
  218. m_shape[i][j] = m_shape[i][m_shW - j - 1];
  219. m_shape[i][m_shW - j - 1] = sw_c;
  220. sw_s = m_solid[i][j];
  221. m_solid[i][j] = m_solid[i][m_shW - j - 1];
  222. m_solid[i][m_shW - j - 1] = sw_s;
  223. }
  224. }
  225. // Inversion du cockpit
  226. m_heartX = m_shW - m_heartX - 1;
  227. // Inversion des armes
  228. for ( unsigned int i(0); i < SHOT_NB; i++) {
  229. for ( unsigned int k(0); k < m_act[i].size(); k++ ){
  230. m_act[i][k].idX = m_shW - 1 - m_act[i][k].idX;
  231. }
  232. }
  233. // Inversion des boucliers
  234. for ( unsigned int k(0); k < m_shields.size(); k++ ){
  235. m_shields[k].idX = m_shW - 1 - m_shields[k].idX;
  236. }
  237. // Inversion des boucliers
  238. for ( unsigned int k(0); k < m_lasers.size(); k++ ){
  239. m_lasers[k].idX = m_shW - 1 - m_lasers[k].idX;
  240. }
  241. // Traitement des caractères orientés
  242. for ( unsigned int i(0); i < m_shH; i++ ) {
  243. for ( unsigned int j(0); j < m_shW; j++ ) {
  244. switch ( m_shape[i][j] ){
  245. case '<':
  246. m_shape[i][j] = '>';
  247. break;
  248. case '>':
  249. m_shape[i][j] = '<';
  250. break;
  251. case ']':
  252. m_shape[i][j] = '[';
  253. break;
  254. case '[':
  255. m_shape[i][j] = ']';
  256. break;
  257. case ')':
  258. m_shape[i][j] = '(';
  259. break;
  260. case '(':
  261. m_shape[i][j] = ')';
  262. break;
  263. case '}':
  264. m_shape[i][j] = '{';
  265. break;
  266. case '{':
  267. m_shape[i][j] = '}';
  268. break;
  269. case '/':
  270. m_shape[i][j] = '\\';
  271. break;
  272. case '\\':
  273. m_shape[i][j] = '/';
  274. break;
  275. default :
  276. break;
  277. }
  278. }
  279. }
  280. }
  281. }
  282. Uint32 SpaceShip::countCPU()
  283. {
  284. Uint32 c( 0 );
  285. // CPU des blocs
  286. for ( unsigned int i(0); i < m_shH; i++ )
  287. {
  288. for ( unsigned int j(0); j < m_shW; j++ )
  289. {
  290. if ( m_shape[i][j] != ' ' )
  291. c += PART_CPU;
  292. }
  293. }
  294. // CPU des armes
  295. Uint32 weapCpu[SHOT_NB] = ACTOR_CPU;
  296. for ( unsigned int i(1); i < SHOT_NB; i++ )
  297. {
  298. c += m_act[i].size() * weapCpu[i];
  299. }
  300. // CPU des boucliers
  301. c += SHIELD_CPU * m_shields.size();
  302. // Fin
  303. return c;
  304. }
  305. bool SpaceShip::hasShield()
  306. {
  307. return m_shields.size() > 0;
  308. }
  309. bool SpaceShip::hasWeapon( int weapId )
  310. {
  311. return m_act[ weapId ].size() > 0;
  312. }
  313. void SpaceShip::draw( SDL_Surface* screen )
  314. {
  315. // N'affiche rien si déjà mort
  316. if ( !getIsAlive() )
  317. return ;
  318. // Enveloppe du bouclier
  319. Uint8 shieldLvl(128);
  320. if ( m_shieldLeft > 0 )
  321. {
  322. shieldLvl = m_shieldLeft * 255 / m_shieldMax ;
  323. for ( int i(-2); i < m_shH + 2; i++ )
  324. {
  325. stringRGBA( screen, m_pos.x - 16, m_pos.y + 8 * i, "+", 0, shieldLvl, shieldLvl, 255 );
  326. stringRGBA( screen, m_pos.x + m_pos.w + 8, m_pos.y + 8 * i, "+", 0, shieldLvl, shieldLvl, 255 );
  327. }
  328. for ( int j(-1); j <= m_shW; j++ )
  329. {
  330. stringRGBA( screen, m_pos.x + 8 * j, m_pos.y - 16, "+", 0, shieldLvl, shieldLvl, 255 );
  331. stringRGBA( screen, m_pos.x + 8 * j, m_pos.y + m_pos.h + 8, "+", 0, shieldLvl, shieldLvl, 255 );
  332. }
  333. }
  334. // Balayae du carénage
  335. for ( int i(0); i < m_shH; i++ )
  336. {
  337. for ( int j(0); j < m_shW; j++ )
  338. {
  339. // Existence d'une pièce
  340. if ( m_solid[i][j] > 0 )
  341. {
  342. char s[2];
  343. s[0] = m_shape[i][j];
  344. s[1] = 0;
  345. // Energie de bouclier disponible
  346. if ( m_shieldLeft > 0 )
  347. {
  348. stringRGBA( screen, m_pos.x + 8 * j, m_pos.y + 8 * i, s, 255 - shieldLvl, m_solid[i][j], shieldLvl, 255 );
  349. }
  350. // Affichage basique
  351. else
  352. stringRGBA( screen, m_pos.x + 8 * j, m_pos.y + 8 * i, s, 255, m_solid[i][j], m_solid[i][j], 255 );
  353. }
  354. }
  355. }
  356. // Affichage des pointeurs
  357. Sint16 u, v, c;
  358. for ( unsigned int i(0); i < m_lasers.size(); i ++ )
  359. {
  360. u = m_lasers[i].idX * 8 + m_pos.x - 9;
  361. v = m_lasers[i].idY * 8 + m_pos.y;
  362. while ( u > -8 )
  363. {
  364. stringRGBA( screen, u, v, "-", m_lasers[i].r, m_lasers[i].g, m_lasers[i].b, m_lasers[i].a );
  365. u -= 36;
  366. }
  367. }
  368. }
  369. void SpaceShip::fire( int weapId )
  370. {
  371. if ( ( SDL_GetTicks() - m_loading[weapId] ) > m_hiter->getDecay( weapId ) )
  372. {
  373. for ( unsigned int k(0); k < m_act[weapId].size(); k++ )
  374. {
  375. if ( m_solid[ m_act[weapId][k].idY ][ m_act[weapId][k].idX ] > 0 )
  376. {
  377. m_hiter->triggerWeapon( weapId, m_pos.x + 8*m_act[weapId][k].idX + 4, m_pos.y + 8*m_act[weapId][k].idY + 4, m_ally );
  378. }
  379. }
  380. m_loading[weapId] = SDL_GetTicks();
  381. }
  382. }
  383. void SpaceShip::update()
  384. {
  385. // Si le vaisseau n'est plus existant, alors rien n'existe
  386. if ( !getIsAlive() )
  387. return ;
  388. // S'il reste du bouclier, il peut absorber les dégats !
  389. if ( m_shieldLeft > 0 )
  390. {
  391. Sint32 deg( m_hiter->absorb( m_ally, m_shH, m_shW, m_pos ) );
  392. if ( deg > 0 )
  393. {
  394. // La recharge du bouclier est retardée
  395. m_shieldLast = SDL_GetTicks();
  396. // Le bouclier en prend un coup
  397. if ( deg > m_shieldLeft )
  398. m_shieldLeft = 0;
  399. else
  400. m_shieldLeft -= deg;
  401. }
  402. }
  403. // S'il reste un carénage, il peut subir des dégâts !
  404. else if ( m_hiter->colide( m_ally, m_solid, m_shH, m_shW, m_pos ) )
  405. {
  406. // La recharge du bouclier est retardée
  407. m_shieldLast = SDL_GetTicks();
  408. // Peut être que certains blocs ne sont plus attachés au vaisseau !
  409. integrity();
  410. // Certains boucliers sont peut être hors service !
  411. if ( m_shieldMax > 0 )
  412. resetShields();
  413. }
  414. // Recharge éventuelle du bouclier
  415. if ( m_shieldLeft < m_shieldMax && ( SDL_GetTicks() - m_shieldLast > m_shieldDelay ) )
  416. {
  417. m_shieldLeft += SHIELD_REGEN ;
  418. if ( m_shieldLeft > m_shieldMax ) m_shieldLeft = m_shieldMax ;
  419. }
  420. }
  421. void SpaceShip::destroyTabs()
  422. {
  423. // Destruction du modèle graphic
  424. if ( m_shape != 0x0 )
  425. {
  426. for ( int i(0); i < m_shH; i++ ) {
  427. delete[] m_shape[i];
  428. m_shape[i] = 0x0;
  429. }
  430. delete[] m_shape;
  431. m_shape = 0x0;
  432. }
  433. // Destruction de la carte du blindage
  434. if ( m_solid != 0x0 )
  435. {
  436. for ( int i(0); i < m_shH; i++ ) {
  437. delete[] m_solid[i];
  438. m_solid[i] = 0x0;
  439. }
  440. delete[] m_solid;
  441. m_solid = 0x0;
  442. }
  443. // Destruction des armes
  444. for ( unsigned int i(0); i < SHOT_NB; i++ )
  445. {
  446. m_act[i].clear();
  447. }
  448. // Destruction du bouclier
  449. m_shields.clear();
  450. // Destruction des pointeurs
  451. m_lasers.clear();
  452. }
  453. void SpaceShip::integrity()
  454. {
  455. // Création du tableau des liens
  456. Sint8 network[ m_shH ][ m_shW ];
  457. for ( int i(0); i < m_shH; i++ )
  458. {
  459. for ( int j(0); j < m_shW; j++ )
  460. {
  461. network[i][j] = -1;
  462. }
  463. }
  464. // Création du réseau
  465. if ( getIsAlive() )
  466. {
  467. network[ m_heartY ][ m_heartX ] = 1;
  468. std::queue<Actor> q; // Couples à tester
  469. Uint16 y, x;
  470. if ( m_heartY > 0 ) q.push( { m_heartY - 1, m_heartX } );
  471. if ( m_heartX > 0 ) q.push( { m_heartY, m_heartX - 1 } );
  472. if ( m_heartY + 1 < m_shH ) q.push( { m_heartY + 1, m_heartX } );
  473. if ( m_heartX + 1 < m_shW ) q.push( { m_heartY, m_heartX + 1} );
  474. while ( !q.empty() )
  475. {
  476. y = q.front().idY;
  477. x = q.front().idX;
  478. if ( m_solid[ y ][ x ] == 0 )
  479. {
  480. // Bloc détruit
  481. network[ y ][ x ] = 0;
  482. }
  483. else if ( ( y > 0 && network[ y - 1 ][ x ] == 1 ) // Haut
  484. || ( y < m_shH - 1 && network[ y + 1 ][ x ] == 1 ) // Bas
  485. || ( x > 0 && network[ y ][ x - 1 ] == 1 ) // Gauche
  486. || ( x < m_shW - 1 && network[ y ][ x + 1 ] == 1 ) ) // Droite
  487. {
  488. // Bloc présent
  489. network[ y ][ x ] = 1;
  490. // Connexion des blocs adjacents
  491. if ( y > 0 && network[ y - 1 ][ x ] == -1 )// Haut
  492. q.push( { y - 1, x } );
  493. if ( y < m_shH - 1 && network[ y + 1 ][ x ] == -1 )// Bas
  494. q.push( { y + 1, x } );
  495. if ( x > 0 && network[ y ][ x - 1 ] == -1 )// Gauche
  496. q.push( { y, x - 1 } );
  497. if ( x < m_shW - 1 && network[ y ][ x + 1 ] == -1 )// Doite
  498. q.push( { y, x + 1 } );
  499. }
  500. else
  501. {
  502. // Bloc non connecté
  503. network[ y ][ x ] = 0;
  504. }
  505. q.pop();
  506. }
  507. }
  508. // Destruction des pièces non connectées
  509. for ( int i(0); i < m_shH; i++ )
  510. {
  511. for ( int j(0); j < m_shW; j++ )
  512. {
  513. if ( m_solid[i][j] > 0 && network[i][j] == -1 ) {
  514. Sint16 vx( j - m_heartX );
  515. Sint16 vy( i - m_heartY );
  516. m_hiter->addShot( new Part( m_pos.x + j*8, m_pos.y + i*8, vx, vy, m_solid[i][j], m_shape[i][j], m_ally ) );
  517. m_solid[i][j] = 0;
  518. }
  519. }
  520. }
  521. }
  522. void SpaceShip::resetShields()
  523. {
  524. m_shieldDelay = SHIELD_MAX_DELAY;
  525. m_shieldMax = 0;
  526. for ( unsigned int k(0); k < m_shields.size(); k++ )
  527. {
  528. if ( m_solid[ m_shields[k].idY ][ m_shields[k].idX ] > 0 )
  529. {
  530. m_shieldDelay -= SHIELD_1_EARN_DELAY;
  531. m_shieldMax += SHIELD_1_EARN_HP;
  532. }
  533. }
  534. if ( m_shieldLeft > m_shieldMax )
  535. m_shieldLeft = m_shieldMax;
  536. if ( m_shieldDelay < SHIELD_MIN_DELAY )
  537. m_shieldDelay = SHIELD_MIN_DELAY;
  538. }