#include 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<> (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; xnext_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; ix = (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; } }