@@ -0,0 +1,631 @@
/*
* Paku Paku for Game Boy — port of presets / pacman / pakupaku . c
*
* One - lane chase inspired by crisp - game - lib " PAKU PAKU " :
* A / Start = reverse Left / Right = face that way
* Collect dots ; power pellet makes the ghost edible .
* Movement / AI match the Pac - Man hardware port ; graphics from pacman .5 e / 5f
* ( regenerate with : python3 scripts / gen_gb_pakupaku_gfx . py ) .
*/
//#link "gb/sfr.sgb"
//#link "gb/crt0.sgb"
//#resource "gb/global.sgb"
# include <stdint.h>
# include "gb/types.h"
# include "gb/hardware.h"
# include "gb/gb.h"
typedef uint8_t byte ;
typedef uint16_t word ;
typedef int8_t sbyte ;
# define FIELD_MAX 152 /* arcade 208 scaled to GB width */
# define PLAYER_SPD 2
# define NUM_DOTS 18
# define HIT_DIST 12
# define ROW_ABOVE 8
# define DOT_TILE_Y 9
# define ROW_BELOW 10
# define CORRIDOR_Y 68
/* BG tiles from pacman.5e (after font 0..34) */
# define BKG_BASE 40
# define T_WALL_ABOVE (BKG_BASE + 0)
# define T_WALL_BELOW (BKG_BASE + 1)
# define T_DOT (BKG_BASE + 2)
# define T_POWER (BKG_BASE + 3)
/*
* Arcade pacman .5f sprites → GB 16 × 16 ( two 8 × 16 OAM each ) .
* Each frame is 4 tiles at SPR_BASE : L - top , L - bot , R - top , R - bot .
* Regenerate : python3 scripts / gen_gb_pakupaku_gfx . py
*/
# define SPR_BASE 48
# define SPR_FRAME(i) ((byte)(SPR_BASE + (i) * 4))
# define SP_OPEN SPR_FRAME(0)
# define SP_MID SPR_FRAME(1)
# define SP_CLOSED SPR_FRAME(2)
# define SP_DEATH0 SPR_FRAME(3) /* 11 frames: 3..13 */
# define SP_DEATH_N 11
# define SP_GHOST0 SPR_FRAME(14)
# define SP_GHOST1 SPR_FRAME(15)
# define SP_SCARED0 SPR_FRAME(16)
# define SP_SCARED1 SPR_FRAME(17)
# define SP_EYES SPR_FRAME(18)
# define SPR_TILE_COUNT 76
typedef struct {
byte tx ;
byte active ;
byte is_power ;
} Dot ;
word rnd = 0xCACE ;
word score ;
byte multiplier ;
byte player_x ;
sbyte player_vx ;
byte enemy_x ;
sbyte enemy_eye_vx ;
word power_ticks ;
word anim_ticks ;
byte btn_prev ;
byte game_over ;
byte waka ;
Dot dots [ NUM_DOTS ] ;
byte joy_left , joy_right , joy_fire , joy_start ;
byte sfx_timer ;
byte sfx_kind ; /* 0=off 1/2=waka 3=eat 4=death 6=power */
byte death_phase ;
const uint8_t font_1bpp [ ] = {
/* 0 space */ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
/* 1 '0' */ 0x3C , 0x66 , 0x6E , 0x76 , 0x66 , 0x66 , 0x3C , 0x00 ,
/* 2 '1' */ 0x18 , 0x38 , 0x18 , 0x18 , 0x18 , 0x18 , 0x7E , 0x00 ,
/* 3 '2' */ 0x3C , 0x66 , 0x06 , 0x0C , 0x18 , 0x30 , 0x7E , 0x00 ,
/* 4 '3' */ 0x3C , 0x66 , 0x06 , 0x1C , 0x06 , 0x66 , 0x3C , 0x00 ,
/* 5 '4' */ 0x0C , 0x1C , 0x3C , 0x6C , 0x7E , 0x0C , 0x0C , 0x00 ,
/* 6 '5' */ 0x7E , 0x60 , 0x7C , 0x06 , 0x06 , 0x66 , 0x3C , 0x00 ,
/* 7 '6' */ 0x1C , 0x30 , 0x60 , 0x7C , 0x66 , 0x66 , 0x3C , 0x00 ,
/* 8 '7' */ 0x7E , 0x06 , 0x0C , 0x18 , 0x30 , 0x30 , 0x30 , 0x00 ,
/* 9 '8' */ 0x3C , 0x66 , 0x66 , 0x3C , 0x66 , 0x66 , 0x3C , 0x00 ,
/*10 '9' */ 0x3C , 0x66 , 0x66 , 0x3E , 0x06 , 0x0C , 0x38 , 0x00 ,
/*11 'A' */ 0x3C , 0x66 , 0x66 , 0x7E , 0x66 , 0x66 , 0x66 , 0x00 ,
/*12 'C' */ 0x3C , 0x66 , 0x60 , 0x60 , 0x60 , 0x66 , 0x3C , 0x00 ,
/*13 'E' */ 0x7E , 0x60 , 0x60 , 0x7C , 0x60 , 0x60 , 0x7E , 0x00 ,
/*14 'F' */ 0x7E , 0x60 , 0x60 , 0x7C , 0x60 , 0x60 , 0x60 , 0x00 ,
/*15 'G' */ 0x3C , 0x66 , 0x60 , 0x6E , 0x66 , 0x66 , 0x3C , 0x00 ,
/*16 'H' */ 0x66 , 0x66 , 0x66 , 0x7E , 0x66 , 0x66 , 0x66 , 0x00 ,
/*17 'I' */ 0x3C , 0x18 , 0x18 , 0x18 , 0x18 , 0x18 , 0x3C , 0x00 ,
/*18 'K' */ 0x66 , 0x6C , 0x78 , 0x70 , 0x78 , 0x6C , 0x66 , 0x00 ,
/*19 'L' */ 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x7E , 0x00 ,
/*20 'M' */ 0x63 , 0x77 , 0x7F , 0x6B , 0x63 , 0x63 , 0x63 , 0x00 ,
/*21 'N' */ 0x66 , 0x76 , 0x7E , 0x7E , 0x6E , 0x66 , 0x66 , 0x00 ,
/*22 'O' */ 0x3C , 0x66 , 0x66 , 0x66 , 0x66 , 0x66 , 0x3C , 0x00 ,
/*23 'P' */ 0x7C , 0x66 , 0x66 , 0x7C , 0x60 , 0x60 , 0x60 , 0x00 ,
/*24 'R' */ 0x7C , 0x66 , 0x66 , 0x7C , 0x6C , 0x66 , 0x66 , 0x00 ,
/*25 'S' */ 0x3C , 0x66 , 0x60 , 0x3C , 0x06 , 0x66 , 0x3C , 0x00 ,
/*26 'T' */ 0x7E , 0x18 , 0x18 , 0x18 , 0x18 , 0x18 , 0x18 , 0x00 ,
/*27 'U' */ 0x66 , 0x66 , 0x66 , 0x66 , 0x66 , 0x66 , 0x3C , 0x00 ,
/*28 'V' */ 0x66 , 0x66 , 0x66 , 0x66 , 0x66 , 0x3C , 0x18 , 0x00 ,
/*29 'W' */ 0x63 , 0x63 , 0x63 , 0x6B , 0x7F , 0x77 , 0x63 , 0x00 ,
/*30 'X' */ 0x66 , 0x66 , 0x3C , 0x18 , 0x3C , 0x66 , 0x66 , 0x00 ,
/*31 'D' */ 0x78 , 0x6C , 0x66 , 0x66 , 0x66 , 0x6C , 0x78 , 0x00 ,
/*32 '-' */ 0x00 , 0x00 , 0x00 , 0x7E , 0x00 , 0x00 , 0x00 , 0x00 ,
/*33 '!' */ 0x18 , 0x18 , 0x18 , 0x18 , 0x18 , 0x00 , 0x18 , 0x00 ,
/*34 '/' */ 0x06 , 0x06 , 0x0C , 0x18 , 0x30 , 0x60 , 0x60 , 0x00 ,
} ;
const uint8_t bkg_tiles [ ] = {
/*{w:8,h:8,bpp:1,count:4,brev:1,np:2,pofs:1,sl:2}*/
0xff , 0xff , 0x00 , 0xff , 0x00 , 0xff , 0xff , 0xff , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xff , 0xff , 0x00 , 0xff , 0x00 , 0xff , 0xff , 0xff ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x18 , 0x00 , 0x18 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x3c , 0x00 , 0x7e , 0x00 , 0xff , 0x00 , 0xff , 0x00 , 0xff , 0x00 , 0xff , 0x00 , 0x7e , 0x00 , 0x3c , 0x00 ,
} ;
const uint8_t sprite_tiles [ ] = {
/*{w:8,h:8,bpp:1,count:76,brev:1,np:2,pofs:1,sl:2}*/
0x00 , 0x00 , 0x07 , 0x07 , 0x1f , 0x1f , 0x3f , 0x3f , 0x3f , 0x3f , 0x7e , 0x7e , 0x7c , 0x7c , 0x78 , 0x78 ,
0x7c , 0x7c , 0x7e , 0x7e , 0x3f , 0x3f , 0x3f , 0x3f , 0x1f , 0x1f , 0x07 , 0x07 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0xc0 , 0xc0 , 0xc0 , 0xc0 , 0x80 , 0x80 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x80 , 0x80 , 0xc0 , 0xc0 , 0xc0 , 0xc0 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x07 , 0x07 , 0x1f , 0x1f , 0x3f , 0x3f , 0x3f , 0x3f , 0x7f , 0x7f , 0x7f , 0x7f , 0x78 , 0x78 ,
0x7f , 0x7f , 0x7f , 0x7f , 0x3f , 0x3f , 0x3f , 0x3f , 0x1f , 0x1f , 0x07 , 0x07 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0xc0 , 0xc0 , 0xf0 , 0xf0 , 0xf8 , 0xf8 , 0xf8 , 0xf8 , 0xe0 , 0xe0 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0xe0 , 0xe0 , 0xf8 , 0xf8 , 0xf8 , 0xf8 , 0xf0 , 0xf0 , 0xc0 , 0xc0 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x07 , 0x07 , 0x1f , 0x1f , 0x3f , 0x3f , 0x3f , 0x3f , 0x7f , 0x7f , 0x7f , 0x7f , 0x7f , 0x7f ,
0x7f , 0x7f , 0x7f , 0x7f , 0x3f , 0x3f , 0x3f , 0x3f , 0x1f , 0x1f , 0x07 , 0x07 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0xc0 , 0xc0 , 0xf0 , 0xf0 , 0xf8 , 0xf8 , 0xf8 , 0xf8 , 0xfc , 0xfc , 0xfc , 0xfc , 0xfc , 0xfc ,
0xfc , 0xfc , 0xfc , 0xfc , 0xf8 , 0xf8 , 0xf8 , 0xf8 , 0xf0 , 0xf0 , 0xc0 , 0xc0 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x60 , 0x60 , 0x70 , 0x70 , 0x78 , 0x78 , 0x7c , 0x7c , 0x7e , 0x7e ,
0x3f , 0x3f , 0x3f , 0x3f , 0x1f , 0x1f , 0x07 , 0x07 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x0c , 0x0c , 0x1c , 0x1c , 0x3c , 0x3c , 0x7c , 0x7c , 0xfc , 0xfc ,
0xf8 , 0xf8 , 0xf8 , 0xf8 , 0xf0 , 0xf0 , 0xc0 , 0xc0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x40 , 0x40 , 0xf0 , 0xf0 , 0xf8 , 0xf8 , 0xfe , 0xfe ,
0x7f , 0x7f , 0x7f , 0x7f , 0x3f , 0x3f , 0x0e , 0x0e , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x04 , 0x04 , 0x1e , 0x1e , 0x3e , 0x3e , 0xfe , 0xfe ,
0xfc , 0xfc , 0xfc , 0xfc , 0xf8 , 0xf8 , 0xe0 , 0xe0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xe0 , 0xe0 , 0xfc , 0xfc ,
0xff , 0xff , 0x7f , 0x7f , 0x3f , 0x3f , 0x0e , 0x0e , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x0e , 0x0e , 0x7e , 0x7e ,
0xfe , 0xfe , 0xfc , 0xfc , 0xf8 , 0xf8 , 0xe0 , 0xe0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xf0 , 0xf0 ,
0xff , 0xff , 0xff , 0xff , 0x7f , 0x7f , 0x1e , 0x1e , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x1e , 0x1e ,
0xfe , 0xfe , 0xfe , 0xfe , 0xfc , 0xfc , 0xf0 , 0xf0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x0f , 0x0f , 0xff , 0xff , 0xff , 0xff , 0x7f , 0x7f , 0x1e , 0x1e , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0xe0 , 0xe0 , 0xfe , 0xfe , 0xfe , 0xfe , 0xfc , 0xfc , 0xf0 , 0xf0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x03 , 0x03 , 0x0f , 0x0f , 0x7f , 0x7f , 0xff , 0xff , 0x7e , 0x7e , 0x1c , 0x1c , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x80 , 0x80 , 0xe0 , 0xe0 , 0xfc , 0xfc , 0xfe , 0xfe , 0xfc , 0xfc , 0x70 , 0x70 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x01 , 0x01 , 0x03 , 0x03 , 0x0f , 0x0f , 0x1f , 0x1f , 0x7f , 0x7f , 0x7e , 0x7e , 0x3c , 0x3c , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x80 , 0x80 , 0xe0 , 0xe0 , 0xf0 , 0xf0 , 0xfc , 0xfc , 0xfc , 0xfc , 0x78 , 0x78 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x01 , 0x01 , 0x03 , 0x03 , 0x07 , 0x07 , 0x07 , 0x07 , 0x0f , 0x0f , 0x1f , 0x1f , 0x0e , 0x0e , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x80 , 0x80 , 0xc0 , 0xc0 , 0xc0 , 0xc0 , 0xe0 , 0xe0 , 0xf0 , 0xf0 , 0xe0 , 0xe0 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x01 , 0x01 , 0x01 , 0x01 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x07 , 0x07 , 0x02 , 0x02 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0xc0 , 0xc0 , 0x80 , 0x80 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x04 , 0x04 , 0x12 , 0x12 ,
0x08 , 0x08 , 0x00 , 0x00 , 0x30 , 0x30 , 0x00 , 0x00 , 0x08 , 0x08 , 0x10 , 0x10 , 0x02 , 0x02 , 0x04 , 0x04 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x40 , 0x40 , 0x80 , 0x80 ,
0x10 , 0x10 , 0x20 , 0x20 , 0x00 , 0x00 , 0x18 , 0x18 , 0x00 , 0x00 , 0x20 , 0x20 , 0x90 , 0x90 , 0x40 , 0x40 ,
0x00 , 0x00 , 0x03 , 0x03 , 0x0f , 0x0f , 0x1f , 0x1f , 0x3f , 0x39 , 0x3f , 0x30 , 0x3c , 0x33 , 0x7c , 0x73 ,
0x7f , 0x79 , 0x7f , 0x7f , 0x7f , 0x7f , 0x7f , 0x7f , 0x7f , 0x7f , 0x6e , 0x6e , 0x46 , 0x46 , 0x00 , 0x00 ,
0x00 , 0x00 , 0xc0 , 0xc0 , 0xf0 , 0xf0 , 0xf8 , 0xf8 , 0xfc , 0xe4 , 0xfc , 0xc0 , 0xf0 , 0xcc , 0xf2 , 0xce ,
0xfe , 0xe6 , 0xfe , 0xfe , 0xfe , 0xfe , 0xfe , 0xfe , 0xfe , 0xfe , 0x76 , 0x76 , 0x62 , 0x62 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x03 , 0x03 , 0x0f , 0x0f , 0x1f , 0x1f , 0x3f , 0x39 , 0x3f , 0x30 , 0x3c , 0x33 , 0x7c , 0x73 ,
0x7f , 0x79 , 0x7f , 0x7f , 0x7f , 0x7f , 0x7f , 0x7f , 0x7f , 0x7f , 0x7b , 0x7b , 0x31 , 0x31 , 0x00 , 0x00 ,
0x00 , 0x00 , 0xc0 , 0xc0 , 0xf0 , 0xf0 , 0xf8 , 0xf8 , 0xfc , 0xe4 , 0xfc , 0xc0 , 0xf0 , 0xcc , 0xf2 , 0xce ,
0xfe , 0xe6 , 0xfe , 0xfe , 0xfe , 0xfe , 0xfe , 0xfe , 0xfe , 0xfe , 0xde , 0xde , 0x8c , 0x8c , 0x00 , 0x00 ,
0x00 , 0x00 , 0x03 , 0x03 , 0x0f , 0x0f , 0x1f , 0x1f , 0x3f , 0x3f , 0x3f , 0x3f , 0x3f , 0x39 , 0x7f , 0x79 ,
0x7f , 0x7f , 0x7f , 0x7f , 0x7f , 0x66 , 0x7f , 0x59 , 0x7f , 0x7f , 0x6e , 0x6e , 0x46 , 0x46 , 0x00 , 0x00 ,
0x00 , 0x00 , 0xc0 , 0xc0 , 0xf0 , 0xf0 , 0xf8 , 0xf8 , 0xfc , 0xfc , 0xfc , 0xfc , 0xfc , 0x9c , 0xfe , 0x9e ,
0xfe , 0xfe , 0xfe , 0xfe , 0xfe , 0x66 , 0xfe , 0x9a , 0xfe , 0xfe , 0x76 , 0x76 , 0x62 , 0x62 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x03 , 0x03 , 0x0f , 0x0f , 0x1f , 0x1f , 0x3f , 0x3f , 0x3f , 0x3f , 0x3f , 0x39 , 0x7f , 0x79 ,
0x7f , 0x7f , 0x7f , 0x7f , 0x7f , 0x66 , 0x7f , 0x59 , 0x7f , 0x7f , 0x7b , 0x7b , 0x31 , 0x31 , 0x00 , 0x00 ,
0x00 , 0x00 , 0xc0 , 0xc0 , 0xf0 , 0xf0 , 0xf8 , 0xf8 , 0xfc , 0xfc , 0xfc , 0xfc , 0xfc , 0x9c , 0xfe , 0x9e ,
0xfe , 0xfe , 0xfe , 0xfe , 0xfe , 0x66 , 0xfe , 0x9a , 0xfe , 0xfe , 0xde , 0xde , 0x8c , 0x8c , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x06 , 0x00 , 0x0f , 0x00 , 0x0c , 0x00 , 0x0c , 0x00 ,
0x06 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x18 , 0x00 , 0x3c , 0x00 , 0x30 , 0x00 , 0x30 , 0x00 ,
0x18 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
} ;
byte rand8 ( void ) {
rnd = rnd * 17 + 53 ;
return ( byte ) ( rnd > > 8 ) ;
}
byte abs_diff ( byte a , byte b ) {
return ( a > b ) ? ( byte ) ( a - b ) : ( byte ) ( b - a ) ;
}
byte glyph ( char c ) {
if ( c = = ' ' ) return 0 ;
if ( c > = ' 0 ' & & c < = ' 9 ' ) return ( byte ) ( 1 + ( c - ' 0 ' ) ) ;
switch ( c ) {
case ' A ' : return 11 ; case ' C ' : return 12 ; case ' E ' : return 13 ;
case ' F ' : return 14 ; case ' G ' : return 15 ; case ' H ' : return 16 ;
case ' I ' : return 17 ; case ' K ' : return 18 ; case ' L ' : return 19 ;
case ' M ' : return 20 ; case ' N ' : return 21 ; case ' O ' : return 22 ;
case ' P ' : return 23 ; case ' R ' : return 24 ; case ' S ' : return 25 ;
case ' T ' : return 26 ; case ' U ' : return 27 ; case ' V ' : return 28 ;
case ' W ' : return 29 ; case ' X ' : return 30 ; case ' D ' : return 31 ;
case ' - ' : return 32 ; case ' ! ' : return 33 ; case ' / ' : return 34 ;
default : return 0 ;
}
}
void put_str ( byte x , byte y , const char * s ) {
while ( * s ) set_bkg_tile_xy ( x + + , y , glyph ( * s + + ) ) ;
}
void put_digit ( byte x , byte y , byte d ) {
set_bkg_tile_xy ( x , y , ( byte ) ( 1 + ( d % 10 ) ) ) ;
}
void clrscr ( void ) {
byte x , y ;
for ( y = 0 ; y < 32 ; y + + )
for ( x = 0 ; x < 32 ; x + + )
set_bkg_tile_xy ( x , y , 0 ) ;
}
void hide_all_sprites ( void ) {
byte i ;
for ( i = 0 ; i < 40 ; i + + ) move_sprite ( i , 0 , 0 ) ;
}
void read_controls ( void ) {
byte j = joypad ( ) ;
joy_left = ( j & J_LEFT ) ! = 0 ;
joy_right = ( j & J_RIGHT ) ! = 0 ;
joy_fire = ( j & J_A ) ! = 0 ;
joy_start = ( j & J_START ) ! = 0 ;
}
void psg_init ( void ) {
NR52_REG = 0x80 ;
NR50_REG = 0x77 ;
NR51_REG = 0xFF ;
NR10_REG = 0x00 ;
}
void sfx_off ( void ) {
sfx_timer = 0 ;
sfx_kind = 0 ;
NR12_REG = 0x00 ;
NR14_REG = 0x80 ;
NR22_REG = 0x00 ;
NR24_REG = 0x80 ;
}
void beep ( word per , byte vol , byte len ) {
/* ch1 one-shot */
NR10_REG = 0x00 ;
NR11_REG = 0x80 ;
NR12_REG = ( byte ) ( ( vol < < 4 ) | 0x01 ) ;
NR13_REG = ( byte ) ( per & 0xff ) ;
NR14_REG = ( byte ) ( 0x80 | ( ( per > > 8 ) & 0x07 ) ) ;
sfx_timer = len ;
}
void play_sfx ( byte id ) {
sfx_kind = id ;
if ( id = = 4 ) death_phase = 0 ;
switch ( id ) {
case 1 : beep ( 0x6C0 , 10 , 3 ) ; break ; /* waka hi */
case 2 : beep ( 0x650 , 9 , 3 ) ; break ; /* waka lo */
case 3 : beep ( 0x700 , 12 , 12 ) ; break ; /* eat ghost */
case 4 : beep ( 0x480 , 12 , 40 ) ; break ; /* death */
case 6 : beep ( 0x720 , 11 , 8 ) ; break ; /* power */
default : sfx_off ( ) ; break ;
}
}
void tick_sfx ( void ) {
if ( ! sfx_timer ) return ;
- - sfx_timer ;
if ( ! sfx_timer & & sfx_kind = = 4 ) {
death_phase + + ;
if ( death_phase < 4 ) {
beep ( ( word ) ( 0x480 - death_phase * 0x40 ) , 10 , 10 ) ;
sfx_kind = 4 ;
} else {
death_phase = 0 ;
sfx_kind = 0 ;
}
}
}
void wait_vblank ( void ) {
wait_vbl_done ( ) ;
tick_sfx ( ) ;
}
void wait_frames ( byte n ) {
while ( n - - ) wait_vblank ( ) ;
}
void wait_for_button ( void ) {
read_controls ( ) ;
while ( ! joy_fire & & ! joy_start ) { wait_vblank ( ) ; read_controls ( ) ; }
while ( joy_fire | | joy_start ) { wait_vblank ( ) ; read_controls ( ) ; }
}
void draw_hud ( void ) {
put_str ( 0 , 0 , " PAKU PAKU " ) ;
put_str ( 0 , 1 , " SCORE " ) ;
put_digit ( 6 , 1 , ( byte ) ( ( score / 1000 ) % 10 ) ) ;
put_digit ( 7 , 1 , ( byte ) ( ( score / 100 ) % 10 ) ) ;
put_digit ( 8 , 1 , ( byte ) ( ( score / 10 ) % 10 ) ) ;
put_digit ( 9 , 1 , ( byte ) ( score % 10 ) ) ;
put_str ( 12 , 1 , " X " ) ;
put_digit ( 13 , 1 , multiplier > 9 ? 9 : multiplier ) ;
put_str ( 0 , 17 , " A=TURN " ) ;
}
void draw_corridor ( void ) {
byte x ;
for ( x = 0 ; x < 20 ; x + + ) {
set_bkg_tile_xy ( x , ROW_ABOVE , T_WALL_ABOVE ) ;
set_bkg_tile_xy ( x , DOT_TILE_Y , 0 ) ;
set_bkg_tile_xy ( x , ROW_BELOW , T_WALL_BELOW ) ;
}
}
void add_dots ( void ) {
byte i , pi ;
pi = ( player_x > 80 ) ? ( byte ) ( 1 + ( rand8 ( ) % 7 ) ) : ( byte ) ( 10 + ( rand8 ( ) % 7 ) ) ;
for ( i = 0 ; i < NUM_DOTS ; i + + ) {
dots [ i ] . tx = ( byte ) ( i + 1 ) ;
dots [ i ] . active = 1 ;
dots [ i ] . is_power = ( i = = pi ) ;
}
if ( multiplier < 99 ) multiplier + + ;
}
void draw_dots ( void ) {
byte i ;
for ( i = 0 ; i < NUM_DOTS ; i + + ) {
if ( ! dots [ i ] . active ) {
set_bkg_tile_xy ( dots [ i ] . tx , DOT_TILE_Y , 0 ) ;
continue ;
}
if ( dots [ i ] . is_power ) {
if ( ( anim_ticks > > 3 ) & 1 )
set_bkg_tile_xy ( dots [ i ] . tx , DOT_TILE_Y , T_POWER ) ;
else
set_bkg_tile_xy ( dots [ i ] . tx , DOT_TILE_Y , 0 ) ;
} else {
set_bkg_tile_xy ( dots [ i ] . tx , DOT_TILE_Y , T_DOT ) ;
}
}
}
void collect_dots ( void ) {
byte i , ptx ;
ptx = ( byte ) ( ( player_x + 8 ) > > 3 ) ;
if ( ptx < 1 ) ptx = 1 ;
if ( ptx > NUM_DOTS ) ptx = NUM_DOTS ;
for ( i = 0 ; i < NUM_DOTS ; i + + ) {
if ( ! dots [ i ] . active ) continue ;
if ( dots [ i ] . tx ! = ptx ) continue ;
dots [ i ] . active = 0 ;
set_bkg_tile_xy ( dots [ i ] . tx , DOT_TILE_Y , 0 ) ;
if ( dots [ i ] . is_power ) {
play_sfx ( 6 ) ;
if ( ! enemy_eye_vx ) power_ticks = 200 ;
} else {
waka ^ = 1 ;
play_sfx ( waka ? 1 : 2 ) ;
}
score + = multiplier ;
}
}
byte dots_left ( void ) {
byte i , n = 0 ;
for ( i = 0 ; i < NUM_DOTS ; i + + )
if ( dots [ i ] . active ) n + + ;
return n ;
}
byte pac_frame ( void ) {
byte ai = ( byte ) ( anim_ticks & 3 ) ;
if ( ai = = 0 ) return SP_OPEN ;
if ( ai = = 1 ) return SP_MID ;
if ( ai = = 2 ) return SP_CLOSED ;
return SP_MID ;
}
void put_actor16 ( byte i0 , byte frame , byte flip , byte prop , byte x , byte y ) {
/* Two 8× 16 sprites = one 16× 16 arcade sprite; swap halves when flipped. */
byte i1 = ( byte ) ( i0 + 1 ) ;
byte p = prop ;
byte oam0 , oam1 ;
if ( flip ) p | = S_FLIPX ;
set_sprite_tile ( i0 , frame ) ;
set_sprite_tile ( i1 , ( byte ) ( frame + 2 ) ) ;
set_sprite_prop ( i0 , p ) ;
set_sprite_prop ( i1 , p ) ;
if ( flip ) {
oam0 = ( byte ) ( x + 16 ) ;
oam1 = ( byte ) ( x + 8 ) ;
} else {
oam0 = ( byte ) ( x + 8 ) ;
oam1 = ( byte ) ( x + 16 ) ;
}
/* Hide if past the right edge (OAM X wraps). */
if ( x > 152 ) {
move_sprite ( i0 , 0 , 0 ) ;
move_sprite ( i1 , 0 , 0 ) ;
return ;
}
move_sprite ( i0 , oam0 , ( byte ) ( y + 16 ) ) ;
move_sprite ( i1 , oam1 , ( byte ) ( y + 16 ) ) ;
}
void draw_actors ( void ) {
byte ghost , gprop , pflip , gflip ;
sbyte evx ;
pflip = ( player_vx < 0 ) ? 1 : 0 ;
put_actor16 ( 0 , pac_frame ( ) , pflip , 0 , player_x , CORRIDOR_Y ) ;
if ( enemy_eye_vx ) {
ghost = SP_EYES ;
gflip = ( enemy_eye_vx < 0 ) ? 1 : 0 ;
gprop = 0 ;
} else if ( power_ticks ) {
ghost = ( ( anim_ticks > > 1 ) & 1 ) ? SP_SCARED1 : SP_SCARED0 ;
gflip = 0 ;
gprop = 0 ;
/* blink near end of power */
if ( power_ticks < 60 & & ( anim_ticks & 0x08 ) ) {
move_sprite ( 2 , 0 , 0 ) ;
move_sprite ( 3 , 0 , 0 ) ;
return ;
}
} else {
ghost = ( ( anim_ticks > > 1 ) & 1 ) ? SP_GHOST1 : SP_GHOST0 ;
evx = ( player_x > enemy_x ) ? 1 : - 1 ;
gflip = ( evx < 0 ) ? 1 : 0 ;
gprop = 0 ;
}
put_actor16 ( 2 , ghost , gflip , gprop , enemy_x , CORRIDOR_Y ) ;
}
void title_screen ( void ) {
byte x ;
clrscr ( ) ;
hide_all_sprites ( ) ;
move_bkg ( 0 , 0 ) ;
/* corridor stripe behind the demo sprites */
for ( x = 0 ; x < 20 ; x + + ) {
set_bkg_tile_xy ( x , 6 , T_WALL_ABOVE ) ;
set_bkg_tile_xy ( x , 7 , 0 ) ;
set_bkg_tile_xy ( x , 8 , T_WALL_BELOW ) ;
}
put_str ( 5 , 2 , " PAKU PAKU " ) ;
put_actor16 ( 0 , SP_OPEN , 0 , 0 , 52 , 48 ) ;
put_actor16 ( 2 , SP_GHOST0 , 0 , 0 , 92 , 48 ) ;
put_str ( 4 , 11 , " A TO TURN " ) ;
put_str ( 2 , 13 , " EAT DOTS EAT GHOST " ) ;
put_str ( 4 , 16 , " PRESS START " ) ;
wait_for_button ( ) ;
sfx_off ( ) ;
}
void show_game_over ( void ) {
byte frame_i , t , frame ;
hide_all_sprites ( ) ;
put_actor16 ( 0 , SP_OPEN , 0 , 0 , player_x , CORRIDOR_Y ) ;
play_sfx ( 4 ) ;
/* Arcade: 11 frames × 8 vblanks */
for ( frame_i = 0 ; frame_i < SP_DEATH_N ; frame_i + + ) {
frame = ( byte ) ( SP_DEATH0 + ( byte ) ( frame_i * 4 ) ) ;
for ( t = 0 ; t < 8 ; t + + ) {
put_actor16 ( 0 , frame , 0 , 0 , player_x , CORRIDOR_Y ) ;
wait_vblank ( ) ;
read_controls ( ) ;
if ( joy_fire | | joy_start ) goto death_done ;
}
}
death_done :
hide_all_sprites ( ) ;
put_str ( 5 , 7 , " GAME OVER " ) ;
put_str ( 4 , 10 , " PRESS START " ) ;
wait_for_button ( ) ;
sfx_off ( ) ;
}
void reset_round ( void ) {
player_x = 48 ;
player_vx = 1 ;
enemy_x = 128 ;
enemy_eye_vx = 0 ;
power_ticks = 0 ;
anim_ticks = 0 ;
btn_prev = 1 ;
game_over = 0 ;
waka = 0 ;
sfx_off ( ) ;
draw_corridor ( ) ;
add_dots ( ) ;
}
void game_loop ( void ) {
byte btn ;
sbyte evx ;
byte espd ;
clrscr ( ) ;
hide_all_sprites ( ) ;
move_bkg ( 0 , 0 ) ;
draw_corridor ( ) ;
draw_hud ( ) ;
reset_round ( ) ;
while ( ! game_over ) {
wait_vblank ( ) ;
anim_ticks + + ;
read_controls ( ) ;
btn = ( joy_fire | | joy_start ) ? 1 : 0 ;
if ( btn & & ! btn_prev ) player_vx = ( sbyte ) - player_vx ;
btn_prev = btn ;
if ( joy_left ) player_vx = - 1 ;
if ( joy_right ) player_vx = 1 ;
/* Same wrap as pacman pakupaku.c */
player_x = ( byte ) ( player_x + player_vx * PLAYER_SPD ) ;
if ( player_x < 4 ) player_x = FIELD_MAX ;
else if ( player_x > FIELD_MAX ) player_x = 4 ;
collect_dots ( ) ;
if ( ! dots_left ( ) ) add_dots ( ) ;
/* Ghost AI — identical rules to presets/pacman/pakupaku.c */
if ( enemy_eye_vx ) {
evx = enemy_eye_vx ;
espd = 3 ;
} else if ( power_ticks ) {
evx = ( player_x > enemy_x ) ? ( sbyte ) - 1 : 1 ;
espd = 1 ;
} else {
evx = ( player_x > enemy_x ) ? 1 : - 1 ;
espd = 2 ;
}
if ( evx > 0 ) {
if ( enemy_x < FIELD_MAX - 2 ) enemy_x = ( byte ) ( enemy_x + espd ) ;
else if ( enemy_eye_vx ) enemy_eye_vx = 0 ;
} else {
if ( enemy_x > 6 ) enemy_x = ( byte ) ( enemy_x - espd ) ;
else if ( enemy_eye_vx ) enemy_eye_vx = 0 ;
}
if ( ! enemy_eye_vx & & abs_diff ( player_x , enemy_x ) < HIT_DIST ) {
if ( power_ticks ) {
play_sfx ( 3 ) ;
score + = ( word ) ( 10 * ( multiplier ? multiplier : 1 ) ) ;
enemy_eye_vx = ( player_x > 80 ) ? ( sbyte ) - 1 : 1 ;
power_ticks = 0 ;
if ( multiplier < 99 ) multiplier + + ;
} else {
game_over = 1 ;
}
}
if ( power_ticks ) power_ticks - - ;
draw_dots ( ) ;
draw_hud ( ) ;
draw_actors ( ) ;
}
}
void setup_graphics ( void ) {
DISPLAY_OFF ;
set_bkg_1bpp_data ( 0 , 35 , font_1bpp ) ;
set_bkg_data ( BKG_BASE , 4 , bkg_tiles ) ;
set_sprite_data ( SPR_BASE , SPR_TILE_COUNT , sprite_tiles ) ;
SPRITES_8x16 ;
BGP_REG = 0xE4 ;
OBP0_REG = 0xE4 ;
OBP1_REG = 0xE4 ;
psg_init ( ) ;
HIDE_WIN ;
SHOW_BKG ;
SHOW_SPRITES ;
DISPLAY_ON ;
}
void main ( void ) {
setup_graphics ( ) ;
score = 0 ;
multiplier = 0 ;
while ( 1 ) {
title_screen ( ) ;
score = 0 ;
multiplier = 0 ;
game_loop ( ) ;
show_game_over ( ) ;
}
}