astrocade updates

This commit is contained in:
Steven Hugg 2019-06-08 12:01:22 -04:00
parent 76cb868382
commit e8260a8e46
15 changed files with 117 additions and 86 deletions

View File

@ -92,6 +92,7 @@ TODO:
- parse .incbin directives?
- can't replace in hex directives
- should maybe use same single-canvas editor for map + char editor
- undo doesn't refresh editor
- crt0.s compiled each time?
- debug highlight doesn't go away when debugging -> running
- show breakpoint of PC or highest address on stack

View File

@ -23,7 +23,7 @@ PrgStart: DI ; Disable interrupts
DW Palettes ; ... with the values at Palettes
DO FILL ; Set background fill
DW NORMEM ; ... starting at the beginning of screen RAM
DW 100*BYTEPL ; ... and going for 100 lines
DW 98*BYTEPL ; ... and going for 100 lines
DB 00010010b ; ... with a fill pattern of three different colored pixels
DO STRDIS ; Set string display
DB 0 ; ... starting 0 pixels from the left of the screen

View File

@ -57,7 +57,7 @@ _display_string:
_paint_rectangle:
call load5_edca_hl
ld b,l
ld h,a
ld a,h
SYSTEM RECTAN
ret

View File

@ -4,6 +4,8 @@
#include "aclib.h"
#include "acextra.h"
#pragma opt_code_speed
#define EXIT_CLIPDEST(addr) if ((((word)addr)&0xfff) >= 0xe10) return
// clear screen and set graphics mode
@ -14,13 +16,14 @@ void clrscr(void) {
// draw vertical line
void vline(byte x, byte y1, byte y2, byte col, byte op) {
byte* dest = &vmagic[y1][x>>2];// destination address
byte y;
col <<= 6; // color goes in top 2 bits
hw_magic = M_SHIFT(x) | op; // set magic register
col <<= 6; // put color in high pixel
for (y=y1; y<=y2; y++) {
EXIT_CLIPDEST(dest);
*dest = col; // shift + xor color
dest += VBWIDTH; // dest address to next scanline
if (y2 >= VHEIGHT) y2 = VHEIGHT-1; // clipping
if (y1 > y2) return;
*dest = col;
while (++y1 <= y2) {
dest += VBWIDTH; // dest address to next scanline
*dest = col;
}
}

View File

@ -0,0 +1,6 @@
#include "aclib.h"
extern void fast_sprite_8(const byte* pattern, byte* dst);
extern void fast_sprite_16(const byte* pattern, byte* dst);

View File

@ -196,7 +196,7 @@ XPAND = 0x19 ;&(25)= ; eXPANDer pixel definition port
INTST = 0x08 ; =&(8) ; read INTercept STatus
VERAF = 0x0E ;=&(14) ; read VERtical Address Feedback
HORAF = 0x0F ;=&(15) ; read HORizontal Address Feedback
;
;
; HAND CONTROL INPUT Ports:
SW0 = 0x10 ;=&(16) ; read SWitch bank 0 for player 1 hand control
SW1 = 0x11 ;=&(17) ; read SWitch bank 1 for player 2 hand control

Binary file not shown.

View File

@ -6,6 +6,7 @@
*/
#include <string.h>
#include <stdlib.h>
//#resource "astrocade.inc"
#include "acbios.h"
@ -26,15 +27,17 @@ const byte player_bitmap[2+9*3] =
const byte bomb_bitmap[] =
{1,3,/*{w:4,h:3,bpp:2,brev:1}*/0xF8,0x3E,0xF8};
const byte bullet_bitmap[] =
{1,5,/*{w:4,h:5,bpp:2,brev:1}*/0x08,0x24,0x18,0x10,0x04};
{1,5,/*{w:4,h:5,bpp:2,brev:1}*/0x0C,0x24,0x18,0x10,0x04};
const byte enemy1_bitmap[18] =
{2,8,/*{w:8,h:8,bpp:2,brev:1}*/0x02,0x80,0x0B,0xE0,0x3F,0xFC,0x37,0xDC,0x3F,0xFC,0x0C,0x30,0x30,0x0C,0x0C,0x30};
{2,8,/*{w:8,h:8,bpp:2,brev:1}*/0x22,0x88,0x2A,0xA8,0x3F,0xFC,0x37,0xDC,0x3F,0xFC,0x38,0x2C,0x30,0x0C,0x0C,0x30};
const byte enemy2_bitmap[] =
{2,8,/*{w:8,h:8,bpp:2,brev:1}*/0x0C,0x30,0x30,0x0C,0x17,0xE8,0x23,0xC4,0x0B,0xD0,0x2C,0x34,0x2F,0xF4,0x10,0x08};
const byte enemy3_bitmap[] =
{2,8,/*{w:8,h:8,bpp:2,brev:1}*/0x0F,0xC0,0x00,0xC0,0x10,0xC4,0x26,0xD8,0x27,0x98,0x26,0xD8,0x14,0x14,0x10,0x04};
const byte enemy4_bitmap[] =
{2,8,/*{w:8,h:8,bpp:2,brev:1}*/0x30,0x0C,0x3C,0x3C,0x0F,0xF0,0x3A,0xE8,0x3B,0xEC,0x3F,0xFC,0x30,0x0C,0x00,0x00};
const byte mothership_bitmap[2+3*6] =
{3,6,/*{w:12,h:6,bpp:2,brev:1}*/0x00,0x28,0x00,0x02,0xBE,0x80,0x2A,0xFF,0xA8,0x25,0x55,0x58,0x0A,0xAA,0xA0,0x02,0xAA,0x80};
const byte explode_bitmap[18] =
{2,8,/*{w:8,h:8,bpp:2,brev:1}*/0x40,0x44,0x10,0x40,0x06,0x81,0x0B,0xE4,0x5B,0xE0,0x02,0x81,0x04,0x10,0x10,0x44};
@ -63,6 +66,7 @@ const byte palette[8] = {
#define PLYRHEIGHT 9
#define ENEMY_SPACING_X 14
#define ENEMY_SPACING_Y 11
#define ENEMY_WIDTH 8
#define ENEMY_MARCH_X 1
#define ENEMY_MARCH_Y 2
#define EXPLODE_TIME 8
@ -85,7 +89,6 @@ typedef struct {
MarchMode this_mode, next_mode;
byte attract;
word score;
byte lives;
@ -123,11 +126,11 @@ void draw_bunker(byte x, byte y, byte y2, byte h, byte w) {
for (i=0; i<h; i++) {
a = y-y2-i*2;
b = y-i;
vline(x+i, a, b, M_XOR, COLOR_BUNKER);
vline(x+h*2+w-i-1, a, b, M_XOR, COLOR_BUNKER);
vline(x+i, a, b, COLOR_BUNKER, M_XOR);
vline(x+h*2+w-i-1, a, b, COLOR_BUNKER, M_XOR);
}
for (i=0; i<w; i++) {
vline(x+h+i, a, b, M_XOR, COLOR_BUNKER);
vline(x+h+i, a, b, COLOR_BUNKER, M_XOR);
}
}
@ -140,12 +143,11 @@ void draw_playfield() {
for (i=0; i<PIXWIDTH; i++)
pixel(i, VHEIGHT-1, COLOR_GROUND, M_OR);
// TODO: const
draw_bunker(20, 65, 15, 15, 20);
draw_bunker(100, 65, 15, 15, 20);
draw_bunker(20, 75, 5, 5, 20);
draw_bunker(100, 75, 5, 5, 20);
}
void add_score(word pts) {
if (attract) return;
score = bcd_add(score, pts);
draw_score();
}
@ -199,9 +201,11 @@ void init_enemies() {
void delete_enemy(Enemy* e) {
erase_sprite(e->shape, e->x, e->y);
explode_x = e->x;
explode_y = e->y;
explode_timer = EXPLODE_TIME;
if (explode_timer == 0) {
explode_x = e->x;
explode_y = e->y;
explode_timer = EXPLODE_TIME;
}
memmove(e, e+1, sizeof(Enemy)*(enemies-e+MAX_ENEMIES-1));
num_enemies--; // update_next_enemy() will check enemy_index
}
@ -217,7 +221,7 @@ void update_next_enemy() {
erase_sprite(e->shape, e->x, e->y);
e->y += ENEMY_MARCH_Y;
// if too close to ground, end game
if (e->y > VHEIGHT-ENEMY_SPACING_Y) {
if (e->y >= player_y) {
destroy_player();
lives = 0;
}
@ -244,7 +248,7 @@ void update_next_enemy() {
char in_rect(Enemy* e, byte x, byte y, byte w, byte h) {
byte ew = e->shape[0]*4;
byte eh = e->shape[1];
return (x >= e->x-w && x <= e->x+ew && y >= e->y-h && y <= e->y+eh);
return (x >= e->x-w && x <= e->x+ew+w && y >= e->y-h && y <= e->y+eh+h);
}
Enemy* find_enemy_at(byte x, byte y) {
@ -266,19 +270,24 @@ void check_bullet_hit(byte x, byte y) {
}
}
void xor_bullet() {
render_sprite(bullet_bitmap, bullet_x, bullet_y, M_XOR);
}
void fire_bullet() {
bullet_x = player_x + 4;
bullet_y = VHEIGHT-PLYRHEIGHT-6;
//render_sprite(bullet_bitmap, bullet_x, bullet_y, M_XOR); // draw
xor_bullet();
}
void move_bullet() {
byte leftover;
erase_sprite(bullet_bitmap, bullet_x, bullet_y);
xor_bullet();
//erase_sprite(bullet_bitmap, bullet_x, bullet_y);
hw_intst; // reset intercept counters
bullet_y -= 2;
render_sprite(bullet_bitmap, bullet_x, bullet_y, M_OR); // erase
leftover = (hw_intst & 0xf0); // any pixels leftover?
xor_bullet();
leftover = hw_intst; // any pixels leftover?
if (leftover || bullet_y < 10) {
erase_sprite(bullet_bitmap, bullet_x, bullet_y);
check_bullet_hit(bullet_x, bullet_y+2);
@ -286,26 +295,37 @@ void move_bullet() {
}
}
void xor_bomb() {
render_sprite(bomb_bitmap, bomb_x, bomb_y, M_XOR);
}
void drop_bomb() {
Enemy* e = &enemies[enemy_index];
bomb_x = e->x + 7;
bomb_y = e->y + 16;
byte i = rand() % num_enemies;
Enemy* e = &enemies[i];
// don't drop on someone else!
if (find_enemy_at(e->x, e->y+ENEMY_SPACING_Y*2)) {
return;
}
bomb_x = e->x + ENEMY_WIDTH/4;
bomb_y = e->y + ENEMY_SPACING_Y;
xor_bomb();
}
void move_bomb() {
hw_intst; // reset intercept counters
erase_sprite(bomb_bitmap, bomb_x, bomb_y); // erase bunker
xor_bomb();
if (bomb_y >= VHEIGHT-5) {
bomb_y = 0;
} else {
bomb_y += 1;
render_sprite(bomb_bitmap, bomb_x, bomb_y, M_OR); // erase
hw_intst; // reset intercept counters
xor_bomb();
if (hw_intst & 0xf0) { // any pixels leftover?
erase_sprite(bomb_bitmap, bomb_x, bomb_y);
if (bomb_y >= player_y) {
// player was hit (probably)
destroy_player();
bomb_y = 0;
}
bomb_y = 0;
}
}
}
@ -314,23 +334,18 @@ byte frame;
signed char player_dir = 0;
void move_player() {
if (attract) {
if (bullet_y == 0) fire_bullet();
player_dir = 0;
} else {
byte mask = hw_p1ctrl;
if (mask & 0x4) {
if (player_x > 0)
player_x--;
}
if (mask & 0x8) {
if (player_x < PIXWIDTH-16)
player_x++;
}
if (mask & 0x10) {
if (bullet_y == 0) {
fire_bullet();
}
byte mask = hw_p1ctrl;
if (mask & 0x4) {
if (player_x > 0)
player_x--;
}
if (mask & 0x8) {
if (player_x < PIXWIDTH-16)
player_x++;
}
if (mask & 0x10) {
if (bullet_y == 0) {
fire_bullet();
}
}
// move player
@ -392,7 +407,6 @@ void game_over_msg() {
}
void play_game() {
attract = 0;
init_game();
init_enemies();
while (lives) {
@ -404,14 +418,6 @@ void play_game() {
game_over_msg();
}
void attract_mode() {
attract = 1;
while (1) {
init_enemies();
play_round();
}
}
void main() {
hw_horcb = 40;
hw_verbl = VHEIGHT*2;

View File

@ -4,6 +4,7 @@
//#link "aclib.s"
#include "acbios.h"
//#link "acbios.s"
#include "acfast.h"
//#link "acfast.s"
//#link "hdr_autostart.s"
@ -25,9 +26,6 @@ const byte SPRITE[] = {
0x45,0xD1, 0x05,0x50, 0x04,0x10, 0x3C,0x3C,
};
extern void fast_sprite_8(const byte* pattern, byte* dst);
extern void fast_sprite_16(const byte* pattern, byte* dst);
#define MAX_SPRITES 8
typedef struct {

View File

@ -68,7 +68,8 @@ void main(void) {
// small font must be aligned to multiple of 4
display_string(4, 80, OPT_ON(1), "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9");
// paint a rectangle with a pattern mask (0xa5)
paint_rectangle(4, 72, 100, 4, 0xa5);
paint_rectangle(4, 72, 100, 5, 0x55);
paint_rectangle(6, 74, 100, 4, 0xaa);
// write from pattern block
write_relative(50, 80, M_XPAND, BALL);
write_relative(60, 80, M_XPAND, BALL);

View File

@ -10,6 +10,8 @@
#include <stdlib.h>
#include <string.h>
#pragma opt_code_speed
void draw_line(int x0, int y0, int x1, int y1, byte color) {
int dx = abs(x1-x0);
int sx = x0<x1 ? 1 : -1;

View File

@ -15,7 +15,7 @@ const byte palette[8] = {
0x07, 0xD4, 0x35, 0x01,
};
const byte BALL[] = {
const byte SPRITE[] = {
0, 0, // x and y offset
1, 4, // width (bytes) and height (lines)
/*{w:4,h:4,bpp:2,brev:1}*/
@ -26,17 +26,17 @@ const byte BALL[] = {
};
void draw_pattern(byte x) {
vmagic[0][x] = BALL[4];
vmagic[1][x] = BALL[5];
vmagic[2][x] = BALL[6];
vmagic[3][x] = BALL[7];
vmagic[0][x] = SPRITE[4];
vmagic[1][x] = SPRITE[5];
vmagic[2][x] = SPRITE[6];
vmagic[3][x] = SPRITE[7];
}
void draw_pattern_inv(byte x) {
vmagic[3][x] = BALL[4];
vmagic[2][x] = BALL[5];
vmagic[1][x] = BALL[6];
vmagic[0][x] = BALL[7];
vmagic[3][x] = SPRITE[4];
vmagic[2][x] = SPRITE[5];
vmagic[1][x] = SPRITE[6];
vmagic[0][x] = SPRITE[7];
}
void main(void) {

View File

@ -32,7 +32,7 @@ void main() {
while (1) {
write_relative(x, y, M_MOVE, player_bitmap);
write_relative(x, y+20, M_MOVE, player_bitmap);
write_relative(x, y+40, M_MOVE, player_bitmap);
write_relative(x, y+40, M_MOVE|M_FLOP, player_bitmap);
// write_relative(x, y+60, M_MOVE, player_bitmap);
fast_vsync();
x++;

View File

@ -95,10 +95,12 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
var infbk = 0;
var verbl = sheight;
var palette = new Uint32Array(8);
var palinds = new Uint8Array(8);
var refreshlines = 0;
var vidactive = false;
var rotdata = new Uint8Array(4);
var rotcount = 0;
var intst = 0;
function ramwrite(a:number, v:number) {
ram.mem[a] = v;
@ -178,13 +180,14 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
if (magicop & 0x20)
v ^= oldv; // TODO: what if both?
// upper 4 bits persist, lower are just since last write
inputs[8] = (inputs[8] & 0xf0) | icpt | (icpt<<4);
intst = (intst & 0xf0) | icpt | (icpt<<4);
}
// commit write to ram/screen
ramwrite(a, v);
}
function setpalette(a:number, v:number) {
palinds[a&7] = v&0xff;
palette[a&7] = ASTROCADE_PALETTE[v&0xff];
refreshall();
}
@ -253,11 +256,18 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
},
read: function(addr) {
addr &= 0x1f;
var rtn = inputs[addr];
if (addr == 8)
inputs[addr] = 0;
// $10 = watchdog
return rtn;
var rtn;
switch (addr) {
case 8:
rtn = intst;
intst = 0;
break;
default:
rtn = inputs[addr];
break;
// $10 = watchdog
}
return rtn;
},
write: function(addr, val) {
addr &= 0x1f;
@ -333,8 +343,10 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
pixels = video.getFrameData();
timer = new AnimationTimer(60, this.nextFrame.bind(this));
// default palette
for (var i=0; i<8; i++)
for (var i=0; i<8; i++) {
palinds[i] = i;
palette[i] = ASTROCADE_PALETTE[i];
}
}
readAddress(addr) {
@ -401,6 +413,7 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
cpu.loadState(state.c);
ram.mem.set(state.b);
palette.set(state.palette);
palinds.set(state.palinds);
magicop = state.magicop;
xpand = state.xpand;
xplower = state.xplower;
@ -412,6 +425,7 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
verbl = state.verbl;
rotcount = state.rotcount;
rotdata.set(state.rotdata);
intst = state.intst;
this.scanline = state.sl;
this.loadControlsState(state);
refreshall();
@ -422,6 +436,7 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
b: ram.mem.slice(0),
in: inputs.slice(0),
palette: palette.slice(0),
palinds: palinds.slice(0),
magicop: magicop,
xpand: xpand,
xplower: xplower,
@ -433,6 +448,7 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
verbl: verbl,
rotcount: rotcount,
rotdata: rotdata.slice(0),
intst: intst,
sl: this.scanline,
};
}
@ -490,12 +506,10 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
s += "\n HORCB: $" + hex(st.horcb);
s += "\n INMOD: $" + hex(st.inmod);
s += "\n INFBK: $" + hex(st.infbk);
s += "\n INTST: $" + hex(st.in[8]); // intercept status
/*
s += "\n INTST: $" + hex(st.intst); // intercept status
s += "\nPalette: ";
for (var i=0; i<8; i++)
s += hex(palette[i]);
*/
s += hex(palinds[i]);
s += "\n";
return s;
}

View File

@ -1645,7 +1645,7 @@ function installErrorHandler() {
} else {
// send exception msg to GA
var msg = msgstr;
if (typeof error == 'string') msg += ": " + error;
//if (typeof error == 'string') msg += ": " + error;
if (line) msg += " (" + line + ":" + col + ")";
if (msg.length > 256) { msg = msg.substring(0, 256); }
if (ga) ga('send', 'exception', {