Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

1755 lines
47KB

  1. /******************************************************************************/
  2. /* */
  3. /* PACMAN GAME FOR ARDUINO DUE */
  4. /* */
  5. /******************************************************************************/
  6. /* Copyright (c) 2014 Dr. NCX (mirracle.mxx@gmail.com) */
  7. /* */
  8. /* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL */
  9. /* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED */
  10. /* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR */
  11. /* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES */
  12. /* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, */
  13. /* WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
  14. /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS */
  15. /* SOFTWARE. */
  16. /* */
  17. /* MIT license, all text above must be included in any redistribution. */
  18. /******************************************************************************/
  19. /* ILI9341: */
  20. /*----------------------------------------------------------------------------*/
  21. /* 8 = RST */
  22. /* 9 = D/C */
  23. /* 10 = CS */
  24. /* */
  25. /*----------------------------------------------------------------------------*/
  26. /* VGA: */
  27. /*----------------------------------------------------------------------------*/
  28. /* 41 = R --[470R]-- } */
  29. /* 40 = R --[ 1K ]-- } = VGA 1 (RED) */
  30. /* 39 = R --[ 2K2]-- } */
  31. /* */
  32. /* 38 = G --[470R]-- } */
  33. /* 37 = G --[ 1K ]-- } = VGA 2 (GREEN) */
  34. /* 36 = G --[ 2K2]-- } */
  35. /* */
  36. /* 35 = B --[390R]-- } = VGA 3 (BLUE) */
  37. /* 34 = B --[820R]-- } */
  38. /* */
  39. /* 43 = Hsync --[ 82R]-- = VGA 13 */
  40. /* 42 = Vsync --[ 82R]-- = VGA 14 */
  41. /* */
  42. /*----------------------------------------------------------------------------*/
  43. /* KEYPAD: */
  44. /*----------------------------------------------------------------------------*/
  45. /* 38 = button START */
  46. /* 40 = button SELECT */
  47. /* 44 = button A */
  48. /* 42 = button B */
  49. /* 52 = button UP */
  50. /* 50 = button DOWN */
  51. /* 48 = button LEFT */
  52. /* 46 = button RIGHT */
  53. /* */
  54. /******************************************************************************/
  55. #define USE_ILI // For ILI9341 leave uncommented
  56. #include <ILI9341_t3n.h>
  57. byte SPEED = 2; // 1=SLOW 2=NORMAL 4=FAST //do not try other values!!!
  58. /******************************************************************************/
  59. /* MAIN GAME VARIABLES */
  60. /******************************************************************************/
  61. #define BONUS_INACTIVE_TIME 600
  62. #define BONUS_ACTIVE_TIME 300
  63. #define START_LIFES 2
  64. #define START_LEVEL 1
  65. byte MAXLIFES = 5;
  66. byte LIFES = START_LIFES;
  67. byte GAMEWIN = 0;
  68. byte GAMEOVER = 0;
  69. byte DEMO = 1;
  70. byte LEVEL = START_LEVEL;
  71. byte ACTUALBONUS = 0; //actual bonus icon
  72. byte ACTIVEBONUS = 0; //status of bonus
  73. byte GAMEPAUSED = 0;
  74. byte PACMANFALLBACK = 0;
  75. /******************************************************************************/
  76. /* LIBRARIES INCLUDES */
  77. /******************************************************************************/
  78. //Library for Gamepad
  79. #include <USBHost_t36.h>
  80. USBHost myusb;
  81. USBHub hub1(myusb);
  82. USBHIDParser hid1(myusb);
  83. JoystickController joystick1(myusb);
  84. //BluetoothController bluet(myusb, true, "0000"); // Version does pairing to device
  85. BluetoothController bluet(myusb); // version assumes it already was paired
  86. USBDriver *drivers[] = {&hub1, &joystick1, &bluet, &hid1};
  87. #define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0]))
  88. const char * driver_names[CNT_DEVICES] = {"Hub1", "JOY1D", "Bluet", "HID1"};
  89. bool driver_active[CNT_DEVICES] = {false, false, false, false};
  90. // Lets also look at HID Input devices
  91. USBHIDInput *hiddrivers[] = {&joystick1};
  92. bool hid_driver_active[CNT_DEVICES] = {false, false, false};
  93. bool show_changed_only = false;
  94. bool show_raw_data = false;
  95. bool show_changed_data = false;
  96. uint32_t buttons;
  97. int psAxis[64];
  98. bool first_joystick_message = true;
  99. uint8_t last_bdaddr[6] = {0, 0, 0, 0, 0, 0};
  100. /* END JOYSTICK DEFINES */
  101. // SPI Library
  102. #include <SPI.h>
  103. // ILI9341_due NEW lib by Marek Buriak http://marekburiak.github.io/ILI9341_due/
  104. #include "ILI9341_due_config.h"
  105. // Connection konfiguration of ILI9341 LCD TFT
  106. #define TFT_RST 8
  107. #define TFT_DC 10
  108. #define TFT_CS 9
  109. ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST);
  110. /******************************************************************************/
  111. /* Controll KEYPAD LOOP */
  112. /******************************************************************************/
  113. boolean but_START = false; //38 //8, 168
  114. boolean but_SELECT = false; //40 //1 , 328
  115. boolean but_A = false; //44 //32768 sqr, 262152
  116. boolean but_B = false; //42 //8192 circ,
  117. boolean but_UP = false; //52 //16, 0
  118. boolean but_DOWN = false; //50 //64, 4
  119. boolean but_LEFT = false; //48 //128, 6
  120. boolean but_RIGHT = false; //46 //32, 2
  121. void ClearKeys() {
  122. but_START = false;
  123. but_SELECT = false;
  124. but_A = false;
  125. but_B = false;
  126. but_UP = false;
  127. but_DOWN = false;
  128. but_LEFT = false;
  129. but_RIGHT = false;
  130. }
  131. void KeyPadLoop() {
  132. buttons = joystick1.getButtons();
  133. Serial.println(buttons);
  134. switch (joystick1.joystickType()) {
  135. case JoystickController::UNKNOWN:
  136. case JoystickController::PS4:
  137. {
  138. if (buttons == 168 ) {
  139. ClearKeys(); //else but_START=false;
  140. but_START = true;
  141. delay(300);
  142. }
  143. if (buttons == 328 ) {
  144. ClearKeys();
  145. but_SELECT = true;
  146. delay(300);
  147. } else but_SELECT = false;
  148. if (buttons == 262152 ) {
  149. ClearKeys();
  150. but_A = true;
  151. } else but_A = false;
  152. if (buttons == 262152) {
  153. ClearKeys();
  154. but_B = true;
  155. } else but_B = false;
  156. if (buttons == 0) {
  157. ClearKeys(); //else but_UP=false;
  158. but_UP = true;
  159. }
  160. if (buttons == 4) {
  161. ClearKeys(); //else but_DOWN=false;
  162. but_DOWN = true;
  163. }
  164. if (buttons == 6) {
  165. ClearKeys(); // else but_LEFT=false;
  166. but_LEFT = true;
  167. }
  168. if (buttons == 2) {
  169. ClearKeys(); //else but_RIGHT=false;
  170. but_RIGHT = true;
  171. }
  172. }
  173. break;
  174. case JoystickController::PS3:
  175. {
  176. if (buttons == 8 ) {
  177. ClearKeys(); //else but_START=false;
  178. but_START = true;
  179. delay(300);
  180. }
  181. if (buttons == 1 ) {
  182. ClearKeys();
  183. but_SELECT = true;
  184. delay(300);
  185. } else but_SELECT = false;
  186. if (buttons == 32768 ) {
  187. ClearKeys();
  188. but_A = true;
  189. } else but_A = false;
  190. if (buttons == 8192) {
  191. ClearKeys();
  192. but_B = true;
  193. } else but_B = false;
  194. if (buttons == 16) {
  195. ClearKeys(); //else but_UP=false;
  196. but_UP = true;
  197. }
  198. if (buttons == 64) {
  199. ClearKeys(); //else but_DOWN=false;
  200. but_DOWN = true;
  201. }
  202. if (buttons == 128) {
  203. ClearKeys(); // else but_LEFT=false;
  204. but_LEFT = true;
  205. }
  206. if (buttons == 32) {
  207. ClearKeys(); //else but_RIGHT=false;
  208. but_RIGHT = true;
  209. }
  210. }
  211. break;
  212. default:
  213. break;
  214. }
  215. yield();
  216. }
  217. /******************************************************************************/
  218. /* GAME VARIABLES AND DEFINITIONS */
  219. /******************************************************************************/
  220. #include "PacmanTiles.h"
  221. enum GameState {
  222. ReadyState,
  223. PlayState,
  224. DeadGhostState, // Player got a ghost, show score sprite and only move eyes
  225. DeadPlayerState,
  226. EndLevelState
  227. };
  228. enum SpriteState
  229. {
  230. PenState,
  231. RunState,
  232. FrightenedState,
  233. DeadNumberState,
  234. DeadEyesState,
  235. AteDotState, // pacman
  236. DeadPacmanState
  237. };
  238. enum {
  239. MStopped = 0,
  240. MRight = 1,
  241. MDown = 2,
  242. MLeft = 3,
  243. MUp = 4,
  244. };
  245. #define ushort uint16_t
  246. #define C16(_rr,_gg,_bb) (((ushort)(((_rr & 0xE0)) | ((_gg & 0xE0) >> 3) | ((_bb & 0xC0) >> 6)) <<8 ))
  247. // 8 bit palette for ILI9341
  248. uint16_t _paletteW[] =
  249. {
  250. C16(0, 0, 0),
  251. C16(255, 0, 0), // 1 red
  252. C16(222, 151, 81), // 2 brown
  253. C16(255, 0, 255), // 3 pink
  254. C16(0, 0, 0),
  255. C16(0, 255, 255), // 5 cyan
  256. C16(71, 84, 255), // 6 mid blue
  257. C16(255, 184, 81), // 7 lt brown
  258. C16(0, 0, 0),
  259. C16(255, 255, 0), // 9 yellow
  260. C16(0, 0, 0),
  261. C16(33, 33, 255), // 11 blue
  262. C16(0, 255, 0), // 12 green
  263. C16(71, 84, 174), // 13 aqua
  264. C16(255, 184, 174), // 14 lt pink
  265. C16(222, 222, 255), // 15 whiteish
  266. };
  267. #define BINKY 0
  268. #define PINKY 1
  269. #define INKY 2
  270. #define CLYDE 3
  271. #define PACMAN 4
  272. #define BONUS 5
  273. const byte _initSprites[] =
  274. {
  275. BINKY, 14, 17 - 3, 31, MLeft,
  276. PINKY, 14 - 2, 17, 79, MLeft,
  277. INKY, 14, 17, 137, MLeft,
  278. CLYDE, 14 + 2, 17, 203, MRight,
  279. PACMAN, 14, 17 + 9, 0, MLeft,
  280. BONUS, 14, 17 + 3, 0, MLeft,
  281. };
  282. // Ghost colors
  283. const byte _palette2[] =
  284. {
  285. 0, 11, 1, 15, // BINKY red
  286. 0, 11, 3, 15, // PINKY pink
  287. 0, 11, 5, 15, // INKY cyan
  288. 0, 11, 7, 15, // CLYDE brown
  289. 0, 11, 9, 9, // PACMAN yellow
  290. 0, 11, 15, 15, // FRIGHTENED
  291. 0, 11, 0, 15, // DEADEYES
  292. 0, 1, 15, 2, // cherry
  293. 0, 1, 15, 12, // strawberry
  294. 0, 7, 2, 12, // peach
  295. 0, 9, 15, 0, // bell
  296. 0, 15, 1, 2, // apple
  297. 0, 12, 15, 5, // grape
  298. 0, 11, 9, 1, // galaxian
  299. 0, 5, 15, 15, // key
  300. };
  301. const byte _paletteIcon2[] =
  302. {
  303. 0, 9, 9, 9, // PACMAN
  304. 0, 2, 15, 1, // cherry
  305. 0, 12, 15, 1, // strawberry
  306. 0, 12, 2, 7, // peach
  307. 0, 0, 15, 9, // bell
  308. 0, 2, 15, 1, // apple
  309. 0, 12, 15, 5, // grape
  310. 0, 1, 9, 11, // galaxian
  311. 0, 5, 15, 15, // key
  312. };
  313. #define PACMANICON 1
  314. #define BONUSICON 2
  315. #define FRIGHTENEDPALETTE 5
  316. #define DEADEYESPALETTE 6
  317. #define BONUSPALETTE 7
  318. #define FPS 60
  319. #define CHASE 0
  320. #define SCATTER 1
  321. #define DOT 7
  322. #define PILL 14
  323. #define PENGATE 0x1B
  324. const byte _opposite[] = { MStopped, MLeft, MUp, MRight, MDown };
  325. #define OppositeDirection(_x) pgm_read_byte(_opposite + _x)
  326. const byte _scatterChase[] = { 7, 20, 7, 20, 5, 20, 5, 0 };
  327. const byte _scatterTargets[] = { 2, 0, 25, 0, 0, 35, 27, 35 }; // inky/clyde scatter targets are backwards
  328. const char _pinkyTargetOffset[] = { 4, 0, 0, 4, -4, 0, -4, 4 }; // Includes pinky target bug
  329. #define FRIGHTENEDGHOSTSPRITE 0
  330. #define GHOSTSPRITE 2
  331. #define NUMBERSPRITE 10
  332. #define PACMANSPRITE 14
  333. const byte _pacLeftAnim[] = { 5, 6, 5, 4 };
  334. const byte _pacRightAnim[] = { 2, 0, 2, 4 };
  335. const byte _pacVAnim[] = { 4, 3, 1, 3 };
  336. word _BonusInactiveTimmer = BONUS_INACTIVE_TIME;
  337. word _BonusActiveTimmer = 0;
  338. /******************************************************************************/
  339. /* GAME - Sprite Class */
  340. /******************************************************************************/
  341. class Sprite
  342. {
  343. public:
  344. int16_t _x, _y;
  345. int16_t lastx, lasty;
  346. byte cx, cy; // cell x and y
  347. byte tx, ty; // target x and y
  348. SpriteState state;
  349. byte pentimer; // could be the same
  350. byte who;
  351. byte _speed;
  352. byte dir;
  353. byte phase;
  354. // Sprite bits
  355. byte palette2; // 4->16 color map index
  356. byte bits; // index of sprite bits
  357. signed char sy;
  358. void Init(const byte* s)
  359. {
  360. who = pgm_read_byte(s++);
  361. cx = pgm_read_byte(s++);
  362. cy = pgm_read_byte(s++);
  363. pentimer = pgm_read_byte(s++);
  364. dir = pgm_read_byte(s);
  365. _x = lastx = (int16_t)cx * 8 - 4;
  366. _y = lasty = (int16_t)cy * 8;
  367. state = PenState;
  368. _speed = 0;
  369. Target(random(20), random(20));
  370. }
  371. void Target(byte x, byte y)
  372. {
  373. tx = x;
  374. ty = y;
  375. }
  376. int16_t Distance(byte x, byte y)
  377. {
  378. int16_t dx = cx - x;
  379. int16_t dy = cy - y;
  380. return dx * dx + dy * dy; // Distance to target
  381. }
  382. // once per sprite, not 9 times
  383. void SetupDraw(GameState gameState, byte deadGhostIndex)
  384. {
  385. sy = 1;
  386. palette2 = who;
  387. byte p = phase >> 3;
  388. if (who == BONUS) {
  389. //BONUS ICONS
  390. bits = 21 + ACTUALBONUS;
  391. palette2 = BONUSPALETTE + ACTUALBONUS;
  392. return;
  393. }
  394. if (who != PACMAN)
  395. {
  396. bits = GHOSTSPRITE + ((dir - 1) << 1) + (p & 1); // Ghosts
  397. switch (state)
  398. {
  399. case FrightenedState:
  400. bits = FRIGHTENEDGHOSTSPRITE + (p & 1); // frightened
  401. palette2 = FRIGHTENEDPALETTE;
  402. break;
  403. case DeadNumberState:
  404. palette2 = FRIGHTENEDPALETTE;
  405. bits = NUMBERSPRITE + deadGhostIndex;
  406. break;
  407. case DeadEyesState:
  408. palette2 = DEADEYESPALETTE;
  409. break;
  410. default:
  411. ;
  412. }
  413. return;
  414. }
  415. // PACMAN animation
  416. byte f = (phase >> 1) & 3;
  417. if (dir == MLeft)
  418. f = pgm_read_byte(_pacLeftAnim + f);
  419. else if (dir == MRight)
  420. f = pgm_read_byte(_pacRightAnim + f);
  421. else
  422. f = pgm_read_byte(_pacVAnim + f);
  423. if (dir == MUp)
  424. sy = -1;
  425. bits = f + PACMANSPRITE;
  426. }
  427. // Draw this sprite into the tile at x,y
  428. void Draw8(int16_t x, int16_t y, byte* tile)
  429. {
  430. int16_t px = x - (_x - 4);
  431. if (px <= -8 || px >= 16) return;
  432. int16_t py = y - (_y - 4);
  433. if (py <= -8 || py >= 16) return;
  434. // Clip y
  435. int16_t lines = py + 8;
  436. if (lines > 16)
  437. lines = 16;
  438. if (py < 0)
  439. {
  440. tile -= py * 8;
  441. py = 0;
  442. }
  443. lines -= py;
  444. // Clip in X
  445. byte right = 16 - px;
  446. if (right > 8)
  447. right = 8;
  448. byte left = 0;
  449. if (px < 0)
  450. {
  451. left = -px;
  452. px = 0;
  453. }
  454. // Get bitmap
  455. signed char dy = sy;
  456. if (dy < 0)
  457. py = 15 - py; // VFlip
  458. byte* data = (byte*)(pacman16x16 + bits * 64);
  459. data += py << 2;
  460. dy <<= 2;
  461. data += px >> 2;
  462. px &= 3;
  463. const byte* palette = _palette2 + (palette2 << 2);
  464. while (lines)
  465. {
  466. const byte *src = data;
  467. byte d = pgm_read_byte(src++);
  468. d >>= px << 1;
  469. byte sx = 4 - px;
  470. byte x = left;
  471. do
  472. {
  473. byte p = d & 3;
  474. if (p)
  475. {
  476. p = pgm_read_byte(palette + p);
  477. if (p)
  478. tile[x] = p;
  479. }
  480. d >>= 2; // Next pixel
  481. if (!--sx)
  482. {
  483. d = pgm_read_byte(src++);
  484. sx = 4;
  485. }
  486. } while (++x < right);
  487. tile += 8;
  488. data += dy;
  489. lines--;
  490. }
  491. }
  492. };
  493. /******************************************************************************/
  494. /* GAME - Playfield Class */
  495. /******************************************************************************/
  496. class Playfield
  497. {
  498. Sprite _sprites[5];
  499. Sprite _BonusSprite; //Bonus
  500. byte _dotMap[(32 / 4) * (36 - 6)];
  501. GameState _state;
  502. long _score; // 7 digits of score
  503. long _hiscore; // 7 digits of score
  504. long _lifescore;
  505. signed char _scoreStr[8];
  506. signed char _hiscoreStr[8];
  507. byte _icons[14]; // Along bottom of screen
  508. ushort _stateTimer;
  509. ushort _frightenedTimer;
  510. byte _frightenedCount;
  511. byte _scIndex; //
  512. ushort _scTimer; // next change of sc status
  513. bool _inited;
  514. byte* _dirty;
  515. public:
  516. Playfield() : _inited(false)
  517. {
  518. // Swizzle palette TODO just fix in place
  519. byte * p = (byte*)_paletteW;
  520. for (int16_t i = 0; i < 16; i++)
  521. {
  522. ushort w = _paletteW[i]; // Swizzle
  523. *p++ = w >> 8;
  524. *p++ = w;
  525. }
  526. }
  527. // Draw 2 bit BG into 8 bit icon tiles at bottom
  528. void DrawBG2(byte cx, byte cy, byte* tile)
  529. {
  530. byte index = 0;
  531. signed char b = 0;
  532. index = _icons[cx >> 1]; // 13 icons across bottom
  533. if (index == 0)
  534. {
  535. memset(tile, 0, 64);
  536. return;
  537. }
  538. index--;
  539. index <<= 2; // 4 tiles per icon
  540. b = (1 - (cx & 1)) + ((cy & 1) << 1); // Index of tile
  541. const byte* bg = pacman8x8x2 + ((b + index) << 4);
  542. const byte* palette = _paletteIcon2 + index;
  543. byte x = 16;
  544. while (x--)
  545. {
  546. byte bits = (signed char)pgm_read_byte(bg++);
  547. byte i = 4;
  548. while (i--)
  549. {
  550. tile[i] = pgm_read_byte(palette + (bits & 3));
  551. bits >>= 2;
  552. }
  553. tile += 4;
  554. }
  555. }
  556. byte GetTile(int16_t cx, int16_t ty)
  557. {
  558. if (_state != ReadyState && ty == 20 && cx > 10 && cx < 17) return (0); //READY TEXT ZONE
  559. if (LEVEL % 5 == 1) return pgm_read_byte(playMap1 + ty * 28 + cx);
  560. if (LEVEL % 5 == 2) return pgm_read_byte(playMap2 + ty * 28 + cx);
  561. if (LEVEL % 5 == 3) return pgm_read_byte(playMap3 + ty * 28 + cx);
  562. if (LEVEL % 5 == 4) return pgm_read_byte(playMap4 + ty * 28 + cx);
  563. if (LEVEL % 5 == 0) return pgm_read_byte(playMap5 + ty * 28 + cx);
  564. }
  565. // Draw 1 bit BG into 8 bit tile
  566. void DrawBG(byte cx, byte cy, byte* tile)
  567. {
  568. if (cy >= 34) //DRAW ICONS BELLOW MAZE
  569. {
  570. DrawBG2(cx, cy, tile);
  571. return;
  572. }
  573. byte c = 11;
  574. if (LEVEL % 8 == 1) c = 11; // Blue
  575. if (LEVEL % 8 == 2) c = 12; // Green
  576. if (LEVEL % 8 == 3) c = 1; // Red
  577. if (LEVEL % 8 == 4) c = 9; // Yellow
  578. if (LEVEL % 8 == 5) c = 2; // Brown
  579. if (LEVEL % 8 == 6) c = 5; // Cyan
  580. if (LEVEL % 8 == 7) c = 3; // Pink
  581. if (LEVEL % 8 == 0) c = 15; // White
  582. byte b = GetTile(cx, cy);
  583. const byte* bg;
  584. // This is a little messy
  585. memset(tile, 0, 64);
  586. if (cy == 20 && cx >= 11 && cx < 17)
  587. {
  588. if (DEMO == 1 && ACTIVEBONUS == 1) return;
  589. if ((_state != ReadyState && GAMEPAUSED != 1 && DEMO != 1) || ACTIVEBONUS == 1) b = 0; // hide 'READY!'
  590. else if (DEMO == 1 && cx == 11) b = 0;
  591. else if (DEMO == 1 && cx == 12) b = 'D';
  592. else if (DEMO == 1 && cx == 13) b = 'E';
  593. else if (DEMO == 1 && cx == 14) b = 'M';
  594. else if (DEMO == 1 && cx == 15) b = 'O';
  595. else if (DEMO == 1 && cx == 16) b = 0;
  596. else if (GAMEPAUSED == 1 && cx == 11) b = 'P';
  597. else if (GAMEPAUSED == 1 && cx == 12) b = 'A';
  598. else if (GAMEPAUSED == 1 && cx == 13) b = 'U';
  599. else if (GAMEPAUSED == 1 && cx == 14) b = 'S';
  600. else if (GAMEPAUSED == 1 && cx == 15) b = 'E';
  601. else if (GAMEPAUSED == 1 && cx == 16) b = 'D';
  602. }
  603. else if (cy == 1)
  604. {
  605. if (cx < 7)
  606. b = _scoreStr[cx];
  607. else if (cx >= 10 && cx < 17)
  608. b = _hiscoreStr[cx - 10]; // HiScore
  609. } else {
  610. if (b == DOT || b == PILL) // DOT==7 or PILL==16
  611. {
  612. if (!GetDot(cx, cy))
  613. return;
  614. c = 14;
  615. }
  616. if (b == PENGATE)
  617. c = 14;
  618. }
  619. bg = playTiles + (b << 3);
  620. if (b >= '0')
  621. c = 15; // text is white
  622. for (byte y = 0; y < 8; y++)
  623. {
  624. signed char bits = (signed char)pgm_read_byte(bg++); ///WARNING CHAR MUST BE signed !!!
  625. byte x = 0;
  626. while (bits)
  627. {
  628. if (bits < 0)
  629. tile[x] = c;
  630. bits <<= 1;
  631. x++;
  632. }
  633. tile += 8;
  634. }
  635. }
  636. // Draw BG then all sprites in this cell
  637. void Draw(uint16_t x, uint16_t y, bool sprites)
  638. {
  639. byte tile[8 * 8];
  640. // Fill with BG
  641. if (y == 20 && x >= 11 && x < 17 && DEMO == 1 && ACTIVEBONUS == 1) return;
  642. DrawBG(x, y, tile);
  643. // Overlay sprites
  644. x <<= 3;
  645. y <<= 3;
  646. if (sprites)
  647. {
  648. for (byte i = 0; i < 5; i++)
  649. _sprites[i].Draw8(x, y, tile);
  650. //AND BONUS
  651. if (ACTIVEBONUS) _BonusSprite.Draw8(x, y, tile);
  652. }
  653. // Show sprite block
  654. #if 0
  655. for (byte i = 0; i < 5; i++)
  656. {
  657. Sprite* s = _sprites + i;
  658. if (s->cx == (x >> 3) && s->cy == (y >> 3))
  659. {
  660. memset(tile, 0, 8);
  661. for (byte j = 1; j < 7; j++)
  662. tile[j * 8] = tile[j * 8 + 7] = 0;
  663. memset(tile + 56, 0, 8);
  664. }
  665. }
  666. #endif
  667. x += (240 - 224) / 2;
  668. y += (320 - 288) / 2;
  669. // Should be a direct Graphics call
  670. byte n = tile[0];
  671. byte i = 0;
  672. word color = (word)_paletteW[n];
  673. //------------------------------------------------------------------------------
  674. #ifdef USE_ILI
  675. drawIndexedmap(tile, x, y, 8, 8); // Call Custom function in ILI9341_DUE.h library
  676. #endif
  677. //------------------------------------------------------------------------------
  678. #ifdef USE_VGA
  679. for (byte tmpY = 0; tmpY < 8; tmpY++) {
  680. word width = 1;
  681. for (byte tmpX = 0; tmpX < 8; tmpX++) {
  682. n = tile[++i];
  683. word next_color = (word)_paletteW[n];
  684. if (x + tmpX > 224 + (240 - 224) / 2) {
  685. break;
  686. }
  687. if (tmpX == 7 && width == 1 ) {
  688. VGA.drawPixel(x + tmpX, y + tmpY, color);
  689. color = next_color;
  690. width = 0;
  691. }
  692. else if (tmpX == 7 && width > 1 ) {
  693. VGA.drawHLine( y + tmpY, x + tmpX - width + 1, x + tmpX + 1, color);
  694. color = next_color;
  695. width = 0;
  696. }
  697. else if (color != next_color && width == 1) {
  698. VGA.drawPixel(x + tmpX, y + tmpY, color);
  699. color = next_color;
  700. width = 0;
  701. }
  702. else if (color != next_color && width > 1) {
  703. VGA.drawHLine( y + tmpY, x + tmpX - width + 1, x + tmpX + 1, color);
  704. color = next_color;
  705. width = 0;
  706. }
  707. width++;
  708. }
  709. }
  710. #endif
  711. //------------------------------------------------------------------------------
  712. }
  713. boolean updateMap [36][28];
  714. // Mark tile as dirty (should not need range checking here)
  715. void Mark(int16_t x, int16_t y, byte* m)
  716. {
  717. x -= 4;
  718. y -= 4;
  719. updateMap[(y >> 3)][(x >> 3)] = true;
  720. updateMap[(y >> 3)][(x >> 3) + 1] = true;
  721. updateMap[(y >> 3)][(x >> 3) + 2] = true;
  722. updateMap[(y >> 3) + 1][(x >> 3)] = true;
  723. updateMap[(y >> 3) + 1][(x >> 3) + 1] = true;
  724. updateMap[(y >> 3) + 1][(x >> 3) + 2] = true;
  725. updateMap[(y >> 3) + 2][(x >> 3)] = true;
  726. updateMap[(y >> 3) + 2][(x >> 3) + 1] = true;
  727. updateMap[(y >> 3) + 2][(x >> 3) + 2] = true;
  728. }
  729. void DrawAllBG()
  730. {
  731. for (byte y = 0; y < 36; y++)
  732. for (byte x = 0; x < 28; x++) {
  733. Draw(x, y, false);
  734. }
  735. }
  736. // Draw sprites overlayed on cells
  737. void DrawAll()
  738. {
  739. byte* m = _dirty;
  740. // Mark sprite old/new positions as dirty
  741. for (byte i = 0; i < 5; i++)
  742. {
  743. Sprite* s = _sprites + i;
  744. Mark(s->lastx, s->lasty, m);
  745. Mark(s->_x, s->_y, m);
  746. }
  747. // Mark BONUS sprite old/new positions as dirty
  748. Sprite* _s = &_BonusSprite;
  749. Mark(_s->lastx, _s->lasty, m);
  750. Mark(_s->_x, _s->_y, m);
  751. // Animation
  752. for (byte i = 0; i < 5; i++)
  753. _sprites[i].SetupDraw(_state, _frightenedCount - 1);
  754. _BonusSprite.SetupDraw(_state, _frightenedCount - 1);
  755. for (byte tmpY = 0; tmpY < 36; tmpY++) {
  756. for (byte tmpX = 0; tmpX < 28; tmpX++) {
  757. if (updateMap[tmpY][tmpX] == true) Draw(tmpX, tmpY, true);
  758. updateMap[tmpY][tmpX] = false;
  759. }
  760. }
  761. }
  762. int16_t Chase(Sprite* s, int16_t cx, int16_t cy)
  763. {
  764. while (cx < 0) // Tunneling
  765. cx += 28;
  766. while (cx >= 28)
  767. cx -= 28;
  768. byte t = GetTile(cx, cy);
  769. if (!(t == 0 || t == DOT || t == PILL || t == PENGATE))
  770. return 0x7FFF;
  771. if (t == PENGATE)
  772. {
  773. if (s->who == PACMAN)
  774. return 0x7FFF; // Pacman can't cross this to enter pen
  775. if (!(InPen(s->cx, s->cy) || s->state == DeadEyesState))
  776. return 0x7FFF; // Can cross if dead or in pen trying to get out
  777. }
  778. int16_t dx = s->tx - cx;
  779. int16_t dy = s->ty - cy;
  780. return (dx * dx + dy * dy); // Distance to target
  781. }
  782. void UpdateTimers()
  783. {
  784. // Update scatter/chase selector, low bit of index indicates scatter
  785. if (_scIndex < 8)
  786. {
  787. if (_scTimer-- == 0)
  788. {
  789. byte duration = pgm_read_byte(_scatterChase + _scIndex++);
  790. _scTimer = duration * FPS;
  791. }
  792. }
  793. // BONUS timmer
  794. if (ACTIVEBONUS == 0 && _BonusInactiveTimmer-- == 0) {
  795. _BonusActiveTimmer = BONUS_ACTIVE_TIME; //5*FPS;
  796. ACTIVEBONUS = 1;
  797. }
  798. if (ACTIVEBONUS == 1 && _BonusActiveTimmer-- == 0) {
  799. _BonusInactiveTimmer = BONUS_INACTIVE_TIME; //10*FPS;
  800. ACTIVEBONUS = 0;
  801. }
  802. // Release frightened ghosts
  803. if (_frightenedTimer && !--_frightenedTimer)
  804. {
  805. for (byte i = 0; i < 4; i++)
  806. {
  807. Sprite* s = _sprites + i;
  808. if (s->state == FrightenedState)
  809. {
  810. s->state = RunState;
  811. s->dir = OppositeDirection(s->dir);
  812. }
  813. }
  814. }
  815. }
  816. // Target closes pill, run from ghosts?
  817. void PacmanAI()
  818. {
  819. Sprite* pacman;
  820. pacman = _sprites + PACMAN;
  821. // Chase frightened ghosts
  822. Sprite* closestGhost = NULL;
  823. Sprite* frightenedGhost = NULL;
  824. Sprite* closestAttackingGhost = NULL;
  825. Sprite* DeadEyesStateGhost = NULL;
  826. int16_t dist = 0x7FFF;
  827. int16_t closestfrightenedDist = 0x7FFF;
  828. int16_t closestAttackingDist = 0x7FFF;
  829. for (byte i = 0; i < 4; i++)
  830. {
  831. Sprite* s = _sprites + i;
  832. int16_t d = s->Distance(pacman->cx, pacman->cy);
  833. if (d < dist)
  834. {
  835. dist = d;
  836. if (s->state == FrightenedState ) {
  837. frightenedGhost = s;
  838. closestfrightenedDist = d;
  839. }
  840. else {
  841. closestAttackingGhost = s;
  842. closestAttackingDist = d;
  843. }
  844. closestGhost = s;
  845. if ( s->state == DeadEyesState ) DeadEyesStateGhost = s;
  846. }
  847. }
  848. PACMANFALLBACK = 0;
  849. if (DEMO == 1 && !DeadEyesStateGhost && frightenedGhost )
  850. {
  851. pacman->Target(frightenedGhost->cx, frightenedGhost->cy);
  852. return;
  853. }
  854. // Under threat; just avoid closest ghost
  855. if (DEMO == 1 && !DeadEyesStateGhost && dist <= 32 && closestAttackingDist < closestfrightenedDist )
  856. {
  857. if (dist <= 16) {
  858. pacman->Target( pacman->cx * 2 - closestAttackingGhost->cx, pacman->cy * 2 - closestAttackingGhost->cy);
  859. PACMANFALLBACK = 1;
  860. } else {
  861. pacman->Target( pacman->cx * 2 - closestAttackingGhost->cx, pacman->cy * 2 - closestAttackingGhost->cy);
  862. }
  863. return;
  864. }
  865. if (ACTIVEBONUS == 1) {
  866. pacman->Target(13, 20);
  867. return;
  868. }
  869. // Go for the pill
  870. if (GetDot(1, 6))
  871. pacman->Target(1, 6);
  872. else if (GetDot(26, 6))
  873. pacman->Target(26, 6);
  874. else if (GetDot(1, 26))
  875. pacman->Target(1, 26);
  876. else if (GetDot(26, 26))
  877. pacman->Target(26, 26);
  878. else
  879. {
  880. // closest dot
  881. int16_t dist = 0x7FFF;
  882. for (byte y = 4; y < 32; y++)
  883. {
  884. for (byte x = 1; x < 26; x++)
  885. {
  886. if (GetDot(x, y))
  887. {
  888. int16_t d = pacman->Distance(x, y);
  889. if (d < dist)
  890. {
  891. dist = d;
  892. pacman->Target(x, y);
  893. }
  894. }
  895. }
  896. }
  897. if (dist == 0x7FFF) {
  898. GAMEWIN = 1; // No dots, GAME WIN!
  899. }
  900. }
  901. }
  902. void Scatter(Sprite* s)
  903. {
  904. const byte* st = _scatterTargets + (s->who << 1);
  905. s->Target(pgm_read_byte(st), pgm_read_byte(st + 1));
  906. }
  907. void UpdateTargets()
  908. {
  909. if (_state == ReadyState)
  910. return;
  911. PacmanAI();
  912. Sprite* pacman = _sprites + PACMAN;
  913. // Ghost AI
  914. bool scatter = _scIndex & 1;
  915. for (byte i = 0; i < 4; i++)
  916. {
  917. Sprite* s = _sprites + i;
  918. // Deal with returning ghost to pen
  919. if (s->state == DeadEyesState)
  920. {
  921. if (s->cx == 14 && s->cy == 17) // returned to pen
  922. {
  923. s->state = PenState; // Revived in pen
  924. s->pentimer = 80;
  925. }
  926. else
  927. s->Target(14, 17); // target pen
  928. continue; //
  929. }
  930. // Release ghost from pen when timer expires
  931. if (s->pentimer)
  932. {
  933. if (--s->pentimer) // stay in pen for awhile
  934. continue;
  935. s->state = RunState;
  936. }
  937. if (InPen(s->cx, s->cy))
  938. {
  939. s->Target(14, 14 - 2); // Get out of pen first
  940. } else {
  941. if (scatter || s->state == FrightenedState)
  942. Scatter(s);
  943. else
  944. {
  945. // Chase mode targeting
  946. signed char tx = pacman->cx;
  947. signed char ty = pacman->cy;
  948. switch (s->who)
  949. {
  950. case PINKY:
  951. {
  952. const char* pto = _pinkyTargetOffset + ((pacman->dir - 1) << 1);
  953. tx += pgm_read_byte(pto);
  954. ty += pgm_read_byte(pto + 1);
  955. }
  956. break;
  957. case INKY:
  958. {
  959. const char* pto = _pinkyTargetOffset + ((pacman->dir - 1) << 1);
  960. Sprite* binky = _sprites + BINKY;
  961. tx += pgm_read_byte(pto) >> 1;
  962. ty += pgm_read_byte(pto + 1) >> 1;
  963. tx += tx - binky->cx;
  964. ty += ty - binky->cy;
  965. }
  966. break;
  967. case CLYDE:
  968. {
  969. if (s->Distance(pacman->cx, pacman->cy) < 64)
  970. {
  971. const byte* st = _scatterTargets + CLYDE * 2;
  972. tx = pgm_read_byte(st);
  973. ty = pgm_read_byte(st + 1);
  974. }
  975. }
  976. break;
  977. }
  978. s->Target(tx, ty);
  979. }
  980. }
  981. }
  982. }
  983. // Default to current direction
  984. byte ChooseDir(int16_t dir, Sprite* s)
  985. {
  986. int16_t choice[4];
  987. choice[0] = Chase(s, s->cx, s->cy - 1); // Up
  988. choice[1] = Chase(s, s->cx - 1, s->cy); // Left
  989. choice[2] = Chase(s, s->cx, s->cy + 1); // Down
  990. choice[3] = Chase(s, s->cx + 1, s->cy); // Right
  991. if (DEMO == 0 && s->who == PACMAN && choice[0] < 0x7FFF && but_UP) dir = MUp;
  992. else if (DEMO == 0 && s->who == PACMAN && choice[1] < 0x7FFF && but_LEFT) dir = MLeft;
  993. else if (DEMO == 0 && s->who == PACMAN && choice[2] < 0x7FFF && but_DOWN) dir = MDown;
  994. else if (DEMO == 0 && s->who == PACMAN && choice[3] < 0x7FFF && but_RIGHT) dir = MRight;
  995. else if (DEMO == 0 && choice[0] < 0x7FFF && s->who == PACMAN && dir == MUp) dir = MUp;
  996. else if (DEMO == 0 && choice[1] < 0x7FFF && s->who == PACMAN && dir == MLeft) dir = MLeft;
  997. else if (DEMO == 0 && choice[2] < 0x7FFF && s->who == PACMAN && dir == MDown) dir = MDown;
  998. else if (DEMO == 0 && choice[3] < 0x7FFF && s->who == PACMAN && dir == MRight) dir = MRight;
  999. else if ((DEMO == 0 && s->who != PACMAN) || DEMO == 1 ) {
  1000. // Don't choose opposite of current direction?
  1001. int16_t dist = choice[4 - dir]; // favor current direction
  1002. byte opposite = OppositeDirection(dir);
  1003. for (byte i = 0; i < 4; i++)
  1004. {
  1005. byte d = 4 - i;
  1006. if ((d != opposite && choice[i] < dist) || (s->who == PACMAN && PACMANFALLBACK && choice[i] < dist))
  1007. {
  1008. if (s->who == PACMAN && PACMANFALLBACK) PACMANFALLBACK = 0;
  1009. dist = choice[i];
  1010. dir = d;
  1011. }
  1012. }
  1013. } else {
  1014. dir = MStopped;
  1015. }
  1016. return dir;
  1017. }
  1018. bool InPen(byte cx, byte cy)
  1019. {
  1020. if (cx <= 10 || cx >= 18) return false;
  1021. if (cy <= 14 || cy >= 18) return false;
  1022. return true;
  1023. }
  1024. byte GetSpeed(Sprite* s)
  1025. {
  1026. if (s->who == PACMAN)
  1027. return _frightenedTimer ? 90 : 80; //90:80
  1028. if (s->state == FrightenedState)
  1029. return 40;
  1030. if (s->state == DeadEyesState)
  1031. return 100;
  1032. if (s->cy == 17 && (s->cx <= 5 || s->cx > 20))
  1033. return 40; // tunnel
  1034. return 75;
  1035. }
  1036. void PackmanDied() { // Noooo... PACMAN DIED :(
  1037. if (LIFES <= 0) {
  1038. GAMEOVER = 1;
  1039. LEVEL = START_LEVEL;
  1040. LIFES = START_LIFES;
  1041. DEMO = 1;
  1042. Init();
  1043. } else {
  1044. LIFES--;
  1045. _inited = true;
  1046. _state = ReadyState;
  1047. _stateTimer = FPS / 2;
  1048. _frightenedCount = 0;
  1049. _frightenedTimer = 0;
  1050. const byte* s = _initSprites;
  1051. for (int16_t i = 0; i < 5; i++)
  1052. _sprites[i].Init(s + i * 5);
  1053. _scIndex = 0;
  1054. _scTimer = 1;
  1055. memset(_icons, 0, sizeof(_icons));
  1056. //AND BONUS
  1057. _BonusSprite.Init(s + 5 * 5);
  1058. _BonusInactiveTimmer = BONUS_INACTIVE_TIME;
  1059. _BonusActiveTimmer = 0;
  1060. for (byte i = 0; i < ACTUALBONUS; i++) {
  1061. _icons[13 - i] = BONUSICON + i;
  1062. }
  1063. for (byte i = 0; i < LIFES; i++) {
  1064. _icons[0 + i] = PACMANICON;
  1065. }
  1066. //Draw LIFE and BONUS Icons
  1067. for (byte y = 34; y < 36; y++)
  1068. for (byte x = 0; x < 28; x++) {
  1069. Draw(x, y, false);
  1070. }
  1071. DrawAllBG();
  1072. }
  1073. }
  1074. void MoveAll()
  1075. {
  1076. UpdateTimers();
  1077. UpdateTargets();
  1078. // Update game state
  1079. if (_stateTimer)
  1080. {
  1081. if (--_stateTimer <= 0)
  1082. {
  1083. switch (_state)
  1084. {
  1085. case ReadyState:
  1086. _state = PlayState;
  1087. _dirty[20 * 4 + 1] |= 0x1F; // Clear 'READY!'
  1088. _dirty[20 * 4 + 2] |= 0x80;
  1089. for (byte tmpX = 11; tmpX < 17; tmpX++) Draw(tmpX, 20, false); // ReDraw (clear) 'READY' position
  1090. break;
  1091. case DeadGhostState:
  1092. _state = PlayState;
  1093. for (byte i = 0; i < 4; i++)
  1094. {
  1095. Sprite* s = _sprites + i;
  1096. if (s->state == DeadNumberState)
  1097. s->state = DeadEyesState;
  1098. }
  1099. break;
  1100. default:
  1101. ;
  1102. }
  1103. } else {
  1104. if (_state == ReadyState)
  1105. return;
  1106. }
  1107. }
  1108. for (byte i = 0; i < 5; i++)
  1109. {
  1110. Sprite* s = _sprites + i;
  1111. // In DeadGhostState, only eyes move
  1112. if (_state == DeadGhostState && s->state != DeadEyesState)
  1113. continue;
  1114. // Calculate speed
  1115. s->_speed += GetSpeed(s);
  1116. if (s->_speed < 100)
  1117. continue;
  1118. s->_speed -= 100;
  1119. s->lastx = s->_x;
  1120. s->lasty = s->_y;
  1121. s->phase++;
  1122. int16_t x = s->_x;
  1123. int16_t y = s->_y;
  1124. if ((x & 0x7) == 0 && (y & 0x7) == 0) // cell aligned
  1125. s->dir = ChooseDir(s->dir, s); // time to choose another direction
  1126. switch (s->dir)
  1127. {
  1128. case MLeft: x -= SPEED; break;
  1129. case MRight: x += SPEED; break;
  1130. case MUp: y -= SPEED; break;
  1131. case MDown: y += SPEED; break;
  1132. case MStopped: break;
  1133. }
  1134. // Wrap x because of tunnels
  1135. while (x < 0)
  1136. x += 224;
  1137. while (x >= 224)
  1138. x -= 224;
  1139. s->_x = x;
  1140. s->_y = y;
  1141. s->cx = (x + 4) >> 3;
  1142. s->cy = (y + 4) >> 3;
  1143. if (s->who == PACMAN)
  1144. EatDot(s->cx, s->cy);
  1145. }
  1146. // Collide
  1147. Sprite* pacman = _sprites + PACMAN;
  1148. // Collide with BONUS
  1149. Sprite* _s = &_BonusSprite;
  1150. if (ACTIVEBONUS == 1 && _s->cx == pacman->cx && _s->cy == pacman->cy)
  1151. {
  1152. Score(ACTUALBONUS * 50);
  1153. ACTUALBONUS++;
  1154. if (ACTUALBONUS > 7) {
  1155. ACTUALBONUS = 0;
  1156. if (LIFES < MAXLIFES) LIFES++;
  1157. //reset all icons
  1158. memset(_icons, 0, sizeof(_icons));
  1159. for (byte i = 0; i < LIFES; i++) {
  1160. _icons[0 + i] = PACMANICON;
  1161. }
  1162. }
  1163. for (byte i = 0; i < ACTUALBONUS; i++) {
  1164. _icons[13 - i] = BONUSICON + i;
  1165. }
  1166. //REDRAW LIFE and BONUS icons
  1167. for (byte y = 34; y < 36; y++)
  1168. for (byte x = 0; x < 28; x++) {
  1169. Draw(x, y, false);
  1170. }
  1171. ACTIVEBONUS = 0;
  1172. _BonusInactiveTimmer = BONUS_INACTIVE_TIME;
  1173. }
  1174. for (byte i = 0; i < 4; i++)
  1175. {
  1176. Sprite* s = _sprites + i;
  1177. //if (s->cx == pacman->cx && s->cy == pacman->cy)
  1178. if (s->_x + SPEED >= pacman->_x && s->_x - SPEED <= pacman->_x && s->_y + SPEED >= pacman->_y && s->_y - SPEED <= pacman->_y)
  1179. {
  1180. if (s->state == FrightenedState)
  1181. {
  1182. s->state = DeadNumberState; // Killed a ghost
  1183. _frightenedCount++;
  1184. _state = DeadGhostState;
  1185. _stateTimer = 10;
  1186. Score((1 << _frightenedCount) * 100);
  1187. }
  1188. else { // pacman died
  1189. if (s->state == DeadNumberState || s->state == FrightenedState || s->state == DeadEyesState) {
  1190. } else {
  1191. PackmanDied();
  1192. }
  1193. }
  1194. }
  1195. }
  1196. }
  1197. // Mark a position dirty
  1198. void Mark(int16_t pos)
  1199. {
  1200. for (byte tmp = 0; tmp < 28; tmp++)
  1201. updateMap[1][tmp] = true;
  1202. }
  1203. void SetScoreChar(byte i, signed char c)
  1204. {
  1205. if (_scoreStr[i] == c)
  1206. return;
  1207. _scoreStr[i] = c;
  1208. Mark(i + 32); //Score
  1209. //Mark(i+32+10); //HiScore
  1210. }
  1211. void SetHiScoreChar(byte i, signed char c)
  1212. {
  1213. if (_hiscoreStr[i] == c)
  1214. return;
  1215. _hiscoreStr[i] = c;
  1216. //Mark(i+32); //Score
  1217. Mark(i + 32 + 10); //HiScore
  1218. }
  1219. void Score(int16_t delta)
  1220. {
  1221. char str[8];
  1222. _score += delta;
  1223. if (DEMO == 0 && _score > _hiscore) _hiscore = _score;
  1224. if (_score > _lifescore && _score % 10000 > 0) {
  1225. _lifescore = (_score / 10000 + 1) * 10000;
  1226. LIFES++; // EVERY 10000 points = 1UP
  1227. for (byte i = 0; i < LIFES; i++) {
  1228. _icons[0 + i] = PACMANICON;
  1229. }
  1230. //REDRAW LIFE and BONUS icons
  1231. for (byte y = 34; y < 36; y++)
  1232. for (byte x = 0; x < 28; x++) {
  1233. Draw(x, y, false);
  1234. }
  1235. _score = _score + 100;
  1236. }
  1237. sprintf(str, "%ld", _score);
  1238. byte i = 7 - strlen(str);
  1239. byte j = 0;
  1240. while (i < 7)
  1241. SetScoreChar(i++, str[j++]);
  1242. sprintf(str, "%ld", _hiscore);
  1243. i = 7 - strlen(str);
  1244. j = 0;
  1245. while (i < 7)
  1246. SetHiScoreChar(i++, str[j++]);
  1247. }
  1248. bool GetDot(byte cx, byte cy)
  1249. {
  1250. return _dotMap[(cy - 3) * 4 + (cx >> 3)] & (0x80 >> (cx & 7));
  1251. }
  1252. void EatDot(byte cx, byte cy)
  1253. {
  1254. if (!GetDot(cx, cy))
  1255. return;
  1256. byte mask = 0x80 >> (cx & 7);
  1257. _dotMap[(cy - 3) * 4 + (cx >> 3)] &= ~mask;
  1258. byte t = GetTile(cx, cy);
  1259. if (t == PILL)
  1260. {
  1261. _frightenedTimer = 10 * FPS;
  1262. _frightenedCount = 0;
  1263. for (byte i = 0; i < 4; i++)
  1264. {
  1265. Sprite* s = _sprites + i;
  1266. if (s->state == RunState)
  1267. {
  1268. s->state = FrightenedState;
  1269. s->dir = OppositeDirection(s->dir);
  1270. }
  1271. }
  1272. Score(50);
  1273. }
  1274. else
  1275. Score(10);
  1276. }
  1277. void Init()
  1278. {
  1279. if (GAMEWIN == 1) {
  1280. GAMEWIN = 0;
  1281. } else {
  1282. LEVEL = START_LEVEL;
  1283. LIFES = START_LIFES;
  1284. ACTUALBONUS = 0; //actual bonus icon
  1285. ACTIVEBONUS = 0; //status of bonus
  1286. _score = 0;
  1287. _lifescore = 10000;
  1288. memset(_scoreStr, 0, sizeof(_scoreStr));
  1289. _scoreStr[5] = _scoreStr[6] = '0';
  1290. }
  1291. _inited = true;
  1292. _state = ReadyState;
  1293. _stateTimer = FPS / 2;
  1294. _frightenedCount = 0;
  1295. _frightenedTimer = 0;
  1296. const byte* s = _initSprites;
  1297. for (int16_t i = 0; i < 5; i++)
  1298. _sprites[i].Init(s + i * 5);
  1299. //AND BONUS
  1300. _BonusSprite.Init(s + 5 * 5);
  1301. _BonusInactiveTimmer = BONUS_INACTIVE_TIME;
  1302. _BonusActiveTimmer = 0;
  1303. _scIndex = 0;
  1304. _scTimer = 1;
  1305. memset(_icons, 0, sizeof(_icons));
  1306. // SET BONUS icons
  1307. for (byte i = 0; i < ACTUALBONUS; i++) {
  1308. _icons[13 - i] = BONUSICON + i;
  1309. }
  1310. // SET Lifes icons
  1311. for (byte i = 0; i < LIFES; i++) {
  1312. _icons[0 + i] = PACMANICON;
  1313. }
  1314. //Draw LIFE and BONUS Icons
  1315. for (byte y = 34; y < 36; y++)
  1316. for (byte x = 0; x < 28; x++) {
  1317. Draw(x, y, false);
  1318. }
  1319. // Init dots from rom
  1320. memset(_dotMap, 0, sizeof(_dotMap));
  1321. byte* map = _dotMap;
  1322. for (byte y = 3; y < 36 - 3; y++) // 30 interior lines
  1323. {
  1324. for (byte x = 0; x < 28; x++)
  1325. {
  1326. byte t = GetTile(x, y);
  1327. if (t == 7 || t == 14)
  1328. {
  1329. byte s = x & 7;
  1330. map[x >> 3] |= (0x80 >> s);
  1331. }
  1332. }
  1333. map += 4;
  1334. }
  1335. DrawAllBG();
  1336. }
  1337. void Step()
  1338. {
  1339. int16_t keys = 0;
  1340. if (GAMEWIN == 1) {
  1341. LEVEL++;
  1342. Init();
  1343. }
  1344. // Start GAME
  1345. if (but_START && DEMO == 1 && GAMEPAUSED == 0) {
  1346. but_START = false;
  1347. DEMO = 0;
  1348. Init();
  1349. } else if (but_START && DEMO == 0 && GAMEPAUSED == 0) { // Or PAUSE GAME
  1350. but_START = false;
  1351. GAMEPAUSED = 1;
  1352. }
  1353. if (GAMEPAUSED && but_START && DEMO == 0) {
  1354. but_START = false;
  1355. GAMEPAUSED = 0;
  1356. for (byte tmpX = 11; tmpX < 17; tmpX++) Draw(tmpX, 20, false);
  1357. }
  1358. // Reset / Start GAME
  1359. if (but_SELECT) {
  1360. DEMO = 0;
  1361. Init();
  1362. } else if (!_inited) {
  1363. DEMO = 1;
  1364. Init();
  1365. }
  1366. // Create a bitmap of dirty tiles
  1367. byte m[(32 / 8) * 36]; // 144 bytes
  1368. memset(m, 0, sizeof(m));
  1369. _dirty = m;
  1370. if (!GAMEPAUSED) MoveAll(); // IF GAME is PAUSED STOP ALL
  1371. if ((ACTIVEBONUS == 0 && DEMO == 1) || GAMEPAUSED == 1 ) for (byte tmpX = 11; tmpX < 17; tmpX++) Draw(tmpX, 20, false); // Draw 'PAUSED' or 'DEMO' text
  1372. DrawAll();
  1373. }
  1374. };
  1375. /******************************************************************************/
  1376. /* SETUP */
  1377. /******************************************************************************/
  1378. #define BLACK 0x0000 // 16bit BLACK Color
  1379. void setup() {
  1380. randomSeed(analogRead(0));
  1381. // TFT 2.2" SPI
  1382. Serial1.begin(2000000);
  1383. Serial.begin(9600);
  1384. Serial.println("\n\nUSB Host Testing");
  1385. Serial.println(sizeof(USBHub), DEC);
  1386. myusb.begin();
  1387. delay(500);
  1388. //------------------------------------------------------------------------------
  1389. #ifdef USE_ILI
  1390. // SETUP TFT LCD
  1391. if (TFT_RST < 255) {
  1392. pinMode(TFT_RST, OUTPUT);
  1393. digitalWrite(TFT_RST, HIGH);
  1394. delay(5);
  1395. digitalWrite(TFT_RST, LOW);
  1396. delay(20);
  1397. digitalWrite(TFT_RST, HIGH);
  1398. delay(150);
  1399. }
  1400. tft.begin();
  1401. delay(100);
  1402. tft.setRotation(2); // 180
  1403. delay(100);
  1404. tft.fillScreen(BLACK);
  1405. #endif
  1406. //------------------------------------------------------------------------------
  1407. }
  1408. /******************************************************************************/
  1409. /* LOOP */
  1410. /******************************************************************************/
  1411. Playfield _game;
  1412. void loop() {
  1413. if (joystick1.available()) {
  1414. if (first_joystick_message) {
  1415. Serial.printf("*** First Joystick message %x:%x ***\n",
  1416. joystick1.idVendor(), joystick1.idProduct());
  1417. first_joystick_message = false;
  1418. const uint8_t *psz = joystick1.manufacturer();
  1419. if (psz && *psz) Serial.printf(" manufacturer: %s\n", psz);
  1420. psz = joystick1.product();
  1421. if (psz && *psz) Serial.printf(" product: %s\n", psz);
  1422. psz = joystick1.serialNumber();
  1423. if (psz && *psz) Serial.printf(" Serial: %s\n", psz);
  1424. // lets try to reduce number of fields that update
  1425. joystick1.axisChangeNotifyMask(0xFFFFFl);
  1426. }
  1427. for (uint8_t i = 0; i < 64; i++) {
  1428. psAxis[i] = joystick1.getAxis(i);
  1429. }
  1430. KeyPadLoop();
  1431. _game.Step();
  1432. yield();
  1433. }
  1434. }
  1435. //-------------------------------------------------------------------------------------------------------------
  1436. #define __C16(_rr,_gg,_bb) ((uint16_t)(((_rr & 0xF8) << 8) | ((_gg & 0xFC) << 3) | ((_bb & 0xF8) >> 3)))
  1437. // 8 bit palette - in RAM because of graphics driver
  1438. uint16_t __paletteW[] =
  1439. {
  1440. __C16(0,0,0),
  1441. __C16(255,0,0), // 1 red
  1442. __C16(222,151,81), // 2 brown
  1443. __C16(255,128,255), // 3 pink
  1444. __C16(0,0,0),
  1445. __C16(0,255,255), // 5 cyan
  1446. __C16(71,84,255), // 6 mid blue
  1447. __C16(255,184,81), // 7 lt brown
  1448. __C16(0,0,0),
  1449. __C16(255,255,0), // 9 yellow
  1450. __C16(0,0,0),
  1451. __C16(33,33,255), // 11 blue
  1452. __C16(0,255,0), // 12 green
  1453. __C16(71,84,174), // 13 aqua
  1454. __C16(255,184,174), // 14 lt pink
  1455. __C16(222,222,255), // 15 whiteish
  1456. };
  1457. void drawIndexedmap(const uint8_t *indexmap, int16_t x, int16_t y, uint16_t w, uint16_t h) {
  1458. byte i = 0;
  1459. word color = (word)__paletteW[indexmap[0]];
  1460. for (byte tmpY = 0; tmpY < 8; tmpY++) {
  1461. byte width = 1;
  1462. for (byte tmpX = 0; tmpX < 8; tmpX++) {
  1463. word next_color = (word)__paletteW[indexmap[++i]];
  1464. if ((color != next_color && width >= 1) || tmpX == 7 ) {
  1465. ///drawPixel_cont(x+tmpX, y+tmpY, color);
  1466. tft.drawFastHLine(x + tmpX - width + 1, y + tmpY, width, color);
  1467. color = next_color;
  1468. width = 0;
  1469. }
  1470. width++;
  1471. }
  1472. }
  1473. }