Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

1776 lines
48KB

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