1 /****************************************************************************
4 * LPC1224/SSD1306 implementation of the famous pacman game
6 * Copyright 2017 Nathael Pajani <nathael.pajani@ed3l.fr>
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 *************************************************************************** */
24 #define ALLOW_SCREENSHOT
27 #include "core/system.h"
28 #include "core/systick.h"
29 #include "lib/string.h"
30 #include "drivers/gpio.h"
31 #include "drivers/ssp.h"
32 #ifdef ALLOW_SCREENSHOT
33 #include "lib/stdio.h"
34 #include "drivers/serial.h"
37 #include "extdrv/status_led.h"
38 #include "extdrv/ssd130x_oled_driver.h"
39 #include "extdrv/ssd130x_oled_buffer.h"
43 #define MODULE_VERSION 0x01
44 #define MODULE_NAME "Pacman"
46 #define SELECTED_FREQ FREQ_SEL_48MHz
48 /***************************************************************************** */
49 /* Pins configuration */
50 /* pins blocks are passed to set_pins() for pins configuration.
51 * Unused pin blocks can be removed safely with the corresponding set_pins() call
52 * All pins blocks may be safelly merged in a single block for single set_pins() call..
54 const struct pio_config common_pins[] = {
55 #ifdef ALLOW_SCREENSHOT
56 /* UART 0 : Config / Debug / USB */
57 { LPC_UART0_RX_PIO_0_1, LPC_IO_DIGITAL },
58 { LPC_UART0_TX_PIO_0_2, LPC_IO_DIGITAL },
61 { LPC_SSP0_SCLK_PIO_0_14, LPC_IO_DIGITAL },
62 { LPC_SSP0_MISO_PIO_0_16, LPC_IO_DIGITAL },
63 { LPC_SSP0_MOSI_PIO_0_17, LPC_IO_DIGITAL },
65 { LPC_GPIO_0_12, LPC_IO_DIGITAL }, /* ISP / User button OK */
67 { LPC_GPIO_0_6, LPC_IO_DIGITAL }, /* User button B4 */
68 { LPC_GPIO_0_5, LPC_IO_DIGITAL }, /* User button B3 */
69 { LPC_GPIO_0_4, LPC_IO_DIGITAL }, /* User button B2 */
70 { LPC_GPIO_0_3, LPC_IO_DIGITAL }, /* User button B1 */
74 const struct pio status_led_green = LPC_GPIO_0_27;
75 const struct pio status_led_red = LPC_GPIO_0_28;
78 const struct pio button_up = LPC_GPIO_0_3; // B1
79 const struct pio button_down = LPC_GPIO_0_6; // B4
80 const struct pio button_left = LPC_GPIO_0_4; // B2
81 const struct pio button_right = LPC_GPIO_0_5; // B3
82 const struct pio button_ok = LPC_GPIO_0_12; // BOK
84 /***************************************************************************** */
85 /* Basic system init and configuration */
89 /* Stop the Watchdog */
90 startup_watchdog_disable(); /* Do it right now, before it gets a chance to break in */
91 system_set_default_power_state();
92 clock_config(SELECTED_FREQ);
93 set_pins(common_pins);
95 status_led_config(&status_led_green, &status_led_red);
96 /* System tick timer MUST be configured and running in order to use the sleeping
98 systick_timer_on(1); /* 1ms */
102 /****************************************************************************/
104 #define DISPLAY_ADDR 0x78
105 static uint8_t gddram[ 4 + GDDRAM_SIZE ];
106 struct oled_display display = {
107 .bus_type = SSD130x_BUS_SPI,
108 .address = DISPLAY_ADDR,
109 .bus_num = SSP_BUS_0,
110 .charge_pump = SSD130x_INTERNAL_PUMP,
111 .video_mode = SSD130x_DISP_NORMAL,
113 .scan_dir = SSD130x_SCAN_BOTTOM_TOP,
114 .read_dir = SSD130x_RIGHT_TO_LEFT,
115 .display_offset_dir = SSD130x_MOVE_TOP,
118 .gpio_cs = LPC_GPIO_1_2,
119 .gpio_dc = LPC_GPIO_1_1,
120 .gpio_rst = LPC_GPIO_1_3,
124 #ifdef ALLOW_SCREENSHOT
125 static void data_rx(uint8_t __attribute((unused))c)
129 volatile int take_screenshot = 0;
130 static void set_screenshot(uint32_t __attribute__((unused))gpio)
135 static void send_screenshot(void)
138 uprintf(UART0, "P4\n128 64\n");
139 for (y = 0; y < 64; y++)
140 for (x = 0; x < 128; x += 8)
142 uint32_t pattern = 0;
143 for (xx = 0; xx < 8; xx++)
146 if ((gddram[4 + (y/8)*128 + x + xx] >> (y & 7)) & 1)
151 uprintf(UART0, "%c", pattern);
153 uprintf(UART0, "\n");
157 /****************************************************************************/
178 static uint32_t current_pills[31];
187 struct Vec2 position; /* */
188 struct Vec2 direction; /* */
189 struct Vec2 offset; /* */
190 struct Vec2 target; /* */
191 enum GhostModes mode; /* */
195 struct Ghost ghosts[4] =
198 { 16, 11 }, { 1, 0 }, { 0, 0 }, { 28, -2 }, GM_CORNERS, 0
201 { 13, 14 }, { 1, 0 }, { 0, 0 }, { 5, -2 }, GM_IN_PEN, 0
205 { 15, 14 }, { 1, 0 }, { 0, 0 }, { 5, 33 }, GM_IN_PEN, 0
209 { 17, 14 }, { 1, 0 }, { 0, 0 }, { 28, 33 }, GM_IN_PEN, 0
215 struct Vec2 position;
216 struct Vec2 direction;
217 struct Vec2 sub_step;
218 struct Vec2 next_dir;
222 struct Pacman pacman =
231 static int screen_offset = 0;
232 static int current_frame = 0;
233 static uint8_t score[5];
234 static uint8_t ghost_score = 0;
236 static volatile uint8_t button_up_pressed = 0;
237 static volatile uint8_t button_down_pressed = 0;
238 static volatile uint8_t button_left_pressed = 0;
239 static volatile uint8_t button_right_pressed = 0;
241 static void handle_buttons(uint32_t gpio)
243 if (gpio == button_up.pin)
245 if (gpio_read(button_up) == 0)
246 button_up_pressed = 1;
248 button_up_pressed = 0;
250 if (gpio == button_left.pin)
252 if (gpio_read(button_left) == 0)
253 button_left_pressed = 1;
255 button_left_pressed = 0;
257 if (gpio == button_down.pin)
259 if (gpio_read(button_down) == 0)
260 button_down_pressed = 1;
262 button_down_pressed = 0;
264 if (gpio == button_right.pin)
266 if (gpio_read(button_right) == 0)
267 button_right_pressed = 1;
269 button_right_pressed = 0;
273 /*==========================================================================*\
275 \*==========================================================================*/
276 static uint32_t my_rand()
278 static uint32_t x = 123456789;
279 static uint32_t y = 234567891;
280 static uint32_t z = 345678912;
281 static uint32_t w = 456789123;
282 static uint32_t c = 0;
297 /*==========================================================================*\
299 \*==========================================================================*/
300 static void draw_glyph(int x, int y, uint8_t glyph)
303 for (i = 0; i < 8; i++)
304 gddram[4 + y * 128 + x + i] = font[glyph * 8 + i];
307 /*==========================================================================*\
309 \*==========================================================================*/
310 static void score_add_10000(int digit)
320 /*==========================================================================*\
322 \*==========================================================================*/
323 static void score_add_1000(int digit)
332 /*==========================================================================*\
334 \*==========================================================================*/
335 static void score_add_100(int digit)
345 /*==========================================================================*\
347 \*==========================================================================*/
348 static void score_add_10(int digit)
358 /*==========================================================================*\
360 \*==========================================================================*/
361 static void draw_score(void)
363 // Note this should be called last, so this can hide a ghost in the tunnel
364 draw_glyph(0, 0, F_BLANK);
365 draw_glyph(0, 1, F_DIGIT_0 + score[0]);
366 draw_glyph(0, 2, F_DIGIT_0 + score[1]);
367 draw_glyph(0, 3, F_DIGIT_0 + score[2]);
368 draw_glyph(0, 4, F_DIGIT_0 + score[3]);
369 draw_glyph(0, 5, F_DIGIT_0 + score[4]);
370 draw_glyph(0, 6, F_DIGIT_0);
371 draw_glyph(0, 7, F_BLANK);
374 draw_glyph(120, 0, F_BLANK);
375 draw_glyph(120, 1, F_PACMAN_RIGHT_1);
376 draw_glyph(120, 2, F_PACMAN_RIGHT_1);
377 draw_glyph(120, 3, F_PACMAN_RIGHT_1);
379 draw_glyph(120, 4, F_BLANK);
380 draw_glyph(120, 5, F_CHERRY);
381 draw_glyph(120, 6, F_BLANK);
382 draw_glyph(120, 7, F_BLANK);
385 /*==========================================================================*\
387 \*==========================================================================*/
388 static void draw_sprite8x8(int x, int y, const uint8_t *sprite)
390 int i, offset = 4 + 128 * (y / 8) + x;
392 if (y >= 0 && y < 64)
393 for (i = 0; i < 8; i++)
394 gddram[offset + i] |= sprite[i] << (y & 7);
395 if (y >= -8 && y < 56)
398 for (i = 0; i < 8; i++)
399 gddram[offset + i] |= sprite[i] >> (8 - (y & 7));
403 /*==========================================================================*\
404 * draw_sprite8x8_with_mask *
405 \*==========================================================================*/
406 static void draw_sprite8x8_with_mask(int x, int y,
407 const uint8_t *sprite,
410 int i, offset = 4 + 128 * (y / 8) + x;
412 if (y >= 0 && y < 64)
413 for (i = 0; i < 8; i++)
415 gddram[offset + i] &= ~(mask[i] << (y & 7));
416 gddram[offset + i] |= sprite[i] << (y & 7);
418 if (y >= -8 && y < 56)
420 offset += 128; // on the next line...
421 for (i = 0; i < 8; i++)
423 gddram[offset + i] &= ~(mask[i] >> (8 - (y % 8)));
424 gddram[offset + i] |= sprite[i] >> (8 - (y % 8));
429 /*==========================================================================*\
431 \*==========================================================================*/
432 static void draw_pills(void)
433 { // FIXME: rewrite this mess!
435 for (y = 1; y < 31; y++) {
436 uint32_t line = current_pills[y];
438 for (x = 0; x < 32; x++)
440 int yp = 4 * y - screen_offset;
441 if ((x == 3 || x == 28) && (y == 3 || y == 23)) {
442 if (current_frame & 8) {
444 gddram[4 + x * 4 + 1] |= 0x01;
445 gddram[4 + x * 4 + 2] |= 0x01;
446 } else if (yp == -2) {
447 gddram[4 + x * 4 + 0] |= 0x01;
448 gddram[4 + x * 4 + 1] |= 0x03;
449 gddram[4 + x * 4 + 2] |= 0x03;
450 gddram[4 + x * 4 + 3] |= 0x01;
451 } else if (yp == -1) {
452 gddram[4 + x * 4 + 0] |= 0x03;
453 gddram[4 + x * 4 + 1] |= 0x07;
454 gddram[4 + x * 4 + 2] |= 0x07;
455 gddram[4 + x * 4 + 3] |= 0x03;
457 else if (yp >= 0 && yp < 64) {
458 int offset = 4 + 128 * (yp >> 3) + x * 4;
460 case 0: case 1: case 2: case 3: case 4:
461 gddram[offset + 0] |= (0x06 << (yp & 7));
462 gddram[offset + 1] |= (0x0F << (yp & 7));
463 gddram[offset + 2] |= (0x0F << (yp & 7));
464 gddram[offset + 3] |= (0x06 << (yp & 7));
467 gddram[offset + 0] |= 0xC0;
468 gddram[offset + 1] |= 0xE0;
469 gddram[offset + 2] |= 0xE0;
470 gddram[offset + 3] |= 0xC0;
472 gddram[offset + 128 + 1] |= 0x01;
473 gddram[offset + 128 + 2] |= 0x01;
477 gddram[offset + 0] |= 0x80;
478 gddram[offset + 1] |= 0xC0;
479 gddram[offset + 2] |= 0xC0;
480 gddram[offset + 3] |= 0x80;
482 gddram[offset + 128 + 0] |= 0x01;
483 gddram[offset + 128 + 1] |= 0x03;
484 gddram[offset + 128 + 2] |= 0x03;
485 gddram[offset + 128 + 3] |= 0x01;
489 gddram[offset + 1] |= 0x80;
490 gddram[offset + 2] |= 0x80;
492 gddram[offset + 128 + 0] |= 0x03;
493 gddram[offset + 128 + 1] |= 0x07;
494 gddram[offset + 128 + 2] |= 0x07;
495 gddram[offset + 128 + 3] |= 0x03;
504 gddram[4 + x * 4 + 1] |= 0x03;
505 gddram[4 + x * 4 + 2] |= 0x03;
506 } else if (yp == -2) {
507 gddram[4 + x * 4 + 1] |= 0x01;
508 gddram[4 + x * 4 + 2] |= 0x01;
510 else if (yp >= 0 && yp < 64) {
511 int offset = 4 + 128 * (yp / 8) + x * 4;
514 case 0: case 1: case 2: case 3: case 4: case 5:
515 gddram[offset + 1] |= (0x06 << (yp & 7));
516 gddram[offset + 2] |= (0x06 << (yp & 7));
519 gddram[offset + 1] |= 0x80;
520 gddram[offset + 2] |= 0x80;
523 gddram[offset + 128 + 1] |= 0x01;
524 gddram[offset + 128 + 2] |= 0x01;
529 gddram[offset + 128 + 1] |= 0x03;
530 gddram[offset + 128 + 2] |= 0x03;
541 /*==========================================================================*\
543 \*==========================================================================*/
544 static void move_ghosts(void)
546 enum Direction { LEFT, RIGHT, UP, DOWN };
547 int checkxdir[4] = { -1,1,0,0 };
548 int checkydir[4] = { 0,0,-1,1 };
552 for (i = 0; i < 4; i++)
554 if (ghosts[i].mode == GM_EATEN)
556 ghosts[i].offset.x = ghosts[i].offset.y = 0;
557 ghosts[i].position.x += ghosts[i].direction.x;
558 ghosts[i].position.y += ghosts[i].direction.y;
561 if (ghosts[i].mode == GM_FRIGHTENED)
562 { // pause every 4 moves
563 if (ghosts[i].stopped == 4)
565 ghosts[i].stopped = 0;
567 } else ghosts[i].stopped++;
569 ghosts[i].offset.x += ghosts[i].direction.x;
570 ghosts[i].offset.y += ghosts[i].direction.y;
573 if (ghosts[i].offset.x >= 4 || ghosts[i].offset.x <= -4) {
574 ghosts[i].offset.x = 0;
575 ghosts[i].position.x += ghosts[i].direction.x;
577 if (ghosts[i].offset.y >= 4 || ghosts[i].offset.y <= -4) {
578 ghosts[i].offset.y = 0;
579 ghosts[i].position.y += ghosts[i].direction.y;
582 if (ghosts[i].offset.y == 0 && ghosts[i].offset.x == 0)
584 int u, a = 9999, b = -1;
586 for (u = 0; u < 4; u++)
588 int forbidden = walls_mask[ghosts[i].position.y+checkydir[u]] >> (ghosts[i].position.x+checkxdir[u]) & 1;
589 // U turns are forbidden by game rules
590 if (ghosts[i].direction.x == -checkxdir[u] &&
591 ghosts[i].direction.y == -checkydir[u])
593 // Ghosts are not allowed reenter the pen (unless eaten)
595 (ghosts[i].position.x == 15 || ghosts[i].position.x == 16) &&
596 ghosts[i].position.y == 11 &&
597 ghosts[i].mode != GM_EATEN)
599 // compute (squared) distance to target
600 int dx = ghosts[i].position.x + checkxdir[u];
601 dx = ghosts[i].target.x - dx;
602 int dy = ghosts[i].position.y + checkydir[u];
603 dy = ghosts[i].target.y - dy;
604 int distance = dx * dx + dy * dy;
605 // Store the minimal distance
606 if (!forbidden && distance <= a)
612 ghosts[i].direction.x = checkxdir[b];
613 ghosts[i].direction.y = checkydir[b];
616 if (ghosts[i].position.x == 15 && ghosts[i].position.y == 13)
617 ghosts[i].mode = GM_IN_PEN;
619 if (ghosts[i].mode == GM_IN_PEN && ghosts[i].position.y == 11)
620 ghosts[i].mode = GM_CORNERS;
621 // handle tunnel for ghosts
622 if (ghosts[i].position.x == 0 && ghosts[i].direction.x == -1)
623 ghosts[i].position.x = 31;
624 if (ghosts[i].position.x == 31 && ghosts[i].direction.x == 1)
625 ghosts[i].position.x = 0;
629 /*==========================================================================*\
631 \*==========================================================================*/
632 static void draw_ghosts(void)
635 for (i = 0; i < 4; i++)
637 enum FontEntries ghost_sprite = F_DIGIT_0;
638 switch (ghosts[i].mode)
641 ghost_sprite = F_GHOST_EYES;
644 ghost_sprite = F_GHOST_FRIGHTENED;
649 if (ghosts[i].direction.x == -1) ghost_sprite = F_GHOST_LEFT;
650 if (ghosts[i].direction.x == 1) ghost_sprite = F_GHOST_RIGHT;
651 if (ghosts[i].direction.y == -1) ghost_sprite = F_GHOST_UP;
652 if (ghosts[i].direction.y == 1) ghost_sprite = F_GHOST_DOWN;
655 ghost_sprite = F_GHOST_STILL;
659 draw_sprite8x8_with_mask(ghosts[i].position.x * 4 + ghosts[i].offset.x - 1,
660 ghosts[i].position.y * 4 + ghosts[i].offset.y - 1 - screen_offset,
661 &font[ghost_sprite * 8],
662 &font[F_GHOST_MASK * 8]);
666 /*==========================================================================*\
668 \*==========================================================================*/
669 static void move_pacman(void)
671 if (pacman.direction.x || pacman.direction.y)
674 if (current_frame & 1)
675 pacman.anim = (pacman.anim + 1) & 3;
676 if (pacman.direction.x == -1) pacman.shape = F_PACMAN_LEFT_0;
677 if (pacman.direction.x == 1) pacman.shape = F_PACMAN_RIGHT_0;
678 if (pacman.direction.y == -1) pacman.shape = F_PACMAN_UP_0;
679 if (pacman.direction.y == 1) pacman.shape = F_PACMAN_DOWN_0;
682 pacman.sub_step.x += pacman.direction.x;
683 pacman.sub_step.y += pacman.direction.y;
685 if (pacman.sub_step.x >= 4 || pacman.sub_step.x <= -4)
687 pacman.sub_step.x = 0;
688 pacman.position.x += pacman.direction.x;
690 if (pacman.sub_step.y >= 4 || pacman.sub_step.y <= -4)
692 pacman.sub_step.y = 0;
693 pacman.position.y += pacman.direction.y;
696 if (pacman.sub_step.x == 0 && pacman.sub_step.y == 0)
698 int x = pacman.position.x, y = pacman.position.y;
699 if (current_pills[y] >> x & 1) // hum, this should be 31-x (or not)
701 current_pills[y] -= 1 << x; // ditto
703 if ((x == 3 || x == 28) && (y == 3 || y == 23))
705 ghosts[GN_BLINKY].mode = GM_FRIGHTENED;
706 ghosts[GN_BLINKY].stopped = 0;
707 ghosts[GN_PINKY].mode = GM_FRIGHTENED;
708 ghosts[GN_PINKY].stopped = 0;
709 ghosts[GN_INKY].mode = GM_FRIGHTENED;
710 ghosts[GN_INKY].stopped = 0;
711 ghosts[GN_CLYDE].mode = GM_FRIGHTENED;
712 ghosts[GN_CLYDE].stopped = 0;
713 score_add_10(5); // energizers worth 50 points
716 else score_add_10(1); // normal pills are worth 10 points
719 // Where can we go next ?
720 x = pacman.position.x + pacman.next_dir.x;
721 y = pacman.position.y + pacman.next_dir.y;
723 if (!(walls_mask[y] >> x & 1))
725 pacman.direction.x = pacman.next_dir.x;
726 pacman.direction.y = pacman.next_dir.y;
728 x = pacman.position.x + pacman.direction.x;
729 y = pacman.position.y + pacman.direction.y;
730 if (walls_mask[y] >> x & 1)
732 pacman.direction.x = 0;
733 pacman.direction.y = 0;
735 // handle tunnel for pacman (ghosts are way slower in this)
736 if (pacman.position.x == 1 && pacman.direction.x == -1)
737 pacman.position.x = 30;
738 if (pacman.position.x == 30 && pacman.direction.x == 1)
739 pacman.position.x = 1;
743 /*==========================================================================*\
745 \*==========================================================================*/
746 static void draw_pacman(void)
748 draw_sprite8x8(pacman.position.x * 4 + pacman.sub_step.x - 2,
749 pacman.position.y * 4 + pacman.sub_step.y - 2 - screen_offset,
750 font + 8 * (pacman.shape + pacman.anim));
753 /*==========================================================================*\
755 \*==========================================================================*/
756 static void draw_walls(int screen_offset)
766 const uint8_t *backgrounds[8] =
768 image0, image1, image2, image3, image4, image5, image6, image7
770 const uint16_t *offsets[8] =
772 image_offsets0, image_offsets1, image_offsets2, image_offsets3,
773 image_offsets4, image_offsets5, image_offsets6, image_offsets7
775 uncompress_image(backgrounds[screen_offset & 7] +
776 offsets[screen_offset & 7][screen_offset >> 3],
780 /*==========================================================================*\
781 * draw_sprite_16x16 *
782 \*==========================================================================*/
783 static void draw_sprite_16x16(int x, int y, const uint8_t *sprite)
785 int i, offset = 4 + 128 * y + x;
788 if (x < 0) start = -x;
789 if (x > 112) end = 128 - x;
790 for (i = start; i < end; i++)
791 gddram[offset + i] |= sprite[i];
792 for (i = start; i < end; i++)
793 gddram[offset + i + 128] |= sprite[i + 16];
796 /*==========================================================================*\
797 * draw_sprite_16x16_reverse *
798 \*==========================================================================*/
799 static void draw_sprite_16x16_reverse(int x, int y, const uint8_t *sprite)
801 int i, offset = 4 + 128 * y + x;
804 if (x < 0) start = -x;
805 if (x > 112) end = 128 - x;
806 for (i = start; i < end; i++)
807 gddram[offset + i] |= sprite[15 - i];
808 for (i = start; i < end; i++)
809 gddram[offset + i + 128] |= sprite[31 - i];
812 /*==========================================================================*\
814 \*==========================================================================*/
815 static void update_screen(void)
817 #ifdef ALLOW_SCREENSHOT
821 // take_screenshot = 0;
824 ssd130x_display_full_screen(&display);
827 /*==========================================================================*\
828 * draw_sprite_16x16_with_mask *
829 \*==========================================================================*/
830 static void draw_sprite_16x16_with_mask(int x, int y,
831 const uint8_t *sprite,
834 int i, offset = 4 + 128 * y + x;
836 for (i = 0; i < 16; i++)
838 gddram[offset + i] &= ~mask[i];
839 gddram[offset + i] |= sprite[i];
841 offset = 4 + 128 * (y + 1) + x;
842 for (i = 0; i < 16; i++)
844 gddram[offset + i] &= ~mask[16 + i];
845 gddram[offset + i] |= sprite[16 + i];
849 /*==========================================================================*\
850 * show_intermission2 *
851 \*==========================================================================*/
852 static void show_intermission2(void)
857 ssd130x_buffer_set(gddram, 0xff);
858 int anim = (frame / 2) % 8;
862 draw_sprite_16x16_with_mask(50, 4,
863 pacmania_se_01, pacmania_se_01_mask);
866 draw_sprite_16x16_with_mask(50, 4,
867 pacmania_se_02, pacmania_se_02_mask);
870 draw_sprite_16x16_with_mask(50, 4,
871 pacmania_se_03, pacmania_se_03_mask);
874 draw_sprite_16x16_with_mask(50, 4,
875 pacmania_se_04, pacmania_se_04_mask);
878 draw_sprite_16x16_with_mask(50, 4,
879 pacmania_se_05, pacmania_se_05_mask);
886 if (button_right_pressed || button_left_pressed ||
887 button_up_pressed || button_down_pressed)
892 /*==========================================================================*\
893 * show_intermission *
894 \*==========================================================================*/
895 static void show_intermission(void)
897 #include "intermission-background.h"
898 int frame = 0, stop = 0;
900 int ghost1 = pac_x - 26;
901 int ghost2 = ghost1 - 18;
902 int ghost3 = ghost2 - 18;
903 int ghost4 = ghost3 - 18;
908 const uint8_t *ghost_sprite;
909 //const uint8_t *pacman_sprite;
910 uncompress_image(background_intermission, gddram + 4);
914 case 0: // pacman is chased by the ghost
915 ghost_sprite = frame & 2 ? big_ghost_0 : big_ghost_1;
916 switch ((frame / 2) & 3)
918 case 0: draw_sprite_16x16(pac_x, 4, big_pacman_0); break;
919 case 1: draw_sprite_16x16(pac_x, 4, big_pacman_1); break;
920 case 2: draw_sprite_16x16(pac_x, 4, big_pacman_2); break;
921 case 3: draw_sprite_16x16(pac_x, 4, big_pacman_1); break;
923 draw_sprite_16x16(ghost1, 4, ghost_sprite);
924 draw_sprite_16x16(ghost2, 4, ghost_sprite);
925 draw_sprite_16x16(ghost3, 4, ghost_sprite);
926 draw_sprite_16x16(ghost4, 4, ghost_sprite);
928 if (frame & 15) pac_x++;
930 ghost2 = ghost1 - 18;
931 ghost3 = ghost2 - 18;
932 ghost4 = ghost3 - 18;
937 //ghost1 = pac_x - 26;
940 case 1: // Pacman eats an energizer : screen is flashing
941 ssd130x_buffer_set(gddram, 0xFF);
947 ghost2 = ghost1 + 18;
948 ghost3 = ghost2 + 18;
949 ghost4 = ghost3 + 18;
953 case 2: // The ghost are going back left, pacman eating them
954 ghost_sprite = frame & 2 ? big_frightened_ghost_0 : big_frightened_ghost_1;
956 switch ((frame / 2) & 3)
958 case 0: draw_sprite_16x16_reverse(pac_x, 4, big_pacman_0); break;
959 case 1: draw_sprite_16x16_reverse(pac_x, 4, big_pacman_1); break;
960 case 2: draw_sprite_16x16_reverse(pac_x, 4, big_pacman_2); break;
961 case 3: draw_sprite_16x16_reverse(pac_x, 4, big_pacman_1); break;
963 draw_sprite_16x16(ghost1, 4, ghost_sprite);
964 draw_sprite_16x16(ghost2, 4, ghost_sprite);
965 draw_sprite_16x16(ghost3, 4, ghost_sprite);
966 draw_sprite_16x16(ghost4, 4, ghost_sprite);
982 gddram[4 + 128 * 4 + pac_x + i++] = 0xf2;
983 gddram[4 + 128 * 4 + pac_x + i++] = 0x92;
984 gddram[4 + 128 * 4 + pac_x + i++] = 0x92;
985 gddram[4 + 128 * 4 + pac_x + i++] = 0x9e;
988 gddram[4 + 128 * 4 + pac_x + i++] = 0x1e;
989 gddram[4 + 128 * 4 + pac_x + i++] = 0x10;
990 gddram[4 + 128 * 4 + pac_x + i++] = 0x10;
991 gddram[4 + 128 * 4 + pac_x + i++] = 0xfe;
994 gddram[4 + 128 * 4 + pac_x + i++] = 0xfe;
995 gddram[4 + 128 * 4 + pac_x + i++] = 0x92;
996 gddram[4 + 128 * 4 + pac_x + i++] = 0x92;
997 gddram[4 + 128 * 4 + pac_x + i++] = 0xfe;
1000 gddram[4 + 128 * 4 + pac_x + i++] = 0xfe;
1002 gddram[4 + 128 * 4 + pac_x + i++] = 0xfe;
1003 gddram[4 + 128 * 4 + pac_x + i++] = 0x92;
1004 gddram[4 + 128 * 4 + pac_x + i++] = 0x92;
1005 gddram[4 + 128 * 4 + pac_x + i++] = 0xf2;
1009 gddram[4 + 128 * 4 + pac_x + i++] = 0xfe;
1010 gddram[4 + 128 * 4 + pac_x + i++] = 0x82;
1011 gddram[4 + 128 * 4 + pac_x + i++] = 0x82;
1012 gddram[4 + 128 * 4 + pac_x + i++] = 0xfe;
1014 gddram[4 + 128 * 4 + pac_x + i++] = 0xfe;
1015 gddram[4 + 128 * 4 + pac_x + i++] = 0x82;
1016 gddram[4 + 128 * 4 + pac_x + i++] = 0x82;
1017 gddram[4 + 128 * 4 + pac_x + i++] = 0xfe;
1021 if (pac_x - ghost4 < 6) { stop = -10; ghost4 = -100; ghost_eaten++; }
1022 if (pac_x - ghost3 < 6) { stop = -10; ghost3 = -100; ghost_eaten++; }
1023 if (pac_x - ghost2 < 6) { stop = -10; ghost2 = -100; ghost_eaten++; }
1024 if (pac_x - ghost1 < 6) { stop = -10; ghost1 = -100; ghost_eaten++; }
1028 frame = 0; stop = 0;
1030 ghost1 = pac_x - 26;
1031 ghost2 = ghost1 - 18;
1032 ghost3 = ghost2 - 18;
1033 ghost4 = ghost3 - 18;
1041 if (button_right_pressed || button_left_pressed ||
1042 button_up_pressed || button_down_pressed)
1047 /****************************************************************************/
1051 #ifdef ALLOW_SCREENSHOT
1052 uart_on(UART0, 1152000, data_rx);
1054 ssp_master_on(SSP_BUS_0, LPC_SSP_FRAME_SPI, 8, 4*1000*1000);
1056 set_gpio_callback(handle_buttons, &button_up, EDGES_BOTH);
1057 set_gpio_callback(handle_buttons, &button_down, EDGES_BOTH);
1058 set_gpio_callback(handle_buttons, &button_left, EDGES_BOTH);
1059 set_gpio_callback(handle_buttons, &button_right, EDGES_BOTH);
1061 #ifdef ALLOW_SCREENSHOT
1062 set_gpio_callback(set_screenshot, &button_ok, EDGE_FALLING);
1065 status_led(green_only);
1067 /* Configure and start display */
1068 ssd130x_display_on(&display);
1070 show_intermission2();
1072 memcpy(current_pills, all_pills, sizeof all_pills);
1075 screen_offset = 4 * (pacman.position.y - 8) + pacman.sub_step.y;
1076 if (screen_offset < 0) screen_offset = 0;
1077 if (screen_offset > 64) screen_offset = 64;
1079 draw_walls(screen_offset);
1082 if (button_up_pressed)
1084 pacman.next_dir.x = 0;
1085 pacman.next_dir.y = -1;
1087 if (button_down_pressed)
1089 pacman.next_dir.x = 0;
1090 pacman.next_dir.y = 1;
1092 if (button_left_pressed)
1094 pacman.next_dir.x = -1;
1095 pacman.next_dir.y = 0;
1097 if (button_right_pressed)
1099 pacman.next_dir.x = 1;
1100 pacman.next_dir.y = 0;
1107 #ifdef ALLOW_SCREENSHOT
1108 if (take_screenshot)
1111 // take_screenshot = 0;
1114 ssd130x_display_full_screen(&display);
1118 int px = pacman.position.x * 4 + pacman.sub_step.x;
1119 int py = pacman.position.y * 4 + pacman.sub_step.y;
1120 for (i = 0; i < 4; i++)
1122 int gx = ghosts[i].position.x * 4 + ghosts[i].offset.y;
1123 int gy = ghosts[i].position.y * 4 + ghosts[i].offset.y;
1124 if (px <= gx + 2 && px >= gx - 2 &&
1125 py <= gy + 2 && py >= gy - 2)
1127 if (ghosts[i].mode == GM_FRIGHTENED)
1130 for (s = 0; s < ghost_score; s++)
1133 ghosts[i].mode = GM_EATEN;
1138 for (i = 0; i < GN_NB_GHOSTS; i++)
1139 switch (ghosts[i].mode)
1142 ghosts[i].target.x = 15;
1143 ghosts[i].target.y = 13;
1145 case GM_CORNERS: // FIXME! ugly
1148 ghosts[0].target.x = 28; ghosts[0].target.y = -2;
1150 else if (i == GN_PINKY)
1152 ghosts[1].target.x = 5; ghosts[1].target.y = -2;
1154 else if (i == GN_INKY)
1156 ghosts[2].target.x = 0; ghosts[2].target.y = 31;
1160 ghosts[3].target.x = 31; ghosts[3].target.y = 31;
1164 ghosts[i].target.x = my_rand() & 31;
1165 ghosts[i].target.y = my_rand() & 31;
1170 ghosts[i].target.x = 16;
1171 ghosts[i].target.y = 11;
1179 unsigned t = systick_get_tick_count();
1180 static unsigned fps = 0;
1183 // uprintf(UART0, "%u ", fps);