#define VECTREX 1
#ifdef VECTREX
#include <vectrex.h>
#else
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define Reset0Ref()
#define Draw_Line_d(y,x)
#define Moveto_d(y,x)
#define Draw_VLc(x)
#endif
#define GRIDLOW -64
#define GRIDHIGH 63
#define PGRIDSCALE 255U
#define XYGRIDSCALE 200U
#define ABSSCALE 127U
#define MY_Y GRIDLOW
#define MEANIE_Y = GRIDHIGH // for now
static inline void set_scale(unsigned int s) {
#ifdef VECTREX
// this should not be faster, but it is. The write to the VIA must be slow.
static unsigned int last_scale = 0;
if (last_scale != s) {
VIA_t1_cnt_lo = last_scale = s;
}
#endif
}
int gridview = 0; // view without perspective when 1.
unsigned int gridscale;
int SX=0, SY=0; // screen X,Y - actual beam pos
static inline void swap (int *a, int *b) {
int t = *a; *a = *b; *b = t;
}
#ifdef VECTREX
static const int perspectiveY[256] = {
-107, -107, -107, -107, -107, -106, -106, -106, -106, -105, -105, -105, -105, -105, -104, -104,
-104, -104, -103, -103, -103, -103, -102, -102, -102, -102, -101, -101, -101, -101, -100, -100,
-100, -100, -99, -99, -99, -98, -98, -98, -98, -97, -97, -97, -96, -96, -96, -95,
-95, -95, -95, -94, -94, -94, -93, -93, -92, -92, -92, -91, -91, -91, -90, -90,
-90, -89, -89, -88, -88, -88, -87, -87, -86, -86, -86, -85, -85, -84, -84, -84,
-83, -83, -82, -82, -81, -81, -80, -80, -79, -79, -78, -78, -77, -77, -76, -76,
-75, -75, -74, -74, -73, -73, -72, -72, -71, -71, -70, -69, -69, -68, -68, -67,
-66, -66, -65, -65, -64, -63, -63, -62, -61, -61, -60, -59, -59, -58, -57, -57,
-56, -55, -54, -54, -53, -52, -51, -51, -50, -49, -48, -48, -47, -46, -45, -44,
-43, -43, -42, -41, -40, -39, -38, -37, -36, -36, -35, -34, -33, -32, -31, -30,
-29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -18, -17, -16, -15, -14, -13,
-12, -11, -9, -8, -7, -6, -5, -3, -2, -1, 0, 2, 3, 4, 6, 7,
8, 10, 11, 13, 14, 15, 17, 18, 20, 21, 23, 24, 26, 27, 29, 30,
32, 34, 35, 37, 39, 40, 42, 44, 45, 47, 49, 51, 52, 54, 56, 58,
60, 62, 64, 65, 67, 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 90,
92, 95, 97, 99, 101, 104, 106, 108, 111, 113, 116, 118, 120, 123, 125, 127,
};
void init_perspective(void) {
}
#else
double perspectiveY[256L]; // map Y=0:255 to Y'=n:255
void init_perspective(void) {
long mapsto, step, Y, UY;
// initialise perspective table. Can be done in rom. Needs calc using 'e' :-/
//fprintf(stdout, "Setting p[127] to 255\n");
perspectiveY[255] = (double)255;
for (Y = 254L; Y >= 0L; Y--) { // top wide, bottom narrow. 16 passes
UY=Y-128;
perspectiveY[Y] = perspectiveY[Y+1]*0.99;
//fprintf(stdout, "Setting p[%d] to %d\n", UY, (int)perspectiveY[Y]);
}
for (Y = 0L; Y < 256L; Y++) { // top wide, bottom narrow. 16 passes
perspectiveY[Y] = round(perspectiveY[Y]);
}
for (Y = 0L; Y < 256L; Y++) { // top wide, bottom narrow. 16 passes
perspectiveY[Y] = -(255-perspectiveY[Y] - 128);
}
perspectiveY[255]=127;
for (Y = -128L; Y < 128L; Y++) { // top wide, bottom narrow. 16 passes
fprintf(stdout, " %d,", (int)(signed char)(perspectiveY[((Y+128)&255)]));
if (((Y+128)&15) == 15) fprintf(stdout, "\n");
}
exit(0);
}
#endif
static inline int PY(int Y) {
if (gridview) return Y;
return -perspectiveY[255-(Y+128)]-32; // -32 is just to move it down the screen
// I should have built the '-' and '255-' into the table. Too lazy to go back and redo it.
}
static inline int PX(int X, int Y) {
if (gridview) return X;
typedef union {
struct {
unsigned int high;
unsigned int low;
} byte;
struct {
unsigned long val;
} word;
} var;
var prod;
unsigned int LY = 255U-(unsigned int)(128+PY(Y)); // convert Y from -128:127 to 0:255
prod.word.val = (long unsigned int)X * (long unsigned int)LY;
return (int)(prod.byte.high); // what we do to avoid >>8 ... :-( btw <<1 causes overflow}
}
// These are in grid space but draw in perspective:
static inline void MoveAbsXY(int x, int y) {
Reset0Ref();
// SX = SY = 0;
//Moveto_d(y-SY, x-SX);
Moveto_d(y, x);
SX = x; SY = y;
}
static inline void PerspectiveMove(int x, int y) {
set_scale(gridscale);
MoveAbsXY(PX(x,y),PY(y));
}
static inline void LineAbsXY(int x, int y) {
Draw_Line_d(y-SY, x-SX); // sizes are carefully chosen so this never overflows
SX = x; SY = y;
}
static inline void PerspectiveLine(int x, int y) {
set_scale(gridscale);
LineAbsXY(PX(x,y),PY(y));
}
#define MAX_MEANIES 3
static int
meanie_x[MAX_MEANIES] = {-48, 0, 48},
meanie_y[MAX_MEANIES] = {0, -50, -16},
meanie_dx[MAX_MEANIES] = { 2, 0, 0},
meanie_dy[MAX_MEANIES] = {0, 2, 4};
static int my_x = 0;
static inline void draw_me(void) {
static int Me[] = {4, -9,0, 9,-9, 9,9, -9,9, -9,-9};
PerspectiveMove(my_x,GRIDLOW);
set_scale(0x7f);
Draw_VLc(Me);
}
static int missile_x, missile_y;
static int firing = 0;
static inline void draw_missile(void) {
static int Missile[] = {4, -9,0, 9,-9, 9,9, -9,9, -9,-9};
PerspectiveMove(missile_x,missile_y);
set_scale((unsigned int)PX(0x7f, missile_y)); // hacky way to apply perspective
//set_scale((unsigned int)PY(missile_y));
Draw_VLc(Missile);
missile_y += 8;
if (missile_y >= GRIDHIGH) firing = 0; // also when it hits a target...
}
static inline void draw_meanie(int x, int y) {
static int Meanie[] = {4, -3,0, 3,-3, 3,3, -3,3, -3,-3};
PerspectiveMove(x,y);
set_scale((unsigned int)PX(0x7f, y)<<1); // hacky way to apply perspective
//set_scale((unsigned int)PY(y)<<1);
Draw_VLc(Meanie);
}
static inline void draw_meanies(void) {
int m; // assumes all on screen all the time.
for (m = 0; m < MAX_MEANIES; m++) {
// if (((meanie_y[m] > GRIDLOW)) && ((meanie_y[m] < GRIDHIGH))) {
draw_meanie(meanie_x[m], meanie_y[m]);
// }
}
}
static void draw_moving_grid(int depth) {
int row, col;
// adding these two lines not only costs cycles we can no longer afford,
// they also mess up the display! Not sure why.
//Print_Str_d(127, -60, "BEAM RIDER\x80");
//Print_Str_d(-127, -120, "L 1 R 2 VIEW 3 FIRE 4\x80");
PerspectiveMove(0, GRIDHIGH);
Moveto_d(0, 64); // Horizon
Draw_Line_d(0, -128); // Horizon
for (col = -48; col <= 48; col += 16) {
PerspectiveMove(col, GRIDLOW); // as long as gridhigh-gridlow <= 127
PerspectiveLine(col, GRIDHIGH); // draw vertical grid component
}
for (row = depth+32; row >= depth-64; row -= 32) {
// depth is the small delta movement between gaps
PerspectiveMove(-48, row); PerspectiveLine(48, row); // draw horizontal grid component
}
}
int main(void) {
int left=0, right=0, fire=0;
int direction=0;
int granularity = 1; // grid speed: can increase up to 4 as more speed needed later in game
int depth = 0, actiontick = 0, slowmode = 1;
// set slowmode to 0 when player reaches basic score that
// shows he knows how the game works...
init_perspective();
for (;;) {
#ifdef VECTREX
Wait_Recal();
Intensity_7F();
// poll buttons. Old code. Should use library calls now.
asm("pshs x,y,u,dp");
asm("lda #0");
asm("jsr 0HF1B4 ; read_btns_mask":::"a","b","d");
asm("puls dp,u,y,x");
left = (*(volatile int *)(0xC80F)) & 1;
right = (*(volatile int *)(0xC80F)) & 2;
gridview = (*(volatile int *)(0xC80F)) & 4; // debugging aid
gridscale = gridview ? XYGRIDSCALE : PGRIDSCALE; // whenever gridview changes...
fire = (*(volatile int *)(0xC80F)) & 8;
#endif
if (left && !right) {
if (my_x > -48) my_x -= 2; direction = -2;
} else if (right && !left) {
if (my_x < 48) my_x += 2; direction = 2;
}
if (my_x & 15) my_x += direction; // make sure it parks on a beam when you release
if (fire && !firing) {
missile_x = (int)(my_x+8)&(int)0xf0; missile_y = GRIDLOW;
firing = 1;
}
if (firing) draw_missile();
draw_moving_grid(depth);
draw_meanies();
draw_me();
if (actiontick == 0) {
// update game state - enemy AI...
int i;
meanie_x[0] += meanie_dx[0];
if (meanie_x[0] == 64-16) meanie_dx[0] = -meanie_dx[0];
if (meanie_x[0] == -64+16) meanie_dx[0] = -meanie_dx[0];
for (i = 0; i < MAX_MEANIES; i++) {
meanie_y[i] -= granularity+meanie_dy[i];
if (meanie_y[i] <= -64) meanie_y[i] = 64;
}
depth -= granularity;
if (depth <= 0) depth = 32;
}
if (slowmode) actiontick = (actiontick + 1)&1;
}
return 0;
}