1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-11-29 14:51:17 +00:00
8bitworkshop/presets/williams-z80/game1.c
2017-04-07 14:20:03 -04:00

658 lines
19 KiB
C

#include <string.h>
typedef unsigned char byte;
typedef signed char sbyte;
typedef unsigned short word;
byte __at (0x0) vidmem[152][256]; // 304x256x4bpp video memory
byte __at (0xc000) palette[16];
volatile byte __at (0xc804) input0;
volatile byte __at (0xc806) input1;
volatile byte __at (0xc80c) input2;
byte __at (0xc900) rom_select;
volatile byte __at (0xcb00) video_counter;
byte __at (0xcbff) watchdog0x39;
byte __at (0xcc00) nvram[0x400];
// blitter flags
#define SRCSCREEN 0x1
#define DSTSCREEN 0x2
#define ESYNC 0x4
#define FGONLY 0x8
#define SOLID 0x10
#define RSHIFT 0x20
#define EVENONLY 0x40
#define ODDONLY 0x80
struct {
byte flags;
byte solid;
word sstart;
word dstart;
byte width;
byte height;
} __at (0xca00) blitter;
// switch flags
#define UP1 (input0 & 0x1)
#define DOWN1 (input0 & 0x2)
#define LEFT1 (input0 & 0x4)
#define RIGHT1 (input0 & 0x8)
#define START1 (input0 & 0x10)
#define START2 (input0 & 0x20)
#define UP2 (input0 & 0x40)
#define DOWN2 (input0 & 0x80)
#define LEFT2 (input1 & 0x1)
#define RIGHT2 (input1 & 0x2)
#define AUTOUP (input2 & 0x1)
#define ADVANCE (input2 & 0x2)
#define COIN2 (input2 & 0x4)
#define HIGHSCORERESET (input2 & 0x8)
#define COIN1 (input2 & 0x10)
#define COIN3 (input2 & 0x20)
#define TILTSWITCH (input2 & 0x40)
#define SOUNDACK (input2 & 0x80)
#define WATCHDOG watchdog0x39=0x39;
//
void main();
// start routine @ 0x0
// set stack pointer, enable interrupts
void start() {
__asm
LD SP,#0xc000
DI
; copy initialized data
LD BC, #l__INITIALIZER
LD A, B
LD DE, #s__INITIALIZED
LD HL, #s__INITIALIZER
LDIR
__endasm;
main();
}
#define LOCHAR 0x21
#define HICHAR 0x5e
const byte font8x8[HICHAR-LOCHAR+1][8] = {
{ 0x18,0x18,0x18,0x18,0x00,0x00,0x18,0x00 }, { 0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00 }, { 0x66,0x66,0xff,0x66,0xff,0x66,0x66,0x00 }, { 0x18,0x3e,0x60,0x3c,0x06,0x7c,0x18,0x00 }, { 0x62,0x66,0x0c,0x18,0x30,0x66,0x46,0x00 }, { 0x3c,0x66,0x3c,0x38,0x67,0x66,0x3f,0x00 }, { 0x06,0x0c,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x0c,0x18,0x30,0x30,0x30,0x18,0x0c,0x00 }, { 0x30,0x18,0x0c,0x0c,0x0c,0x18,0x30,0x00 }, { 0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00 }, { 0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30 }, { 0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00 }, { 0x00,0x03,0x06,0x0c,0x18,0x30,0x60,0x00 }, { 0x3c,0x66,0x6e,0x76,0x66,0x66,0x3c,0x00 }, { 0x18,0x18,0x38,0x18,0x18,0x18,0x7e,0x00 }, { 0x3c,0x66,0x06,0x0c,0x30,0x60,0x7e,0x00 }, { 0x3c,0x66,0x06,0x1c,0x06,0x66,0x3c,0x00 }, { 0x06,0x0e,0x1e,0x66,0x7f,0x06,0x06,0x00 }, { 0x7e,0x60,0x7c,0x06,0x06,0x66,0x3c,0x00 }, { 0x3c,0x66,0x60,0x7c,0x66,0x66,0x3c,0x00 }, { 0x7e,0x66,0x0c,0x18,0x18,0x18,0x18,0x00 }, { 0x3c,0x66,0x66,0x3c,0x66,0x66,0x3c,0x00 }, { 0x3c,0x66,0x66,0x3e,0x06,0x66,0x3c,0x00 }, { 0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00 }, { 0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x30 }, { 0x0e,0x18,0x30,0x60,0x30,0x18,0x0e,0x00 }, { 0x00,0x00,0x7e,0x00,0x7e,0x00,0x00,0x00 }, { 0x70,0x18,0x0c,0x06,0x0c,0x18,0x70,0x00 }, { 0x3c,0x66,0x06,0x0c,0x18,0x00,0x18,0x00 }, { 0x3c,0x66,0x6e,0x6e,0x60,0x62,0x3c,0x00 }, { 0x18,0x3c,0x66,0x7e,0x66,0x66,0x66,0x00 }, { 0x7c,0x66,0x66,0x7c,0x66,0x66,0x7c,0x00 }, { 0x3c,0x66,0x60,0x60,0x60,0x66,0x3c,0x00 }, { 0x78,0x6c,0x66,0x66,0x66,0x6c,0x78,0x00 }, { 0x7e,0x60,0x60,0x78,0x60,0x60,0x7e,0x00 }, { 0x7e,0x60,0x60,0x78,0x60,0x60,0x60,0x00 }, { 0x3c,0x66,0x60,0x6e,0x66,0x66,0x3c,0x00 }, { 0x66,0x66,0x66,0x7e,0x66,0x66,0x66,0x00 }, { 0x3c,0x18,0x18,0x18,0x18,0x18,0x3c,0x00 }, { 0x1e,0x0c,0x0c,0x0c,0x0c,0x6c,0x38,0x00 }, { 0x66,0x6c,0x78,0x70,0x78,0x6c,0x66,0x00 }, { 0x60,0x60,0x60,0x60,0x60,0x60,0x7e,0x00 }, { 0x63,0x77,0x7f,0x6b,0x63,0x63,0x63,0x00 }, { 0x66,0x76,0x7e,0x7e,0x6e,0x66,0x66,0x00 }, { 0x3c,0x66,0x66,0x66,0x66,0x66,0x3c,0x00 }, { 0x7c,0x66,0x66,0x7c,0x60,0x60,0x60,0x00 }, { 0x3c,0x66,0x66,0x66,0x66,0x3c,0x0e,0x00 }, { 0x7c,0x66,0x66,0x7c,0x78,0x6c,0x66,0x00 }, { 0x3c,0x66,0x60,0x3c,0x06,0x66,0x3c,0x00 }, { 0x7e,0x18,0x18,0x18,0x18,0x18,0x18,0x00 }, { 0x66,0x66,0x66,0x66,0x66,0x66,0x3c,0x00 }, { 0x66,0x66,0x66,0x66,0x66,0x3c,0x18,0x00 }, { 0x63,0x63,0x63,0x6b,0x7f,0x77,0x63,0x00 }, { 0x66,0x66,0x3c,0x18,0x3c,0x66,0x66,0x00 }, { 0x66,0x66,0x66,0x3c,0x18,0x18,0x18,0x00 }, { 0x7e,0x06,0x0c,0x18,0x30,0x60,0x7e,0x00 }, { 0x3c,0x30,0x30,0x30,0x30,0x30,0x3c,0x00 }, { 0x00,0x60,0x30,0x18,0x0c,0x06,0x03,0x00 }, { 0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3c,0x00 }, { 0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x18 }
};
static byte font_table[HICHAR-LOCHAR+1][8*4];
void fill_char_table_entry(char ch) {
const byte* src = &font8x8[ch-LOCHAR][0];
byte* data = &font_table[ch-LOCHAR][0];
int i,j,pixels;
for (i=0; i<8; i++) {
byte b = *src++;
for (j=0; j<4; j++) {
pixels = 0;
if (b & 0x80) pixels |= 0xf0;
if (b & 0x40) pixels |= 0x0f;
*data++ = pixels;
b <<= 2;
}
}
}
void fill_char_table() {
char ch;
for (ch=LOCHAR; ch<=HICHAR; ch++) {
fill_char_table_entry(ch);
}
}
const byte palette_data[16] = {
0x00, 0x03, 0x19, 0x50, 0x52, 0x07, 0x1f, 0x37, 0xe0, 0xa4, 0xfd, 0xff, 0x38, 0x70, 0x7f, 0xf8, };
const byte laser_vert[2+1*8] = {
1,8,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
};
const byte laser_horiz[2+4*2] = {
4,2,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
};
const byte playersprite1[] = {
7,16,
0x00,0x00,0xef,0xef,0xe0,0x00,0x00,
0x00,0xee,0xee,0xfe,0xee,0xe0,0x00,
0x0e,0xed,0xef,0xef,0xed,0xee,0x00,
0x0e,0xee,0xdd,0xdd,0xde,0xee,0x00,
0x0e,0xee,0xed,0xde,0xee,0xee,0x00,
0x00,0xee,0xee,0xde,0xee,0xe0,0x00,
0x00,0xee,0xee,0xde,0xee,0xe0,0x00,
0x00,0x00,0xed,0xdd,0xe0,0x00,0x0d,
0xdd,0xdd,0xee,0xee,0xed,0xdd,0xd0,
0x0d,0xee,0xee,0xee,0xee,0xee,0x00,
0x0e,0xe0,0xee,0xee,0xe0,0xee,0x00,
0x0e,0xe0,0xee,0xee,0xe0,0xee,0x00,
0x0e,0xe0,0xdd,0xdd,0xd0,0xde,0x00,
0x0d,0x00,0xee,0x0e,0xe0,0x0d,0x00,
0x00,0x00,0xed,0x0e,0xe0,0x00,0x00,
0x00,0x0d,0xdd,0x0d,0xdd,0x00,0x18,
};
const byte sprite1[2+16*16/2] = {
8,16,
0x00,0x09,0x99,0x00,0x00,0x99,0x90,0x00,
0x00,0x94,0x94,0x90,0x09,0x49,0x49,0x00,
0x04,0x49,0x49,0x90,0x09,0x94,0x94,0x90,
0x94,0x99,0x94,0x90,0x09,0x49,0x99,0x49,
0x99,0x99,0x49,0x93,0x39,0x94,0x99,0x99,
0x04,0x49,0x99,0x94,0x49,0x99,0x94,0x90,
0x00,0x94,0x94,0x43,0x34,0x49,0x49,0x00,
0x00,0x09,0x43,0x94,0x49,0x34,0x90,0x00,
0x00,0x90,0x00,0x39,0x93,0x00,0x09,0x00,
0x00,0x09,0x83,0x33,0x33,0x33,0x90,0x00,
0x00,0x09,0x32,0x23,0x32,0x23,0x90,0x00,
0x00,0x03,0x03,0x23,0x82,0x30,0x30,0x00,
0x03,0x30,0x00,0x33,0x33,0x00,0x03,0x30,
0x00,0x30,0x03,0x00,0x00,0x30,0x03,0x00,
0x00,0x00,0x00,0x30,0x03,0x00,0x00,0x00,
0x00,0x09,0x99,0x00,0x00,0x99,0x90,0x00,
};
const byte sprite2[2+16*16/2] = {
8,16,
0x00,0x94,0x94,0x90,0x09,0x49,0x49,0x00,
0x04,0x49,0x49,0x90,0x09,0x94,0x94,0x90,
0x94,0x99,0x94,0x90,0x09,0x49,0x99,0x49,
0x99,0x99,0x49,0x93,0x39,0x94,0x99,0x99,
0x04,0x49,0x99,0x94,0x49,0x99,0x94,0x90,
0x00,0x94,0x94,0x43,0x34,0x49,0x49,0x00,
0x00,0x09,0x43,0x94,0x49,0x34,0x90,0x00,
0x00,0x90,0x00,0x39,0x93,0x00,0x09,0x00,
0x00,0x09,0x83,0x33,0x33,0x33,0x90,0x00,
0x00,0x09,0x32,0x23,0x32,0x23,0x90,0x00,
0x00,0x03,0x03,0x23,0x82,0x30,0x30,0x00,
0x03,0x30,0x00,0x33,0x33,0x00,0x03,0x30,
0x00,0x30,0x03,0x00,0x00,0x30,0x03,0x00,
0x00,0x00,0x00,0x30,0x03,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,
};
const byte sprite3[2+16*16/2] = {
8,16,
0x00,0x00,0x00,0x01,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x11,0x11,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x10,0x00,0x00,0x00,
0x00,0x11,0x10,0x01,0x10,0x01,0x11,0x00,
0x11,0x00,0x10,0x11,0x11,0x01,0x00,0x11,
0x10,0x00,0x11,0x11,0x11,0x11,0x00,0x01,
0x10,0x00,0x00,0x11,0x11,0x00,0x00,0x01,
0x00,0x01,0x10,0x11,0x41,0x01,0x10,0x00,
0x00,0x10,0x11,0x11,0x11,0x11,0x01,0x00,
0x01,0x00,0x00,0x51,0x15,0x00,0x00,0x10,
0x01,0x00,0x01,0x10,0x01,0x10,0x00,0x10,
0x01,0x00,0x10,0x00,0x00,0x01,0x00,0x10,
0x00,0x10,0x01,0x00,0x00,0x10,0x01,0x00,
0x00,0x10,0x00,0x00,0x00,0x00,0x01,0x00,
0x00,0x01,0x10,0x00,0x00,0x01,0x10,0x00,
};
const byte sprite4[2+16*16/2] = {
8,16,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xbb,0xbb,0x00,0x00,0x00,
0x00,0x00,0x00,0xbb,0xbb,0x00,0x00,0x00,
0x00,0x00,0xbb,0xbb,0xbb,0xbb,0x00,0x00,
0x00,0x0b,0x4b,0xbb,0xbb,0xb4,0xb0,0x00,
0x00,0x0b,0x44,0xbb,0xbb,0x49,0xb0,0x00,
0x00,0xbb,0x99,0x4b,0xb4,0x99,0xbb,0x00,
0x00,0x4b,0xb9,0x9b,0xb4,0x4b,0xb4,0x00,
0x00,0x04,0xbb,0x4b,0xb9,0xbb,0x40,0x00,
0x00,0x00,0x4b,0xbb,0xbb,0xb4,0x00,0x00,
0x11,0x00,0x0b,0xbb,0xbb,0xb0,0x00,0x11,
0x10,0x10,0x0b,0x41,0x14,0xb0,0x01,0x01,
0x10,0x00,0x05,0x11,0x11,0x50,0x00,0x01,
0x01,0x00,0x01,0x51,0x15,0x10,0x00,0x10,
0x00,0x10,0x01,0x10,0x01,0x10,0x01,0x00,
0x01,0x01,0x10,0x10,0x01,0x01,0x10,0x10,
};
const byte sprite5[2+16*16/2] = {
8,16,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x22,0x00,0x00,0x22,0x00,0x00,
0x00,0x20,0x20,0x00,0x00,0x02,0x02,0x00,
0x02,0x22,0x12,0x00,0x00,0x21,0x22,0x20,
0x00,0x02,0x11,0x00,0x00,0x11,0x20,0x00,
0x00,0x00,0x02,0x11,0x11,0x20,0x00,0x00,
0x00,0x00,0x02,0x22,0x22,0x20,0x00,0x00,
0x00,0x00,0x21,0x22,0x22,0x12,0x00,0x00,
0x00,0x00,0x22,0x12,0x21,0x22,0x00,0x00,
0x02,0x00,0x22,0x12,0x21,0x22,0x00,0x20,
0x20,0x02,0x21,0x11,0x11,0x12,0x20,0x02,
0x02,0x22,0x15,0x12,0x21,0x51,0x22,0x20,
0x02,0x11,0x15,0x52,0x25,0x51,0x11,0x20,
0x20,0x00,0x22,0x12,0x21,0x22,0x00,0x02,
0x20,0x02,0x20,0x20,0x02,0x02,0x20,0x02,
0x02,0x02,0x00,0x20,0x02,0x00,0x20,0x20,
};
const byte sprite6[2+12*16/2] = {
8,12,
0x00,0x00,0x00,0x00,0x04,0x04,0x04,0x00,
0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x40,
0x00,0x00,0x04,0x04,0x49,0x49,0x99,0x44,
0x00,0x00,0x44,0x44,0x99,0x94,0x44,0x40,
0x00,0x04,0x49,0x99,0x94,0x49,0x99,0x40,
0x00,0x44,0x99,0x94,0x49,0x99,0x44,0x00,
0x04,0x49,0x44,0x99,0x99,0x44,0x00,0x00,
0x04,0x44,0x00,0x49,0x44,0x40,0x00,0x00,
0x04,0x40,0x00,0x04,0x00,0x00,0x00,0x00,
0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
const byte sprite7[2+16*16/2] = {
8,16,
0x00,0x60,0x00,0x00,0x00,0x00,0x06,0x00,
0x60,0x60,0x00,0x00,0x00,0x00,0x06,0x06,
0x60,0x60,0x50,0x00,0x00,0x05,0x06,0x06,
0x60,0x60,0x06,0x00,0x00,0x60,0x06,0x06,
0x66,0x60,0x06,0x06,0x60,0x60,0x06,0x66,
0x66,0x60,0x66,0x66,0x66,0x66,0x06,0x66,
0x66,0x60,0x6b,0x6b,0xb6,0xb6,0x06,0x66,
0x06,0x66,0x66,0xb6,0x6b,0x66,0x66,0x60,
0x00,0x67,0x66,0x66,0x66,0x66,0x66,0x00,
0x00,0x11,0x11,0x66,0x66,0x11,0x11,0x00,
0x01,0x11,0x21,0x11,0x11,0x12,0x11,0x10,
0x00,0x10,0x01,0x01,0x10,0x10,0x01,0x00,
0x00,0x10,0x11,0x00,0x00,0x11,0x01,0x00,
0x00,0x00,0x10,0x00,0x00,0x01,0x00,0x00,
};
const byte sprite8[2+16*16/2] = {
8,16,
0x00,0x00,0x11,0x11,0x11,0x11,0x00,0x00,
0x00,0x01,0x61,0x11,0x21,0x12,0x10,0x00,
0x00,0x11,0x12,0x11,0x61,0x11,0x11,0x00,
0x00,0x11,0x71,0x21,0x61,0x17,0x11,0x00,
0x00,0x11,0x77,0x11,0x12,0x77,0x11,0x00,
0x00,0x11,0x17,0x17,0x71,0x72,0x11,0x00,
0x00,0x16,0x21,0x78,0x87,0x11,0x11,0x00,
0x00,0x01,0x81,0x88,0x88,0x18,0x10,0x00,
0x00,0x08,0x18,0x58,0x85,0x81,0x80,0x00,
0x00,0x88,0x01,0x88,0x88,0x10,0x88,0x00,
0x00,0x08,0x07,0x78,0x87,0x70,0x80,0x00,
0x08,0x80,0x07,0x80,0x08,0x70,0x08,0x80,
0x88,0x00,0x88,0x00,0x00,0x88,0x00,0x88,
0x80,0x00,0x08,0x80,0x08,0x80,0x00,0x08,
0x00,0x00,0x00,0x80,0x08,0x00,0x00,0x00,
};
const byte sprite9[2+13*16/2] = {
8,13,
0x00,0x00,0xaa,0x00,0x00,0xaa,0x00,0x00,
0x00,0x00,0xa0,0x0a,0xa0,0x0a,0x00,0x00,
0x0a,0xaa,0xa4,0xaa,0xaa,0x3a,0xaa,0xa0,
0x00,0x0a,0x3a,0x9a,0xa9,0xa3,0xa0,0x00,
0x00,0x0a,0xaa,0x99,0xa4,0xaa,0xa0,0x00,
0x00,0x0a,0xaa,0x99,0x94,0xaa,0xa0,0x00,
0x00,0xaa,0x33,0xaa,0xaa,0x43,0xaa,0x00,
0x0a,0x3a,0xaa,0x3a,0xa3,0xaa,0xa3,0xa0,
0x00,0xaa,0xaa,0x30,0x03,0xaa,0xaa,0x00,
0x00,0x0a,0xa0,0x30,0x03,0x0a,0xa0,0x00,
0x00,0xa3,0xa0,0x00,0x00,0x0a,0x4a,0x00,
0x00,0xaa,0xa0,0x00,0x00,0x0a,0xaa,0x00,
0x00,0x0a,0xa0,0x00,0x00,0x0a,0xa0,0x00,
};
const byte* const all_sprites[9] = {
sprite1,
sprite2,
sprite3,
sprite4,
sprite5,
sprite6,
sprite7,
sprite8,
sprite9,
};
inline word swapw(word j) {
return ((j << 8) | (j >> 8));
}
// x1: 0-151
// y1: 0-255
inline void blit_solid(byte x1, byte y1, byte w, byte h, byte color) {
blitter.width = w^4;
blitter.height = h^4;
blitter.dstart = x1+y1*256; // swapped
blitter.solid = color;
blitter.flags = DSTSCREEN|SOLID;
}
inline void blit_copy(byte x1, byte y1, byte w, byte h, const byte* data) {
blitter.width = w^4;
blitter.height = h^4;
blitter.sstart = swapw((word)data);
blitter.dstart = x1+y1*256; // swapped
blitter.flags = DSTSCREEN|FGONLY;
}
inline void blit_copy_solid(byte x1, byte y1, byte w, byte h, const byte* data, byte solid) {
blitter.width = w^4;
blitter.height = h^4;
blitter.sstart = swapw((word)data);
blitter.dstart = x1+y1*256; // swapped
blitter.solid = solid;
blitter.flags = DSTSCREEN|FGONLY|SOLID;
}
inline void draw_sprite(const byte* data, byte x, byte y) {
blitter.width = data[0]^4;
blitter.height = data[1]^4;
blitter.sstart = swapw((word)(data+2));
blitter.dstart = x+y*256; // swapped
blitter.flags = DSTSCREEN|FGONLY;
}
inline void draw_sprite_solid(const byte* data, byte x, byte y, byte color) {
blitter.width = data[0]^4;
blitter.height = data[1]^4;
blitter.sstart = swapw((word)(data+2));
blitter.dstart = x+y*256; // swapped
blitter.solid = color;
blitter.flags = DSTSCREEN|FGONLY|SOLID;
}
inline void erase_sprite_rect(const byte* data, byte x, byte y) {
blitter.width = data[0]^4;
blitter.height = data[1]^4;
blitter.dstart = x+y*256; // swapped
blitter.solid = 0;
blitter.flags = DSTSCREEN|SOLID;
}
inline void draw_sprite_strided(const byte* data, byte x, byte y, byte stride) {
const byte* src = data+2;
byte height = data[1]^4;
byte width = data[0]^4;
while (height--) {
blit_copy(x, y, width, 1, src);
y += stride;
src += width;
}
}
inline void draw_char(char ch, byte x, byte y, byte color) {
if (ch < LOCHAR || ch > HICHAR) return;
blit_copy_solid(x, y, 4, 8, font_table[ch - LOCHAR], color);
}
void draw_string(const char* str, byte x, byte y, byte color) {
while (*str) {
draw_char(*str++, x, y, color);
x += 4;
}
}
typedef struct Actor* a;
typedef void ActorUpdateFn(struct Actor* a);
typedef void ActorDrawFn(struct Actor* a);
typedef void ActorEnumerateFn(struct Actor* a);
typedef struct Actor {
byte grid_index;
byte next_actor;
byte x,y;
byte* shape;
ActorUpdateFn* update;
ActorDrawFn* draw;
union {
struct { sbyte dx,dy; } laser;
} u;
} Actor;
#define GBITS 3
#define GDIM (1<<GBITS)
#define MAX_ACTORS 256
static byte grid[GDIM*GDIM]; // should be 256
static Actor actors[MAX_ACTORS];
inline byte xy2grid(byte x, byte y) {
return (x >> (8-GBITS)) | (y & ((GDIM-1) << GBITS));
}
void insert_into_grid(byte gi, byte actor_index) {
struct Actor* a = &actors[actor_index];
a->grid_index = gi;
a->next_actor = grid[gi];
grid[gi] = actor_index;
}
void delete_from_grid(byte gi, byte actor_index) {
byte i = grid[gi];
byte next = actors[actor_index].next_actor;
// is actor to delete at head of list?
if (i == actor_index) {
grid[gi] = next;
} else {
// iterate through the list
do {
byte j = actors[i].next_actor;
if (j == actor_index) {
actors[i].next_actor = next;
break;
}
i = j;
} while (1); // watchdog reset if actor not found to delete
}
actors[actor_index].next_actor = 0;
actors[actor_index].grid_index = 0;
}
void add_actor(byte actor_index) {
struct Actor* a = &actors[actor_index];
insert_into_grid(xy2grid(a->x, a->y), actor_index);
}
void enumerate_actors_at_grid(ActorEnumerateFn* enumfn, byte gi) {
byte ai = grid[gi];
while (ai) {
Actor* a = &actors[ai];
enumfn(a);
ai = a->next_actor;
}
}
void enumerate_actors_in_rect(ActorEnumerateFn* enumfn,
byte x1, byte y1, byte x2, byte y2) {
byte gi = xy2grid(x1, y1);
byte gi1 = xy2grid(x2, y2) + 1;
byte gwidth = 1 + ((gi1 - gi) & (GDIM-1));
byte x;
do {
for (x=0; x<gwidth; x++) {
byte ai = grid[gi];
while (ai) {
Actor* a = &actors[ai];
enumfn(a);
ai = a->next_actor;
}
gi++;
}
if (gi == gi1) break;
gi += GDIM - gwidth;
} while (1);
}
void draw_actor_normal(struct Actor* a) {
draw_sprite(a->shape, a->x, a->y);
}
void draw_actor_debug(struct Actor* a) {
draw_sprite_solid(a->shape, a->x, a->y, a->next_actor?0xff:0x33);
}
byte update_actor(byte actor_index) {
struct Actor* a = &actors[actor_index];
byte next_actor = a->next_actor;
byte gi0,gi1;
// if NULL shape, we don't have anything
if (a->shape) {
gi0 = a->grid_index;
draw_sprite_solid(a->shape, a->x, a->y, 0);
if (a->update) a->update(a);
// did we delete it?
if (a->shape) {
if (a->draw) a->draw(a);
gi1 = xy2grid(a->x, a->y);
// grid bucket changed?
if (gi0 != gi1) {
delete_from_grid(gi0, actor_index);
insert_into_grid(gi1, actor_index);
}
} else {
delete_from_grid(gi0, actor_index);
}
}
return next_actor;
}
//
word lfsr = 1;
word rand() {
byte lsb = lfsr & 1;
lfsr >>= 1;
if (lsb) lfsr ^= 0xd400;
return lfsr;
}
signed char random_dir() {
byte x = rand();
if (x < 85) return 0;
else if (x < 85*2) return -1;
else return 1;
}
void random_walk(Actor* a) {
a->x += random_dir();
a->y += random_dir();
}
void update_grid_cell(byte grid_index) {
byte actor_index = grid[grid_index];
while (actor_index) {
actor_index = update_actor(actor_index);
}
}
void update_grid_rows(byte row_start, byte row_end) {
byte i0 = row_start * GDIM;
byte i1 = row_end * GDIM;
byte i;
for (i=i0; i!=i1; i++) {
update_grid_cell(i);
}
}
byte did_overflow() {
__asm
ld l,#0
ret nc
inc l
__endasm;
}
void laser_move(Actor* a) {
a->x += a->u.laser.dx;
if (a->x > 152) a->shape = NULL;
a->y += a->u.laser.dy;
if (a->y > 255-8) a->shape = NULL;
}
void shoot_laser(sbyte dx, sbyte dy, const byte* shape) {
actors[2].shape = (void*) shape;
actors[2].x = actors[1].x;
actors[2].y = actors[1].y;
actors[2].u.laser.dx = dx;
actors[2].u.laser.dy = dy;
add_actor(2);
}
void player_move(Actor* a) {
byte x = a->x;
byte y = a->y;
if (UP1) y-=2;
if (DOWN1) y+=2;
if (LEFT1) x-=1;
if (RIGHT1) x+=1;
a->x = x;
a->y = y;
// shoot laser
if (actors[2].shape == NULL) {
if (UP2) shoot_laser(0,-8,laser_vert);
else if (DOWN2) shoot_laser(0,8,laser_vert);
else if (LEFT2) shoot_laser(-4,0,laser_horiz);
else if (RIGHT2) shoot_laser(4,0,laser_horiz);
}
}
void main() {
byte i;
byte num_actors = 32;
blit_solid(0, 0, 255, 255, 0);
memset(grid, 0, sizeof(grid));
memset(actors, 0, sizeof(actors));
memcpy(palette, palette_data, 16);
fill_char_table();
WATCHDOG;
for (i=1; i<num_actors; i++) {
Actor* a = &actors[i];
a->x = (i & 7) * 16 + 16;
a->y = (i / 4) * 16 + 32;
a->shape = (void*) all_sprites[i%9];
//a->update = random_walk;
a->draw = draw_actor_normal;
add_actor(i);
}
actors[1].shape = (void*) playersprite1;
actors[1].update = player_move;
actors[2].update = laser_move;
actors[2].shape = NULL;
WATCHDOG;
while (1) {
while (video_counter == 0) ;
update_grid_rows(GDIM*3/4, GDIM*4/4);
while (video_counter == 0x3c) ;
update_grid_rows(GDIM*0/4, GDIM*1/4);
while (video_counter == 0xbc) ;
update_grid_rows(GDIM*1/4, GDIM*2/4);
while (video_counter == 0xfc) ;
update_grid_rows(GDIM*2/4, GDIM*3/4);
WATCHDOG;
}
}