1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-06-10 21:29:33 +00:00

updated apple2 keys, presets

This commit is contained in:
Steven Hugg 2018-08-13 10:52:58 -04:00
parent 56aab0e6a5
commit f7129e9fde
5 changed files with 137 additions and 140 deletions

3
.gitmodules vendored
View File

@ -1,9 +1,6 @@
[submodule "javatari.js"] [submodule "javatari.js"]
path = javatari.js path = javatari.js
url = https://github.com/sehugg/javatari.js url = https://github.com/sehugg/javatari.js
[submodule "dasm"]
path = dasm
url = https://github.com/sehugg/dasm
[submodule "codemirror"] [submodule "codemirror"]
path = codemirror path = codemirror
url = https://github.com/codemirror/CodeMirror url = https://github.com/codemirror/CodeMirror

View File

@ -28,7 +28,7 @@ TODO:
- kbd shortcuts - kbd shortcuts
- PC x86 support - PC x86 support
- show errors in list (maybe window list?) - show errors in list (maybe window list?)
- can't see 1st line in editor sometimes - can't see 1st line in editor sometimes (when scrolling cursor past bottom of screen)
- online help - online help
- show self-modifying code insns left of editor - show self-modifying code insns left of editor
- facade/kbd shortcuts for emulators, focus - facade/kbd shortcuts for emulators, focus

View File

@ -3,24 +3,29 @@
#include <conio.h> #include <conio.h>
#include <apple2.h> #include <apple2.h>
// type aliases for byte/signed byte/unsigned 16-bit
typedef unsigned char byte; typedef unsigned char byte;
typedef signed char sbyte; typedef signed char sbyte;
typedef unsigned short word; typedef unsigned short word;
// peeks, pokes, and strobes
#define POKE(addr,val) (*(unsigned char*) (addr) = (val)) #define POKE(addr,val) (*(unsigned char*) (addr) = (val))
#define POKEW(addr,val) (*(unsigned*) (addr) = (val)) #define POKEW(addr,val) (*(unsigned*) (addr) = (val))
#define PEEK(addr) (*(unsigned char*) (addr)) #define PEEK(addr) (*(unsigned char*) (addr))
#define PEEKW(addr) (*(unsigned*) (addr)) #define PEEKW(addr) (*(unsigned*) (addr))
#define STROBE(addr) __asm__ ("sta %w", addr) #define STROBE(addr) __asm__ ("sta %w", addr)
// speaker click
#define CLICK STROBE(0xc030) #define CLICK STROBE(0xc030)
/// HIRES LOOKUP TABLE /// HIRES LOOKUP TABLE
#define VHEIGHT 192 #define VHEIGHT 192 // number of scanlines
#define VBWIDTH 40 #define VBWIDTH 40 // number of bytes per scanline
#define PIXWIDTH 280 // 7 pixels per byte
#define LUT(x) (byte*)(0x2000|x) #define LUT(x) (byte*)(0x2000|x)
// starting address of each scanline
static byte* const vidmem[VHEIGHT] = { static byte* const vidmem[VHEIGHT] = {
LUT(0x0000), LUT(0x0400), LUT(0x0800), LUT(0x0c00), LUT(0x1000), LUT(0x1400), LUT(0x1800), LUT(0x1c00), 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(0x0080), LUT(0x0480), LUT(0x0880), LUT(0x0c80), LUT(0x1080), LUT(0x1480), LUT(0x1880), LUT(0x1c80),
@ -48,20 +53,7 @@ static byte* const vidmem[VHEIGHT] = {
LUT(0x03d0), LUT(0x07d0), LUT(0x0bd0), LUT(0x0fd0), LUT(0x13d0), LUT(0x17d0), LUT(0x1bd0), LUT(0x1fd0) LUT(0x03d0), LUT(0x07d0), LUT(0x0bd0), LUT(0x0fd0), LUT(0x13d0), LUT(0x17d0), LUT(0x1bd0), LUT(0x1fd0)
}; };
const byte DIV7_140[140] = { // divide-by 7 table
0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 8,
9, 9, 9,10,10,10,10,11,11,11,12,12,12,12,13,13,13,14,14,14,14,15,15,15,16,16,16,16,17,17,17,18,
18,18,18,19,19,19,20,20,20,20,21,21,21,22,22,22,22,23,23,23,24,24,24,24,25,25,25,26,26,26,26,27,
27,27,28,28,28,28,29,29,29,30,30,30,30,31,31,31,32,32,32,32,33,33,33,34,34,34,34,35,35,35,36,36,
36,36,37,37,37,38,38,38,38,39,39,39};
const byte MOD7_140[140] = {
0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6,
1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0,
2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1,
3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 0, 2,
4, 6, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5};
const byte DIV7[256] = { const byte DIV7[256] = {
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 9, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 9,
@ -72,6 +64,7 @@ const byte DIV7[256] = {
27,27,27,27,28,28,28,28,28,28,28,29,29,29,29,29,29,29,30,30,30,30,30,30,30,31,31,31,31,31,31,31, 27,27,27,27,28,28,28,28,28,28,28,29,29,29,29,29,29,29,30,30,30,30,30,30,30,31,31,31,31,31,31,31,
32,32,32,32,32,32,32,33,33,33,33,33,33,33,34,34,34,34,34,34,34,35,35,35,35,35,35,35,36,36,36,36}; 32,32,32,32,32,32,32,33,33,33,33,33,33,33,34,34,34,34,34,34,34,35,35,35,35,35,35,35,36,36,36,36};
// modulo-by-7 table
const byte MOD7[256] = { const byte MOD7[256] = {
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3,
4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0,
@ -82,18 +75,19 @@ const byte MOD7[256] = {
3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3}; 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3};
// bitmask table
const byte BIT7[7] = { 1, 2, 4, 8, 16, 32, 64 }; const byte BIT7[7] = { 1, 2, 4, 8, 16, 32, 64 };
#pragma static-locals(on) #pragma static-locals(on)
/// SOUND FUNCTIONS /// SOUND FUNCTIONS
void tone(byte freq, byte dur, sbyte mod) { void tone(byte period, byte dur, sbyte mod) {
word i; word i;
while (dur--) { while (dur--) {
for (i=0; i<freq; i++) ; for (i=0; i<period; i++) ;
CLICK; CLICK;
freq += mod; period += mod;
} }
} }
@ -107,57 +101,49 @@ void clrscr() {
memset((byte*)0x2000, 0, 0x2000); // clear page 1 memset((byte*)0x2000, 0, 0x2000); // clear page 1
} }
void xor_pixel(byte x, byte y) { void xor_vline(byte x, byte y1, byte y2) {
byte xb = DIV7[x]; byte xb = DIV7[x]; // divide x by 7
byte mask = BIT7[MOD7[x]]; byte mask = BIT7[MOD7[x]]; // lookup bitmask for remainder
byte* dest = &vidmem[y][xb];
*dest ^= mask;
}
void draw_vline(byte x, byte y1, byte y2) {
byte xb = DIV7[x];
byte mask = BIT7[MOD7[x]];
byte y; byte y;
for (y=y1; y<y2; y++) { for (y=y1; y<=y2; y++) {
byte* dest = &vidmem[y][xb]; byte* dest = &vidmem[y][xb]; // lookup dest. address
*dest ^= mask; *dest ^= mask; // XOR mask with destination
} }
} }
#define LOCHAR 0x20 void xor_pixel(byte x, byte y) {
#define HICHAR 0x7f xor_vline(x, y, y); // draw line with 1-pixel height
}
const byte font8x8[HICHAR-LOCHAR+1][8] = {/*{w:8,h:8,bpp:1,count:96}*/
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 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,0x7c,0x06,0x3c,0x60,0x3e,0x18,0x00 }, { 0x46,0x66,0x30,0x18,0x0c,0x66,0x62,0x00 }, { 0x3c,0x66,0x3c,0x1c,0xe6,0x66,0xfc,0x00 }, { 0x60,0x30,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x18,0x0c,0x0c,0x0c,0x18,0x30,0x00 }, { 0x0c,0x18,0x30,0x30,0x30,0x18,0x0c,0x00 }, { 0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00 }, { 0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x0c }, { 0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00 }, { 0x00,0xc0,0x60,0x30,0x18,0x0c,0x06,0x00 }, { 0x3c,0x66,0x76,0x6e,0x66,0x66,0x3c,0x00 }, { 0x18,0x18,0x1c,0x18,0x18,0x18,0x7e,0x00 }, { 0x3c,0x66,0x60,0x30,0x0c,0x06,0x7e,0x00 }, { 0x3c,0x66,0x60,0x38,0x60,0x66,0x3c,0x00 }, { 0x60,0x70,0x78,0x66,0xfe,0x60,0x60,0x00 }, { 0x7e,0x06,0x3e,0x60,0x60,0x66,0x3c,0x00 }, { 0x3c,0x66,0x06,0x3e,0x66,0x66,0x3c,0x00 }, { 0x7e,0x66,0x30,0x18,0x18,0x18,0x18,0x00 }, { 0x3c,0x66,0x66,0x3c,0x66,0x66,0x3c,0x00 }, { 0x3c,0x66,0x66,0x7c,0x60,0x66,0x3c,0x00 }, { 0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00 }, { 0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x0c }, { 0x70,0x18,0x0c,0x06,0x0c,0x18,0x70,0x00 }, { 0x00,0x00,0x7e,0x00,0x7e,0x00,0x00,0x00 }, { 0x0e,0x18,0x30,0x60,0x30,0x18,0x0e,0x00 }, { 0x3c,0x66,0x60,0x30,0x18,0x00,0x18,0x00 }, { 0x3c,0x66,0x76,0x76,0x06,0x46,0x3c,0x00 }, { 0x18,0x3c,0x66,0x7e,0x66,0x66,0x66,0x00 }, { 0x3e,0x66,0x66,0x3e,0x66,0x66,0x3e,0x00 }, { 0x3c,0x66,0x06,0x06,0x06,0x66,0x3c,0x00 }, { 0x1e,0x36,0x66,0x66,0x66,0x36,0x1e,0x00 }, { 0x7e,0x06,0x06,0x1e,0x06,0x06,0x7e,0x00 }, { 0x7e,0x06,0x06,0x1e,0x06,0x06,0x06,0x00 }, { 0x3c,0x66,0x06,0x76,0x66,0x66,0x3c,0x00 }, { 0x66,0x66,0x66,0x7e,0x66,0x66,0x66,0x00 }, { 0x3c,0x18,0x18,0x18,0x18,0x18,0x3c,0x00 }, { 0x78,0x30,0x30,0x30,0x30,0x36,0x1c,0x00 }, { 0x66,0x36,0x1e,0x0e,0x1e,0x36,0x66,0x00 }, { 0x06,0x06,0x06,0x06,0x06,0x06,0x7e,0x00 }, { 0xc6,0xee,0xfe,0xd6,0xc6,0xc6,0xc6,0x00 }, { 0x66,0x6e,0x7e,0x7e,0x76,0x66,0x66,0x00 }, { 0x3c,0x66,0x66,0x66,0x66,0x66,0x3c,0x00 }, { 0x3e,0x66,0x66,0x3e,0x06,0x06,0x06,0x00 }, { 0x3c,0x66,0x66,0x66,0x66,0x3c,0x70,0x00 }, { 0x3e,0x66,0x66,0x3e,0x1e,0x36,0x66,0x00 }, { 0x3c,0x66,0x06,0x3c,0x60,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 }, { 0xc6,0xc6,0xc6,0xd6,0xfe,0xee,0xc6,0x00 }, { 0x66,0x66,0x3c,0x18,0x3c,0x66,0x66,0x00 }, { 0x66,0x66,0x66,0x3c,0x18,0x18,0x18,0x00 }, { 0x7e,0x60,0x30,0x18,0x0c,0x06,0x7e,0x00 }, { 0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3c,0x00 }, { 0x00,0x06,0x0c,0x18,0x30,0x60,0xc0,0x00 }, { 0x3c,0x30,0x30,0x30,0x30,0x30,0x3c,0x00 }, { 0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x18 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff }, { 0x06,0x0c,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3c,0x60,0x7c,0x66,0x7c,0x00 }, { 0x00,0x06,0x06,0x3e,0x66,0x66,0x3e,0x00 }, { 0x00,0x00,0x3c,0x06,0x06,0x06,0x3c,0x00 }, { 0x00,0x60,0x60,0x7c,0x66,0x66,0x7c,0x00 }, { 0x00,0x00,0x3c,0x66,0x7e,0x06,0x3c,0x00 }, { 0x00,0x70,0x18,0x7c,0x18,0x18,0x18,0x00 }, { 0x00,0x00,0x7c,0x66,0x66,0x7c,0x60,0x3e }, { 0x00,0x06,0x06,0x3e,0x66,0x66,0x66,0x00 }, { 0x00,0x18,0x00,0x1c,0x18,0x18,0x3c,0x00 }, { 0x00,0x60,0x00,0x60,0x60,0x60,0x60,0x3c }, { 0x00,0x06,0x06,0x36,0x1e,0x36,0x66,0x00 }, { 0x00,0x1c,0x18,0x18,0x18,0x18,0x3c,0x00 }, { 0x00,0x00,0x66,0xfe,0xfe,0xd6,0xc6,0x00 }, { 0x00,0x00,0x3e,0x66,0x66,0x66,0x66,0x00 }, { 0x00,0x00,0x3c,0x66,0x66,0x66,0x3c,0x00 }, { 0x00,0x00,0x3e,0x66,0x66,0x3e,0x06,0x06 }, { 0x00,0x00,0x7c,0x66,0x66,0x7c,0x60,0x60 }, { 0x00,0x00,0x3e,0x66,0x06,0x06,0x06,0x00 }, { 0x00,0x00,0x7c,0x06,0x3c,0x60,0x3e,0x00 }, { 0x00,0x18,0x7e,0x18,0x18,0x18,0x70,0x00 }, { 0x00,0x00,0x66,0x66,0x66,0x66,0x7c,0x00 }, { 0x00,0x00,0x66,0x66,0x66,0x3c,0x18,0x00 }, { 0x00,0x00,0xc6,0xd6,0xfe,0x7c,0x6c,0x00 }, { 0x00,0x00,0x66,0x3c,0x18,0x3c,0x66,0x00 }, { 0x00,0x00,0x66,0x66,0x66,0x7c,0x30,0x1e }, { 0x00,0x00,0x7e,0x30,0x18,0x0c,0x7e,0x00 }, { 0x38,0x0c,0x0c,0x06,0x0c,0x0c,0x38,0x00 }, { 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18 }, { 0x1c,0x30,0x30,0x60,0x30,0x30,0x1c,0x00 }, { 0x00,0x4c,0x32,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
};
typedef enum { typedef enum {
OP_DRAW, OP_XOR, OP_ERASE OP_DRAW, OP_XOR, OP_ERASE
}; } GraphicsOperation;
byte render_sprite(const byte* src, byte x, byte y, byte op) { byte render_sprite(const byte* src, byte x, byte y, byte op) {
byte i,j; byte i,j;
byte w = *src++; byte w = *src++; // get width from 1st byte of sprite
byte h = *src++; byte h = *src++; // get height from 2nd byte of sprite
byte xb = DIV7[x]; byte xb = DIV7[x]; // xb = x DIV 7
byte xs = MOD7[x]; byte xs = MOD7[x]; // xs = x MOD 7
byte result = 0; byte result = 0; // result (used only with XOR)
for (j=0; j<h; j++) { for (j=0; j<h; j++) {
byte* dest = &vidmem[y++][xb]; byte* dest = &vidmem[y++][xb]; // lookup video address
byte rest = 0; byte rest = 0; // rest = leftover bits
for (i=0; i<w; i++) { for (i=0; i<w; i++) {
byte data = *src++; byte data = *src++; // get next sprite byte
byte next = (data << xs) | rest; byte next = (data << xs) | rest; // shift and OR with leftover
// compute graphics operation, write to dest
switch (op) { switch (op) {
case OP_DRAW: *dest++ = next; break; case OP_DRAW: *dest++ = next; break;
case OP_XOR: result |= (*dest++ ^= next); break; case OP_XOR: result |= (*dest++ ^= next); break;
case OP_ERASE: *dest++ &= ~next; break; case OP_ERASE: *dest++ &= ~next; break;
} }
rest = data >> (7-xs); rest = data >> (7-xs); // save leftover bits
} }
// compute final byte operation
switch (op) { switch (op) {
case OP_DRAW: *dest = rest; break; case OP_DRAW: *dest = rest; break;
case OP_XOR: result |= (*dest ^= rest); break; case OP_XOR: result |= (*dest ^= rest); break;
case OP_ERASE: *dest &= ~rest; break; case OP_ERASE: *dest &= ~rest; break;
} }
} }
@ -168,6 +154,7 @@ void draw_sprite(const byte* src, byte x, byte y) {
render_sprite(src, x, y, OP_DRAW); render_sprite(src, x, y, OP_DRAW);
} }
// XOR returns non-zero if any pixels were overlapped
byte xor_sprite(const byte* src, byte x, byte y) { byte xor_sprite(const byte* src, byte x, byte y) {
return render_sprite(src, x, y, OP_XOR); return render_sprite(src, x, y, OP_XOR);
} }
@ -176,6 +163,7 @@ void erase_sprite(const byte* src, byte x, byte y) {
render_sprite(src, x, y, OP_ERASE); render_sprite(src, x, y, OP_ERASE);
} }
// clear just sets all bytes to 0, and is fast
void clear_sprite(const byte* src, byte x, byte y) { void clear_sprite(const byte* src, byte x, byte y) {
byte i,j; byte i,j;
byte w = *src++; byte w = *src++;
@ -189,36 +177,49 @@ void clear_sprite(const byte* src, byte x, byte y) {
} }
} }
void draw_char(char ch, byte x, byte y) { // FONT FUNCTIONS
#define LOCHAR 0x20 // lowest character value in font
#define HICHAR 0x7f // highest character value in font
const byte font8x8[HICHAR-LOCHAR+1][8] = {/*{w:8,h:8,bpp:1,count:96}*/
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 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,0x7c,0x06,0x3c,0x60,0x3e,0x18,0x00 }, { 0x46,0x66,0x30,0x18,0x0c,0x66,0x62,0x00 }, { 0x3c,0x66,0x3c,0x1c,0xe6,0x66,0xfc,0x00 }, { 0x60,0x30,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x30,0x18,0x0c,0x0c,0x0c,0x18,0x30,0x00 }, { 0x0c,0x18,0x30,0x30,0x30,0x18,0x0c,0x00 }, { 0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00 }, { 0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x0c }, { 0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00 }, { 0x00,0xc0,0x60,0x30,0x18,0x0c,0x06,0x00 }, { 0x3c,0x66,0x76,0x6e,0x66,0x66,0x3c,0x00 }, { 0x18,0x18,0x1c,0x18,0x18,0x18,0x7e,0x00 }, { 0x3c,0x66,0x60,0x30,0x0c,0x06,0x7e,0x00 }, { 0x3c,0x66,0x60,0x38,0x60,0x66,0x3c,0x00 }, { 0x60,0x70,0x78,0x66,0xfe,0x60,0x60,0x00 }, { 0x7e,0x06,0x3e,0x60,0x60,0x66,0x3c,0x00 }, { 0x3c,0x66,0x06,0x3e,0x66,0x66,0x3c,0x00 }, { 0x7e,0x66,0x30,0x18,0x18,0x18,0x18,0x00 }, { 0x3c,0x66,0x66,0x3c,0x66,0x66,0x3c,0x00 }, { 0x3c,0x66,0x66,0x7c,0x60,0x66,0x3c,0x00 }, { 0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00 }, { 0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x0c }, { 0x70,0x18,0x0c,0x06,0x0c,0x18,0x70,0x00 }, { 0x00,0x00,0x7e,0x00,0x7e,0x00,0x00,0x00 }, { 0x0e,0x18,0x30,0x60,0x30,0x18,0x0e,0x00 }, { 0x3c,0x66,0x60,0x30,0x18,0x00,0x18,0x00 }, { 0x3c,0x66,0x76,0x76,0x06,0x46,0x3c,0x00 }, { 0x18,0x3c,0x66,0x7e,0x66,0x66,0x66,0x00 }, { 0x3e,0x66,0x66,0x3e,0x66,0x66,0x3e,0x00 }, { 0x3c,0x66,0x06,0x06,0x06,0x66,0x3c,0x00 }, { 0x1e,0x36,0x66,0x66,0x66,0x36,0x1e,0x00 }, { 0x7e,0x06,0x06,0x1e,0x06,0x06,0x7e,0x00 }, { 0x7e,0x06,0x06,0x1e,0x06,0x06,0x06,0x00 }, { 0x3c,0x66,0x06,0x76,0x66,0x66,0x3c,0x00 }, { 0x66,0x66,0x66,0x7e,0x66,0x66,0x66,0x00 }, { 0x3c,0x18,0x18,0x18,0x18,0x18,0x3c,0x00 }, { 0x78,0x30,0x30,0x30,0x30,0x36,0x1c,0x00 }, { 0x66,0x36,0x1e,0x0e,0x1e,0x36,0x66,0x00 }, { 0x06,0x06,0x06,0x06,0x06,0x06,0x7e,0x00 }, { 0xc6,0xee,0xfe,0xd6,0xc6,0xc6,0xc6,0x00 }, { 0x66,0x6e,0x7e,0x7e,0x76,0x66,0x66,0x00 }, { 0x3c,0x66,0x66,0x66,0x66,0x66,0x3c,0x00 }, { 0x3e,0x66,0x66,0x3e,0x06,0x06,0x06,0x00 }, { 0x3c,0x66,0x66,0x66,0x66,0x3c,0x70,0x00 }, { 0x3e,0x66,0x66,0x3e,0x1e,0x36,0x66,0x00 }, { 0x3c,0x66,0x06,0x3c,0x60,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 }, { 0xc6,0xc6,0xc6,0xd6,0xfe,0xee,0xc6,0x00 }, { 0x66,0x66,0x3c,0x18,0x3c,0x66,0x66,0x00 }, { 0x66,0x66,0x66,0x3c,0x18,0x18,0x18,0x00 }, { 0x7e,0x60,0x30,0x18,0x0c,0x06,0x7e,0x00 }, { 0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3c,0x00 }, { 0x00,0x06,0x0c,0x18,0x30,0x60,0xc0,0x00 }, { 0x3c,0x30,0x30,0x30,0x30,0x30,0x3c,0x00 }, { 0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x18 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff }, { 0x06,0x0c,0x18,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x3c,0x60,0x7c,0x66,0x7c,0x00 }, { 0x00,0x06,0x06,0x3e,0x66,0x66,0x3e,0x00 }, { 0x00,0x00,0x3c,0x06,0x06,0x06,0x3c,0x00 }, { 0x00,0x60,0x60,0x7c,0x66,0x66,0x7c,0x00 }, { 0x00,0x00,0x3c,0x66,0x7e,0x06,0x3c,0x00 }, { 0x00,0x70,0x18,0x7c,0x18,0x18,0x18,0x00 }, { 0x00,0x00,0x7c,0x66,0x66,0x7c,0x60,0x3e }, { 0x00,0x06,0x06,0x3e,0x66,0x66,0x66,0x00 }, { 0x00,0x18,0x00,0x1c,0x18,0x18,0x3c,0x00 }, { 0x00,0x60,0x00,0x60,0x60,0x60,0x60,0x3c }, { 0x00,0x06,0x06,0x36,0x1e,0x36,0x66,0x00 }, { 0x00,0x1c,0x18,0x18,0x18,0x18,0x3c,0x00 }, { 0x00,0x00,0x66,0xfe,0xfe,0xd6,0xc6,0x00 }, { 0x00,0x00,0x3e,0x66,0x66,0x66,0x66,0x00 }, { 0x00,0x00,0x3c,0x66,0x66,0x66,0x3c,0x00 }, { 0x00,0x00,0x3e,0x66,0x66,0x3e,0x06,0x06 }, { 0x00,0x00,0x7c,0x66,0x66,0x7c,0x60,0x60 }, { 0x00,0x00,0x3e,0x66,0x06,0x06,0x06,0x00 }, { 0x00,0x00,0x7c,0x06,0x3c,0x60,0x3e,0x00 }, { 0x00,0x18,0x7e,0x18,0x18,0x18,0x70,0x00 }, { 0x00,0x00,0x66,0x66,0x66,0x66,0x7c,0x00 }, { 0x00,0x00,0x66,0x66,0x66,0x3c,0x18,0x00 }, { 0x00,0x00,0xc6,0xd6,0xfe,0x7c,0x6c,0x00 }, { 0x00,0x00,0x66,0x3c,0x18,0x3c,0x66,0x00 }, { 0x00,0x00,0x66,0x66,0x66,0x7c,0x30,0x1e }, { 0x00,0x00,0x7e,0x30,0x18,0x0c,0x7e,0x00 }, { 0x38,0x0c,0x0c,0x06,0x0c,0x0c,0x38,0x00 }, { 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18 }, { 0x1c,0x30,0x30,0x60,0x30,0x30,0x1c,0x00 }, { 0x00,0x4c,0x32,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
};
// draw character from column 0..39, row 0..23
void draw_char(char ch, byte col, byte row) {
byte i; byte i;
const byte* src = &font8x8[(ch-LOCHAR)][0]; const byte* src = &font8x8[(ch-LOCHAR)][0];
x *= 8; byte y = row*8;
for (i=0; i<8; i++) { for (i=0; i<8; i++) {
byte* dest = &vidmem[x++][y]; byte* dest = &vidmem[y++][col];
*dest = *src; *dest = *src;
src += 1; src += 1;
} }
} }
void draw_string(const char* str, byte x, byte y) { // draw string starting at row/col (vert 1 = draw vertical)
void draw_string(const char* str, byte col, byte row, byte vert) {
do { do {
byte ch = *str++; byte ch = *str++;
if (!ch) break; if (!ch) break;
draw_char(ch, x, y); draw_char(ch, col, row);
x++; if (vert) row++; else col++;
} while (1); } while (1);
} }
void draw_bcd_word(word bcd, byte x, byte y) { // draw 4-digit BCD word
void draw_bcd_word(word bcd, byte col, byte row, byte vert) {
byte j; byte j;
x += 3; if (vert) row+=3; else col+=3; // move to rightmost digit
for (j=0; j<4; j++) { for (j=0; j<4; j++) {
draw_char('0'+(bcd&0xf), x, y); draw_char('0'+(bcd&0xf), col, row);
x--; if (vert) row--; else col--;
bcd >>= 4; bcd >>= 4;
} }
} }
// add two 4-digit BCD words
word bcd_add(word a, word b) { word bcd_add(word a, word b) {
word result; word result;
__asm__ ("sed"); // set decimal (BCD) mode __asm__ ("sed"); // set decimal (BCD) mode
@ -258,9 +259,6 @@ const byte* const enemy_bitmaps[4] = {
// //
byte attract; byte attract;
byte credits;
byte curplayer;
word score; word score;
byte lives; byte lives;
@ -290,26 +288,51 @@ typedef struct {
MarchMode this_mode, next_mode; MarchMode this_mode, next_mode;
void draw_lives(byte player) { void draw_lives() {
byte i; byte i;
byte n = lives; byte n = lives;
byte x = player ? (22-MAXLIVES) : 6; byte y = 18;
byte y = VBWIDTH-3; byte x = VBWIDTH-1;
for (i=0; i<MAXLIVES; i++) { for (i=0; i<MAXLIVES; i++) {
draw_char(i<n?'*':' ', x++, y); draw_char(i<n?'*':' ', x, y++);
} }
} }
void draw_score(byte player) { void draw_score() {
byte x = player ? 24 : 0; byte x = VBWIDTH-1;
byte y = VBWIDTH-3; byte y = 10;
draw_bcd_word(score, x, y); draw_bcd_word(score, x, y, 1);
}
void draw_bunker(byte x, byte y, byte y2, byte h, byte w) {
byte i,a,b;
for (i=0; i<h; i++) {
a = y-y2-i*2;
b = y-i;
xor_vline(x+i, a, b);
xor_vline(x+h*2+w-i-1, a, b);
}
for (i=0; i<w; i++) {
xor_vline(x+h+i, a, b);
}
}
void draw_playfield() {
byte i;
clrscr();
draw_string("PLAYER 1", VBWIDTH-1, 0, 1);
draw_score();
draw_lives();
for (i=0; i<VBWIDTH-4; i++)
vidmem[191][i] = (i&1) ? 0x55 : 0x2a;
draw_bunker(20, 165, 15, 15, 20);
draw_bunker(160, 165, 15, 15, 20);
} }
void add_score(word pts) { void add_score(word pts) {
if (attract) return; if (attract) return;
score = bcd_add(score, pts); score = bcd_add(score, pts);
draw_score(curplayer); draw_score();
} }
void xor_player_derez() { void xor_player_derez() {
@ -345,8 +368,8 @@ void init_enemies() {
e->x = x; e->x = x;
e->y = y; e->y = y;
e->shape = enemy_bitmaps[bm]; e->shape = enemy_bitmaps[bm];
x += 28; x += 29;
if (x >= 28*7) { if (x >= 200) {
x = 0; x = 0;
y += 20; y += 20;
bm++; bm++;
@ -403,32 +426,6 @@ void update_next_enemy() {
enemy_index++; enemy_index++;
} }
void draw_bunker(byte x, byte y, byte y2, byte h, byte w) {
byte i,a,b;
for (i=0; i<h; i++) {
a = y-y2-i*2;
b = y-i;
draw_vline(x+i, a, b);
draw_vline(x+h*2+w-i-1, a, b);
}
for (i=0; i<w; i++) {
draw_vline(x+h+i, a, b);
}
}
void draw_playfield() {
byte i;
clrscr();
draw_string("PLAYER 1", 0, VBWIDTH-1);
draw_string("USE A/Z/SPACE", 11, VBWIDTH-1);
draw_score(0);
draw_lives(0);
for (i=0; i<VBWIDTH-4; i++)
vidmem[191][i] = (i&1) ? 0x55 : 0x2a;
draw_bunker(20, 165, 15, 15, 20);
draw_bunker(160, 165, 15, 15, 20);
}
char in_rect(Enemy* e, byte x, byte y, byte w, byte h) { char in_rect(Enemy* e, byte x, byte y, byte w, byte h) {
byte ew = e->shape[0]*8; byte ew = e->shape[0]*8;
byte eh = e->shape[1]; byte eh = e->shape[1];
@ -482,7 +479,7 @@ void drop_bomb() {
void move_bomb() { void move_bomb() {
byte leftover = xor_sprite(bomb_bitmap, bomb_x, bomb_y); // erase byte leftover = xor_sprite(bomb_bitmap, bomb_x, bomb_y); // erase
if (bomb_y < 192-10) { if (bomb_y > 192-12) {
bomb_y = 0; bomb_y = 0;
} else if (leftover) { } else if (leftover) {
erase_sprite(bomb_bitmap, bomb_x, bomb_y); // erase bunker erase_sprite(bomb_bitmap, bomb_x, bomb_y); // erase bunker
@ -510,13 +507,13 @@ void move_player() {
if (kbhit()) { if (kbhit()) {
key = cgetc(); key = cgetc();
switch (key) { switch (key) {
case 'Z': case 8: // left arrow
player_dir = player_dir < 0 ? 0 : -2; player_dir = player_dir < 0 ? 0 : -2;
break; break;
case 'X': case 21: // right arrow
player_dir = player_dir > 0 ? 0 : 2; player_dir = player_dir > 0 ? 0 : 2;
break; break;
case ' ': case ' ': // space
if (bullet_y == 0) { if (bullet_y == 0) {
fire_bullet(); fire_bullet();
} }
@ -558,17 +555,18 @@ void play_round() {
void init_game() { void init_game() {
score = 0; score = 0;
lives = 5; lives = 5;
curplayer = 0;
} }
void game_over_msg() { void game_over_msg() {
byte i; byte i;
byte x=11;
byte y=10;
for (i=0; i<50; i++) { for (i=0; i<50; i++) {
draw_string(" *************** ", 5, 15); draw_string(" *************** ", x, y+0, 0);
draw_string("*** ***", 5, 16); draw_string("*** ***", x, y+1, 0);
draw_string("** GAME OVER **", 5, 17); draw_string("** GAME OVER **", x, y+2, 0);
draw_string("*** ***", 5, 18); draw_string("*** ***", x, y+3, 0);
draw_string(" *************** ", 5, 19); draw_string(" *************** ", x, y+4, 0);
} }
} }
@ -595,7 +593,6 @@ void attract_mode() {
void main() { void main() {
// NOTE: initializers don't get run, so we init here // NOTE: initializers don't get run, so we init here
credits = 0;
while (1) { while (1) {
//attract_mode(); //attract_mode();
play_game(); play_game();

View File

@ -3,7 +3,6 @@
#include <string.h> #include <string.h>
#include <conio.h> #include <conio.h>
#include <apple2.h> #include <apple2.h>
#include <joystick.h>
#define COLS 40 #define COLS 40
#define ROWS 24 #define ROWS 24
@ -12,13 +11,14 @@ typedef unsigned char byte;
typedef signed char sbyte; typedef signed char sbyte;
typedef unsigned short word; typedef unsigned short word;
// BASL = text address of cursor position
static byte** BASL = (byte**) 0x28; static byte** BASL = (byte**) 0x28;
byte getchar(byte x, byte y) { byte getchar(byte x, byte y) {
// JSR VTABZ // JSR VTABZ
// LDA (BASL) ($28) // LDA (BASL) ($28)
gotoxy(x,y); gotoxy(x,y); // set cursor position
return (*BASL)[x]; return (*BASL)[x]; // lookup value @ cursor address
} }
void delay(byte count) { void delay(byte count) {
@ -45,6 +45,7 @@ Player players[2];
byte credits = 0; byte credits = 0;
byte frames_per_move; byte frames_per_move;
byte gameover;
#define START_SPEED 12 #define START_SPEED 12
#define MAX_SPEED 5 #define MAX_SPEED 5
@ -73,22 +74,22 @@ void draw_box(byte x, byte y, byte x2, byte y2, const char* chars) {
void draw_playfield() { void draw_playfield() {
draw_box(0,1,COLS-1,ROWS-1,BOX_CHARS); draw_box(0,1,COLS-1,ROWS-1,BOX_CHARS);
cputsxy(0,0,"Plyr1:"); cputsxy( 0, 0, "Plyr1:");
cputsxy(20,0,"Plyr2:"); cputsxy(20, 0, "Plyr2:");
cputcxy(7,0,players[0].score+'0'); cputcxy( 7, 0, players[0].score+'0');
cputcxy(27,0,players[1].score+'0'); cputcxy(27, 0, players[1].score+'0');
} }
typedef enum { D_RIGHT, D_DOWN, D_LEFT, D_UP } dir_t; typedef enum { D_RIGHT, D_DOWN, D_LEFT, D_UP } dir_t;
const char DIR_X[4] = { 1, 0, -1, 0 }; const sbyte DIR_X[4] = { 1, 0, -1, 0 };
const char DIR_Y[4] = { 0, 1, 0, -1 }; const sbyte DIR_Y[4] = { 0, 1, 0, -1 };
void init_game() { void init_game() {
memset(players, 0, sizeof(players)); memset(players, 0, sizeof(players));
players[0].head_attr = '1'; players[0].head_attr = '1';
players[1].head_attr = '2'; players[1].head_attr = '2';
players[0].tail_attr = 1; players[0].tail_attr = '#';
players[1].tail_attr = 9; players[1].tail_attr = '*';
frames_per_move = START_SPEED; frames_per_move = START_SPEED;
} }
@ -120,13 +121,14 @@ void human_control(Player* p) {
if (!p->human) return; if (!p->human) return;
if (!kbhit()) return; if (!kbhit()) return;
key = cgetc(); key = cgetc();
// I/J/K/M cursor movement
switch (key) { switch (key) {
case 'I': dir = D_UP; break; case 'I': dir = D_UP; break;
case 'J': dir = D_LEFT; break; case 'J': dir = D_LEFT; break;
case 'K': dir = D_RIGHT; break; case 'K': dir = D_RIGHT; break;
case 'M': dir = D_DOWN; break; case 'M': dir = D_DOWN; break;
} }
// don't let the player reverse // don't let the player reverse direction
if (dir < 0x80 && dir != (p->dir ^ 2)) { if (dir < 0x80 && dir != (p->dir ^ 2)) {
p->dir = dir; p->dir = dir;
} }
@ -159,21 +161,17 @@ void ai_control(Player* p) {
} }
} }
byte gameover;
void flash_colliders() { void flash_colliders() {
byte i; byte i;
// flash players that collided // flash players that collided
for (i=0; i<56; i++) { for (i=0; i<56; i++) {
//cv_set_frequency(CV_SOUNDCHANNEL_0, 1000+i*8);
//cv_set_attenuation(CV_SOUNDCHANNEL_0, i/2);
if (players[0].collided) players[0].head_attr ^= 0x80;
if (players[1].collided) players[1].head_attr ^= 0x80;
delay(2); delay(2);
revers(players[0].collided && (i&1));
draw_player(&players[0]); draw_player(&players[0]);
revers(players[1].collided && (i&1));
draw_player(&players[1]); draw_player(&players[1]);
} }
//cv_set_attenuation(CV_SOUNDCHANNEL_0, 28); revers(0);
} }
void make_move() { void make_move() {
@ -237,6 +235,5 @@ void play_game() {
} }
void main() { void main() {
joy_install (joy_static_stddrv);
play_game(); play_game();
} }

View File

@ -152,13 +152,19 @@ var Apple2Platform = function(mainElement) {
audio = new SampleAudio(cpuFrequency); audio = new SampleAudio(cpuFrequency);
video.create(); video.create();
video.setKeyboardEvents(function(key,code,flags) { video.setKeyboardEvents(function(key,code,flags) {
// since we're an Apple II+, we don't do lowercase
if (flags & 1) { if (flags & 1) {
if (code) { if (code) {
// convert to uppercase for Apple ][
if (code >= 0x61 && code <= 0x7a) if (code >= 0x61 && code <= 0x7a)
code -= 0x20; code -= 0x20;
kbdlatch = (code | 0x80) & 0xff; kbdlatch = (code | 0x80) & 0xff;
} else if (key) { } else if (key) {
switch (key) {
case 37: key=8; break; // left
case 39: key=21; break; // right
case 38: key=11; break; // up
case 40: key=10; break; // down
}
kbdlatch = (key | 0x80) & 0xff; kbdlatch = (key | 0x80) & 0xff;
} }
} }