1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-06-02 12:41:30 +00:00
8bitworkshop/presets/apple2/cosmic.c
2018-08-06 14:54:18 -04:00

557 lines
16 KiB
C

#include <string.h>
#include <conio.h>
#include <apple2.h>
typedef unsigned char byte;
typedef signed char sbyte;
typedef unsigned short word;
#define POKE(addr,val) (*(unsigned char*) (addr) = (val))
#define POKEW(addr,val) (*(unsigned*) (addr) = (val))
#define PEEK(addr) (*(unsigned char*) (addr))
#define PEEKW(addr) (*(unsigned*) (addr))
#define STROBE(addr) __asm__ ("sta %w", addr)
#define CLICK STROBE(0xc030)
/// HIRES LOOKUP TABLE
#define VHEIGHT 192
#define VBWIDTH 40
#define LUT(x) (byte*)(0x2000|x)
static byte* vidmem[VHEIGHT] = {
LUT(0x0000), LUT(0x0400), LUT(0x0800), LUT(0x0c00), LUT(0x1000), LUT(0x1400), LUT(0x1800), LUT(0x1c00),
LUT(0x0080), LUT(0x0480), LUT(0x0880), LUT(0x0c80), LUT(0x1080), LUT(0x1480), LUT(0x1880), LUT(0x1c80),
LUT(0x0100), LUT(0x0500), LUT(0x0900), LUT(0x0d00), LUT(0x1100), LUT(0x1500), LUT(0x1900), LUT(0x1d00),
LUT(0x0180), LUT(0x0580), LUT(0x0980), LUT(0x0d80), LUT(0x1180), LUT(0x1580), LUT(0x1980), LUT(0x1d80),
LUT(0x0200), LUT(0x0600), LUT(0x0a00), LUT(0x0e00), LUT(0x1200), LUT(0x1600), LUT(0x1a00), LUT(0x1e00),
LUT(0x0280), LUT(0x0680), LUT(0x0a80), LUT(0x0e80), LUT(0x1280), LUT(0x1680), LUT(0x1a80), LUT(0x1e80),
LUT(0x0300), LUT(0x0700), LUT(0x0b00), LUT(0x0f00), LUT(0x1300), LUT(0x1700), LUT(0x1b00), LUT(0x1f00),
LUT(0x0380), LUT(0x0780), LUT(0x0b80), LUT(0x0f80), LUT(0x1380), LUT(0x1780), LUT(0x1b80), LUT(0x1f80),
LUT(0x0028), LUT(0x0428), LUT(0x0828), LUT(0x0c28), LUT(0x1028), LUT(0x1428), LUT(0x1828), LUT(0x1c28),
LUT(0x00a8), LUT(0x04a8), LUT(0x08a8), LUT(0x0ca8), LUT(0x10a8), LUT(0x14a8), LUT(0x18a8), LUT(0x1ca8),
LUT(0x0128), LUT(0x0528), LUT(0x0928), LUT(0x0d28), LUT(0x1128), LUT(0x1528), LUT(0x1928), LUT(0x1d28),
LUT(0x01a8), LUT(0x05a8), LUT(0x09a8), LUT(0x0da8), LUT(0x11a8), LUT(0x15a8), LUT(0x19a8), LUT(0x1da8),
LUT(0x0228), LUT(0x0628), LUT(0x0a28), LUT(0x0e28), LUT(0x1228), LUT(0x1628), LUT(0x1a28), LUT(0x1e28),
LUT(0x02a8), LUT(0x06a8), LUT(0x0aa8), LUT(0x0ea8), LUT(0x12a8), LUT(0x16a8), LUT(0x1aa8), LUT(0x1ea8),
LUT(0x0328), LUT(0x0728), LUT(0x0b28), LUT(0x0f28), LUT(0x1328), LUT(0x1728), LUT(0x1b28), LUT(0x1f28),
LUT(0x03a8), LUT(0x07a8), LUT(0x0ba8), LUT(0x0fa8), LUT(0x13a8), LUT(0x17a8), LUT(0x1ba8), LUT(0x1fa8),
LUT(0x0050), LUT(0x0450), LUT(0x0850), LUT(0x0c50), LUT(0x1050), LUT(0x1450), LUT(0x1850), LUT(0x1c50),
LUT(0x00d0), LUT(0x04d0), LUT(0x08d0), LUT(0x0cd0), LUT(0x10d0), LUT(0x14d0), LUT(0x18d0), LUT(0x1cd0),
LUT(0x0150), LUT(0x0550), LUT(0x0950), LUT(0x0d50), LUT(0x1150), LUT(0x1550), LUT(0x1950), LUT(0x1d50),
LUT(0x01d0), LUT(0x05d0), LUT(0x09d0), LUT(0x0dd0), LUT(0x11d0), LUT(0x15d0), LUT(0x19d0), LUT(0x1dd0),
LUT(0x0250), LUT(0x0650), LUT(0x0a50), LUT(0x0e50), LUT(0x1250), LUT(0x1650), LUT(0x1a50), LUT(0x1e50),
LUT(0x02d0), LUT(0x06d0), LUT(0x0ad0), LUT(0x0ed0), LUT(0x12d0), LUT(0x16d0), LUT(0x1ad0), LUT(0x1ed0),
LUT(0x0350), LUT(0x0750), LUT(0x0b50), LUT(0x0f50), LUT(0x1350), LUT(0x1750), LUT(0x1b50), LUT(0x1f50),
LUT(0x03d0), LUT(0x07d0), LUT(0x0bd0), LUT(0x0fd0), LUT(0x13d0), LUT(0x17d0), LUT(0x1bd0), LUT(0x1fd0)
};
/// SOUND FUNCTIONS
void tone(byte freq, byte dur, sbyte mod) {
word i;
while (dur--) {
for (i=0; i<freq; i++) ;
CLICK;
freq += mod;
}
}
/// GRAPHICS FUNCTIONS
void clrscr() {
STROBE(0xc052); // turn off mixed-mode
STROBE(0xc054); // page 1
STROBE(0xc057); // hi-res
STROBE(0xc050); // set graphics mode
memset((byte*)0x2000, 0, 0x2000); // clear page 1
}
void xor_pixel(byte x, byte y) {
byte* dest = &vidmem[x][y>>3];
*dest ^= 0x1 << (y&7);
}
void draw_vline(byte x, byte y1, byte y2) {
byte yb1 = y1/8;
byte yb2 = y2/8;
byte* dest = &vidmem[x][yb1];
signed char nbytes = yb2 - yb1;
*dest++ ^= 0xff << (y1&7);
if (nbytes > 0) {
while (--nbytes > 0) {
*dest++ ^= 0xff;
}
*dest ^= 0xff >> (~y2&7);
} else {
*--dest ^= 0xff << ((y2+1)&7);
}
}
#define LOCHAR 0x20
#define HICHAR 0x5e
const byte font8x8[HICHAR-LOCHAR+1][8] = {/*{w:8,h:8,bpp:1,count:64,xform:"rotate(-90deg)"}*/
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x79,0x79,0x00,0x00,0x00 }, { 0x00,0x70,0x70,0x00,0x00,0x70,0x70,0x00 }, { 0x14,0x7f,0x7f,0x14,0x14,0x7f,0x7f,0x14 }, { 0x00,0x12,0x3a,0x6b,0x6b,0x2e,0x24,0x00 }, { 0x00,0x63,0x66,0x0c,0x18,0x33,0x63,0x00 }, { 0x00,0x26,0x7f,0x59,0x59,0x77,0x27,0x05 }, { 0x00,0x00,0x00,0x10,0x30,0x60,0x40,0x00 }, { 0x00,0x00,0x1c,0x3e,0x63,0x41,0x00,0x00 }, { 0x00,0x00,0x41,0x63,0x3e,0x1c,0x00,0x00 }, { 0x08,0x2a,0x3e,0x1c,0x1c,0x3e,0x2a,0x08 }, { 0x00,0x08,0x08,0x3e,0x3e,0x08,0x08,0x00 }, { 0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x00 }, { 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00 }, { 0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x00 }, { 0x00,0x01,0x03,0x06,0x0c,0x18,0x30,0x20 }, { 0x00,0x3e,0x7f,0x49,0x51,0x7f,0x3e,0x00 }, { 0x00,0x01,0x11,0x7f,0x7f,0x01,0x01,0x00 }, { 0x00,0x23,0x67,0x45,0x49,0x79,0x31,0x00 }, { 0x00,0x22,0x63,0x49,0x49,0x7f,0x36,0x00 }, { 0x00,0x0c,0x0c,0x14,0x34,0x7f,0x7f,0x04 }, { 0x00,0x72,0x73,0x51,0x51,0x5f,0x4e,0x00 }, { 0x00,0x3e,0x7f,0x49,0x49,0x6f,0x26,0x00 }, { 0x00,0x60,0x60,0x4f,0x5f,0x70,0x60,0x00 }, { 0x00,0x36,0x7f,0x49,0x49,0x7f,0x36,0x00 }, { 0x00,0x32,0x7b,0x49,0x49,0x7f,0x3e,0x00 }, { 0x00,0x00,0x00,0x12,0x12,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x13,0x13,0x00,0x00,0x00 }, { 0x00,0x08,0x1c,0x36,0x63,0x41,0x41,0x00 }, { 0x00,0x14,0x14,0x14,0x14,0x14,0x14,0x00 }, { 0x00,0x41,0x41,0x63,0x36,0x1c,0x08,0x00 }, { 0x00,0x20,0x60,0x45,0x4d,0x78,0x30,0x00 }, { 0x00,0x3e,0x7f,0x41,0x59,0x79,0x3a,0x00 }, { 0x00,0x1f,0x3f,0x68,0x68,0x3f,0x1f,0x00 }, { 0x00,0x7f,0x7f,0x49,0x49,0x7f,0x36,0x00 }, { 0x00,0x3e,0x7f,0x41,0x41,0x63,0x22,0x00 }, { 0x00,0x7f,0x7f,0x41,0x63,0x3e,0x1c,0x00 }, { 0x00,0x7f,0x7f,0x49,0x49,0x41,0x41,0x00 }, { 0x00,0x7f,0x7f,0x48,0x48,0x40,0x40,0x00 }, { 0x00,0x3e,0x7f,0x41,0x49,0x6f,0x2e,0x00 }, { 0x00,0x7f,0x7f,0x08,0x08,0x7f,0x7f,0x00 }, { 0x00,0x00,0x41,0x7f,0x7f,0x41,0x00,0x00 }, { 0x00,0x02,0x03,0x41,0x7f,0x7e,0x40,0x00 }, { 0x00,0x7f,0x7f,0x1c,0x36,0x63,0x41,0x00 }, { 0x00,0x7f,0x7f,0x01,0x01,0x01,0x01,0x00 }, { 0x00,0x7f,0x7f,0x30,0x18,0x30,0x7f,0x7f }, { 0x00,0x7f,0x7f,0x38,0x1c,0x7f,0x7f,0x00 }, { 0x00,0x3e,0x7f,0x41,0x41,0x7f,0x3e,0x00 }, { 0x00,0x7f,0x7f,0x48,0x48,0x78,0x30,0x00 }, { 0x00,0x3c,0x7e,0x42,0x43,0x7f,0x3d,0x00 }, { 0x00,0x7f,0x7f,0x4c,0x4e,0x7b,0x31,0x00 }, { 0x00,0x32,0x7b,0x49,0x49,0x6f,0x26,0x00 }, { 0x00,0x40,0x40,0x7f,0x7f,0x40,0x40,0x00 }, { 0x00,0x7e,0x7f,0x01,0x01,0x7f,0x7e,0x00 }, { 0x00,0x7c,0x7e,0x03,0x03,0x7e,0x7c,0x00 }, { 0x00,0x7f,0x7f,0x06,0x0c,0x06,0x7f,0x7f }, { 0x00,0x63,0x77,0x1c,0x1c,0x77,0x63,0x00 }, { 0x00,0x70,0x78,0x0f,0x0f,0x78,0x70,0x00 }, { 0x00,0x43,0x47,0x4d,0x59,0x71,0x61,0x00 }, { 0x00,0x00,0x7f,0x7f,0x41,0x41,0x00,0x00 }, { 0x00,0x20,0x30,0x18,0x0c,0x06,0x03,0x01 }, { 0x00,0x00,0x41,0x41,0x7f,0x7f,0x00,0x00 }, { 0x00,0x08,0x18,0x3f,0x3f,0x18,0x08,0x00 }
};
void draw_sprite(const byte* src, byte x, byte y) {
byte i,j;
byte w = *src++;
byte h = *src++;
for (j=0; j<h; j++) {
byte* dest = &vidmem[x++][y];
for (i=0; i<w; i++) {
*dest++ = *src++;
}
}
}
byte xor_sprite(const byte* src, byte x, byte y) {
byte i,j;
byte result = 0;
byte w = *src++;
byte h = *src++;
for (j=0; j<h; j++) {
byte* dest = &vidmem[x++][y];
for (i=0; i<w; i++) {
result |= (*dest++ ^= *src++);
}
}
return result;
}
void erase_sprite(const byte* src, byte x, byte y) {
byte i,j;
byte w = *src++;
byte h = *src++;
for (j=0; j<h; j++) {
byte* dest = &vidmem[x++][y];
for (i=0; i<w; i++) {
*dest++ &= ~(*src++);
}
}
}
void clear_sprite(const byte* src, byte x, byte y) {
byte i,j;
byte w = *src++;
byte h = *src++;
for (j=0; j<h; j++) {
byte* dest = &vidmem[x++][y];
for (i=0; i<w; i++) {
*dest++ = 0;
}
}
}
void draw_char(char ch, byte x, byte y) {
byte i;
const byte* src = &font8x8[(ch-LOCHAR)][0];
x *= 8;
for (i=0; i<8; i++) {
byte* dest = &vidmem[x++][y];
*dest = *src;
src += 1;
}
}
void draw_string(const char* str, byte x, byte y) {
do {
byte ch = *str++;
if (!ch) break;
draw_char(ch, x, y);
x++;
} while (1);
}
void draw_bcd_word(word bcd, byte x, byte y) {
byte j;
x += 3;
for (j=0; j<4; j++) {
draw_char('0'+(bcd&0xf), x, y);
x--;
bcd >>= 4;
}
}
word bcd_add(word a, word b) {
word result;
__asm__ ("sed"); // set decimal (BCD) mode
result = a+b;
__asm__ ("cld"); // clear BCD mode
return result;
}
//
// GAME GRAPHICS
//
const byte player_bitmap[] =
{2,27,/*{w:16,h:27,bpp:1,xform:"rotate(-90deg)"}*/0x0,0x0,0x0,0x0,0x0f,0x00,0x3e,0x00,0xf4,0x07,0xec,0x00,0x76,0x00,0x2b,0x00,0x33,0x00,0x75,0x00,0xf5,0x00,0xeb,0x31,0xbf,0xef,0x3f,0xcf,0xbf,0xef,0xeb,0x31,0xf5,0x00,0x75,0x00,0x33,0x00,0x2b,0x00,0x76,0x00,0xec,0x00,0xf4,0x07,0x3e,0x00,0x0f,0x00,0x00,0x00,0x0,0x0};
const byte bomb_bitmap[] =
{1,5,/*{w:8,h:5,bpp:1,xform:"rotate(-90deg)"}*/0x88,0x55,0x77,0x55,0x88};
const byte bullet_bitmap[] =
{2,2,/*{w:16,h:2,bpp:1,xform:"rotate(-90deg)"}*/0x88,0x88,0x44,0x44};
const byte enemy1_bitmap[] =
{2,17,/*{w:16,h:17,bpp:1,xform:"rotate(-90deg)"}*/0x00,0x00,0x00,0x0c,0x04,0x1e,0x46,0x3f,0xb8,0x7f,0xb0,0x7f,0xba,0x7f,0xfd,0x3f,0xfc,0x07,0xfc,0x07,0xfd,0x3f,0xba,0x7f,0xb0,0x7f,0xb8,0x7f,0x46,0x3f,0x04,0x1e,0x00,0x0c};
const byte enemy2_bitmap[] =
{2,16,/*{w:16,h:16,bpp:1,xform:"rotate(-90deg)"}*/0x26,0x00,0x59,0x10,0x10,0x30,0x33,0x18,0xe6,0x61,0xc4,0x56,0x03,0x03,0xdc,0x03,0xdc,0x03,0x03,0x03,0xc4,0x56,0xe6,0x61,0x33,0x18,0x10,0x30,0x59,0x10,0x26,0x00};
const byte enemy3_bitmap[] =
{2,16,/*{w:16,h:16,bpp:1,xform:"rotate(-90deg)"}*/0x80,0x1f,0xc0,0x03,0xf8,0x3f,0x70,0x00,0xf0,0x01,0xfc,0x07,0xe8,0x01,0xf8,0x03,0xf8,0x03,0xe8,0x01,0xf8,0x07,0xf0,0x01,0x70,0x00,0xf8,0x3f,0xc0,0x03,0x80,0x1f};
const byte enemy4_bitmap[] =
{2,16,/*{w:16,h:16,bpp:1,xform:"rotate(-90deg)"}*/0x06,0x00,0x0c,0x00,0x28,0x00,0x70,0x1f,0x84,0x3f,0xde,0x37,0xbb,0x3f,0xf0,0x3f,0xf0,0x3f,0xbb,0x3f,0xde,0x37,0x84,0x3f,0x70,0x1f,0x28,0x00,0x0c,0x00,0x06,0x00};
const byte* const enemy_bitmaps[4] = {
enemy1_bitmap,
enemy2_bitmap,
enemy3_bitmap,
enemy4_bitmap
};
//
// GAME CODE
//
byte attract;
byte credits;
byte curplayer;
word score;
byte lives;
#define MAXLIVES 5
byte player_x;
byte bullet_x;
byte bullet_y;
byte bomb_x;
byte bomb_y;
typedef struct {
byte x,y;
const byte* shape; // need const here
} Enemy;
#define MAX_ENEMIES 28
Enemy enemies[MAX_ENEMIES];
byte enemy_index;
byte num_enemies;
typedef struct {
int right:1;
int down:1;
} MarchMode;
MarchMode this_mode, next_mode;
void draw_lives(byte player) {
byte i;
byte n = lives;
byte x = player ? (22-MAXLIVES) : 6;
byte y = VBWIDTH-3;
for (i=0; i<MAXLIVES; i++) {
draw_char(i<n?'*':' ', x++, y);
}
}
void draw_score(byte player) {
byte x = player ? 24 : 0;
byte y = VBWIDTH-3;
draw_bcd_word(score, x, y);
}
void add_score(word pts) {
if (attract) return;
score = bcd_add(score, pts);
draw_score(curplayer);
}
void xor_player_derez() {
byte i,j;
byte x = player_x+13;
byte y = 8;
byte* rand = (byte*) &clrscr; // use code as random #'s
for (j=1; j<=0x1f; j++) {
for (i=0; i<50; i++) {
signed char xx = x + (*rand++ & 0x1f) - 15;
signed char yy = y + (*rand++ & j);
xor_pixel(xx, yy);
if ((xx & 0x1f) > j) { CLICK; }
}
}
}
void destroy_player() {
xor_player_derez(); // xor derez pattern
xor_sprite(player_bitmap, player_x, 1); // erase ship via xor
xor_player_derez(); // xor 2x to erase derez pattern
player_x = 0xff;
lives--;
}
void init_enemies() {
byte i,x,y,bm;
x=0;
y=26;
bm=0;
for (i=0; i<MAX_ENEMIES; i++) {
Enemy* e = &enemies[i];
e->x = x;
e->y = y;
e->shape = enemy_bitmaps[bm];
x += 28;
if (x >= VHEIGHT-32) {
x = 0;
y -= 3;
bm++;
}
}
enemy_index = 0;
num_enemies = MAX_ENEMIES;
this_mode.right = 1;
this_mode.down = 0;
next_mode.right = 1;
next_mode.down = 0;
}
void delete_enemy(Enemy* e) {
clear_sprite(e->shape, e->x, e->y);
memmove(e, e+1, sizeof(Enemy)*(enemies-e+MAX_ENEMIES-1));
num_enemies--; // update_next_enemy() will check enemy_index
tone(1,10,10);
}
void update_next_enemy() {
Enemy* e;
if (enemy_index >= num_enemies) {
enemy_index = 0;
memcpy(&this_mode, &next_mode, sizeof(this_mode));
tone(220+num_enemies,3,1);
}
e = &enemies[enemy_index];
clear_sprite(e->shape, e->x, e->y);
if (this_mode.down) {
// if too close to ground, end game
if (--e->y < 5) {
destroy_player();
lives = 0;
}
next_mode.down = 0;
} else {
if (this_mode.right) {
e->x += 2;
if (e->x >= VHEIGHT-32) {
next_mode.down = 1;
next_mode.right = 0;
}
} else {
e->x -= 2;
if (e->x == 0) {
next_mode.down = 1;
next_mode.right = 1;
}
}
}
draw_sprite(e->shape, e->x, e->y);
enemy_index++;
}
void draw_bunker(byte x, byte y, byte y2, byte h, byte w) {
byte i;
for (i=0; i<h; i++) {
draw_vline(x+i, y+i, y+y2+i*2);
draw_vline(x+h*2+w-i-1, y+i, y+y2+i*2);
}
for (i=0; i<w; i++) {
draw_vline(x+h+i, y+h, y+y2+h*2);
}
}
void draw_playfield() {
byte i;
clrscr();
draw_string("PLAYER 1", 0, VBWIDTH-1);
draw_score(0);
draw_lives(0);
for (i=0; i<VHEIGHT; i++)
vidmem[i][0] = 0x7f & 0x55;
draw_bunker(20, 40, 15, 15, 20);
draw_bunker(125, 40, 15, 15, 20);
}
char in_rect(Enemy* e, byte x, byte y, byte w, byte h) {
byte eh = e->shape[0];
byte ew = e->shape[1];
return (x >= e->x-w && x <= e->x+ew && y >= e->y-h && y <= e->y+eh);
}
Enemy* find_enemy_at(byte x, byte y) {
byte i;
for (i=0; i<num_enemies; i++) {
Enemy* e = &enemies[i];
if (in_rect(e, x, y, 2, 0)) {
return e;
}
}
return NULL;
}
void check_bullet_hit(byte x, byte y) {
Enemy* e = find_enemy_at(x,y);
if (e) {
delete_enemy(e);
add_score(0x25);
}
}
void fire_bullet() {
bullet_x = player_x + 13;
bullet_y = 3;
xor_sprite(bullet_bitmap, bullet_x, bullet_y); // draw
}
void move_bullet() {
byte leftover = xor_sprite(bullet_bitmap, bullet_x, bullet_y); // erase
if (leftover || bullet_y > 26) {
clear_sprite(bullet_bitmap, bullet_x, bullet_y);
check_bullet_hit(bullet_x, bullet_y+2);
bullet_y = 0;
} else {
bullet_y++;
tone(bullet_y,3,0);
xor_sprite(bullet_bitmap, bullet_x, bullet_y); // draw
}
}
void drop_bomb() {
Enemy* e = &enemies[enemy_index];
bomb_x = e->x + 7;
bomb_y = e->y - 2;
xor_sprite(bomb_bitmap, bomb_x, bomb_y);
}
void move_bomb() {
byte leftover = xor_sprite(bomb_bitmap, bomb_x, bomb_y); // erase
if (bomb_y < 2) {
bomb_y = 0;
} else if (leftover) {
erase_sprite(bomb_bitmap, bomb_x, bomb_y); // erase bunker
if (bomb_y < 3) {
// player was hit (probably)
destroy_player();
}
bomb_y = 0;
} else {
bomb_y--;
xor_sprite(bomb_bitmap, bomb_x, bomb_y);
}
}
byte frame;
signed char player_dir = 0;
void move_player() {
if (attract) {
if (bullet_y == 0) fire_bullet();
} else {
char key;
// handle keyboard
if (kbhit()) {
key = cgetc();
switch (key) {
case 'A':
player_dir = player_dir < 0 ? 0 : -2;
break;
case 'Z':
player_dir = player_dir > 0 ? 0 : 2;
break;
case ' ':
if (bullet_y == 0) {
fire_bullet();
}
break;
}
}
// move player
if (player_dir < 0 && player_x > 0)
player_x += player_dir;
else if (player_dir > 0 && player_x < VHEIGHT-28)
player_x += player_dir;
}
draw_sprite(player_bitmap, player_x, 1);
}
void play_round() {
draw_playfield();
player_x = VHEIGHT/2-8;
bullet_y = 0;
bomb_y = 0;
frame = 0;
while (player_x != 0xff && num_enemies) {
move_player();
if (bullet_y) {
move_bullet();
}
update_next_enemy();
if (frame & 1) {
if (bomb_y == 0) {
drop_bomb();
} else {
move_bomb();
}
}
frame++;
}
}
void init_game() {
score = 0;
lives = 5;
curplayer = 0;
}
void game_over_msg() {
byte i;
for (i=0; i<50; i++) {
draw_string(" *************** ", 5, 15);
draw_string("*** ***", 5, 16);
draw_string("** GAME OVER **", 5, 17);
draw_string("*** ***", 5, 18);
draw_string(" *************** ", 5, 19);
}
}
void play_game() {
attract = 0;
init_game();
init_enemies();
while (lives) {
play_round();
if (num_enemies == 0) {
init_enemies();
}
}
game_over_msg();
}
void attract_mode() {
attract = 1;
while (1) {
init_enemies();
play_round();
}
}
void main() {
// NOTE: initializers don't get run, so we init here
credits = 0;
while (1) {
//attract_mode();
play_game();
}
}