#include <vectrex.h>
#include "controller.h"
#ifndef TRUE
#define TRUE (0==0)
#define FALSE (!TRUE)
#endif
static unsigned char current_intensity = 127;
#define HEIGHT 30
#define HALF_HEIGHT 15
#define WIDTH 30
#define HALF_WIDTH 15
#define tx(x) (x)
#define ty(y) (y)
void line(int xl, int yb, int xr, int yt) {
int a,b;
int dx, dy;
Intensity_a(current_intensity);
Reset0Ref();
a=ty(yb); b=tx(xl);
Moveto_d((int)(a<<2), (int)(b<<2));
dy = ty(yt)-a; dx = tx(xr)-b;
Draw_Line_d((int)(dy<<2), (int)(dx<<2));
}
// original author 'CatOnTreeStudio' at scratch.mit.edu
// hacked by gtoal@gtoal.com for Vectrex
// To do: use perspective spacing for walls as in
// https://scratch.mit.edu/projects/157841571/
// (Currently spacing is linear and doesn't look quite right)
#define KEY_RIGHT 0
#define KEY_LEFT 1
#define KEY_UP 2
#define KEY_DOWN 3
#define KEY_ANY 4
int key(int code) {
unsigned int bit[5] = { 0x88, 0x44, 0x22, 0x11, 0xFF };
return (int)buttons_pressed() & (int)bit[code];
}
#define FADE 8
void intensity(int i) {
Intensity_a(current_intensity = (unsigned char)i);
}
static int
rotation=1, KeyPressOn=0;
static int
dist,
stepX=0,
stepY=0,
Size_X,
Size_Y,
HeroPosY,
HeroPosX,
ScreenSizeX,
ScreenSizeY,
ScreenPosX,
ScreenPosY;
// The original scratch code supported coloured blocks and the different
// codes (1:7) below represent different coloured blocks (walls).
// (9 is a corridor space and I think 8 was for an object in a space)
// If the maze is pre-built like this, using a large array is OK as it
// is const and therefore in ROM space. However if you need dynamic
// dungeon generation then the array could be shrunk considerably by
// replacing each byte with a single bit (since the vectrex only
// supports one colour), and packing 8 bits per byte.
// (the fenceposts are because Scratch's arrays are based at 1 rather than 0.
// - easier to add an exra element than to adjust all the indexes)
const char *Level[] = {
"1111111111111111111111"
"1111111111111111111111",
"1199919119991199991111", // <-- starts in northwest corner (2,2)
"1191119999199994491111",
"1191111119194444491111",
"1191111119199999499911",
"1199999989111944444911",
"1191111939111999494911",
"1191199939991119994911",
"1111193333391119199911",
"1199199933399919111111",
"1191111933333919999111",
"1199999939933919119911",
"1191111933933919111911",
"1191111933933911111911",
"1191191993999999199911",
"1199991193933919991911",
"1191191993933911111911",
"1191191933933911999911",
"1191191993999911111211",
"1111111113333111111111",
"1111111111111111111111",
};
// left and right wall code could be merged into one procedure at the expense of clarity.
// I'm OK with the redundancy for now.
void DrawLeftWall (int WallPosXLeft, int WallPosYUp, int WallPosYDown, int stepX, int stepY) {
if (Level[(HeroPosY + dist * stepY - stepX)][(HeroPosX + dist * stepX + stepY)] > '7') {
if (Level[(HeroPosY + (dist + 1) * stepY - stepX)][(HeroPosX + (dist + 1) * stepX + stepY)] > '7') {
if (WallPosYUp - (HALF_WIDTH + (dist + 1) * Size_X) * 3/8 != 0) {
line(WallPosXLeft + dist * Size_X, WallPosYUp - (HALF_WIDTH + dist * Size_X) * 3/8,
WallPosXLeft + (dist + 1) * Size_X, WallPosYUp - (HALF_WIDTH + (dist + 1) * Size_X) * 3/8);
}
if (WallPosYDown + (dist + 1) * Size_Y != 0) {
line(WallPosXLeft + (dist + 1) * Size_X, WallPosYUp - (dist + 1) * Size_Y,
WallPosXLeft + (dist + 1) * Size_X, WallPosYDown + (dist + 1) * Size_Y);
line(WallPosXLeft + (dist + 1) * Size_X, WallPosYDown + (HALF_WIDTH + (dist + 1) * Size_X) * 3/8,
WallPosXLeft + dist * Size_X, WallPosYDown + (HALF_WIDTH + dist * Size_X) * 3/8);
}
} else {
if (WallPosYUp - (dist + 1) * Size_Y != 0) {
line(WallPosXLeft + dist * Size_X, WallPosYUp - (dist + 1) * Size_Y,
WallPosXLeft + (dist + 1) * Size_X, WallPosYUp - (dist + 1) * Size_Y);
line(WallPosXLeft + (dist + 1) * Size_X, WallPosYUp - (dist + 1) * Size_Y,
WallPosXLeft + (dist + 1) * Size_X, WallPosYDown + (dist + 1) * Size_Y);
line(WallPosXLeft + (dist + 1) * Size_X, WallPosYDown + (dist + 1) * Size_Y,
WallPosXLeft + dist * Size_X, WallPosYDown + (dist + 1) * Size_Y);
}
}
} else {
if (WallPosYDown + (dist + 1) * Size_Y != 0) {
line(WallPosXLeft + dist * Size_X, WallPosYUp - dist * Size_Y,
WallPosXLeft + (dist + 1) * Size_X, WallPosYUp - (dist + 1) * Size_Y);
line(WallPosXLeft + (dist + 1) * Size_X, WallPosYUp - (dist + 1) * Size_Y,
WallPosXLeft + (dist + 1) * Size_X, WallPosYDown + (dist + 1) * Size_Y);
line(WallPosXLeft + (dist + 1) * Size_X, WallPosYDown + (dist + 1) * Size_Y,
WallPosXLeft + dist * Size_X, WallPosYDown + dist * Size_Y);
}
}
}
void DrawRightWall (int WallPosXRight, int WallPosYUp, int WallPosYDown, int stepX, int stepY) {
if (Level[(HeroPosY + dist * stepY + stepX)][(HeroPosX + dist * stepX - stepY)] > '7') {
if (Level[(HeroPosY + (dist + 1) * stepY + stepX)][(HeroPosX + (dist + 1) * stepX - stepY)] > '7') {
if (WallPosYUp - (dist + 1) * Size_Y != 0) {
line(WallPosXRight - dist * Size_X, WallPosYUp - (HALF_WIDTH + dist * Size_X) * 3/8,
WallPosXRight - (dist + 1) * Size_X, WallPosYUp - (HALF_WIDTH + (dist + 1) * Size_X) * 3/8);
line(WallPosXRight - (dist + 1) * Size_X, WallPosYUp - (dist + 1) * Size_Y,
WallPosXRight - (dist + 1) * Size_X, WallPosYDown + (dist + 1) * Size_Y);
line(WallPosXRight - (dist + 1) * Size_X, WallPosYDown + (HALF_WIDTH + (dist + 1) * Size_X) * 3/8,
WallPosXRight - dist * Size_X, WallPosYDown + (HALF_WIDTH + dist * Size_X) * 3/8);
}
} else {
if (WallPosYUp - (dist + 1) * Size_Y != 0) {
line(WallPosXRight - dist * Size_X, WallPosYUp - (dist + 1) * Size_Y,
WallPosXRight - (dist + 1) * Size_X, WallPosYUp - (dist + 1) * Size_Y);
line(WallPosXRight - (dist + 1) * Size_X, WallPosYUp - (dist + 1) * Size_Y,
WallPosXRight - (dist + 1) * Size_X, WallPosYDown + (dist + 1) * Size_Y);
line(WallPosXRight - (dist + 1) * Size_X, WallPosYDown + (dist + 1) * Size_Y,
WallPosXRight - dist * Size_X, WallPosYDown + (dist + 1) * Size_Y);
}
}
} else {
if (WallPosYDown + (dist + 1) * Size_Y != 0) {
line(WallPosXRight - dist * Size_X, WallPosYDown + dist * Size_Y,
WallPosXRight - dist * Size_X, WallPosYUp - dist * Size_Y);
line(WallPosXRight - dist * Size_X, WallPosYUp - dist * Size_Y,
WallPosXRight - (dist + 1) * Size_X, WallPosYUp - (dist + 1) * Size_Y);
line(WallPosXRight - (dist + 1) * Size_X, WallPosYUp - (dist + 1) * Size_Y,
WallPosXRight - (dist + 1) * Size_X, WallPosYDown + (dist + 1) * Size_Y);
line(WallPosXRight - (dist + 1) * Size_X, WallPosYDown + (dist + 1) * Size_Y,
WallPosXRight - dist * Size_X, WallPosYDown + dist * Size_Y);
}
}
}
void BuildBackgroundWall (int WallPosXLeft, int WallPosXRight, int WallPosYDown, int WallPosYUp, int stepX, int stepY) {
dist = 0;
intensity ((int)(64 - dist * FADE));
while (!( (Level[(HeroPosY + dist * stepY)][(HeroPosX + dist * stepX)] < '8') || (dist > 4) )) {
DrawLeftWall (WallPosXLeft, WallPosYUp, WallPosYDown, stepX, stepY);
DrawRightWall (WallPosXRight, WallPosYUp, WallPosYDown, stepX, stepY);
dist += 1;
intensity ((int)(64 - dist * FADE));
}
intensity ((int)(64 - (dist - 1) * FADE));
if (WallPosYDown + dist * Size_Y != 0) {
line(WallPosXLeft + dist * Size_X, WallPosYDown + dist * Size_Y,
WallPosXRight - dist * Size_X, WallPosYDown + dist * Size_Y);
line(WallPosXRight - dist * Size_X, WallPosYUp - dist * Size_Y,
WallPosXLeft + dist * Size_X, WallPosYUp - dist * Size_Y);
}
}
#define set_scale(i) VIA_t1_cnt_lo = i
void DrawFrame(void) {
Wait_Recal();
set_scale(0x7F);
Read_Btns();
enable_controller_1_x();
enable_controller_1_y();
Joy_Analog();
Intensity_a(60);
Print_Str_d(-100,-120, "BACK FORWARD LEFT RIGHT\x80");
if (rotation == 0) {
stepX = 1; stepY = 0;
} else if (rotation == 1) {
stepX = 0; stepY = 1;
} else if (rotation == 2) {
stepX = -1; stepY = 0;
} else /* rotation == 3 */ {
stepX = 0; stepY = -1;
}
if (KeyPressOn && !key(KEY_ANY)) {
KeyPressOn = 0;
} else if (key(KEY_LEFT)) {
if (KeyPressOn == 0) { rotation += 3; KeyPressOn = 1; }
} else if (key(KEY_RIGHT)) {
if (KeyPressOn == 0) { rotation += 1; KeyPressOn = 1; }
} else if (key(KEY_UP)) {
if (KeyPressOn == 0) {
if (Level[(HeroPosY + stepY)][(HeroPosX + stepX)] > '7') { HeroPosX += stepX; HeroPosY += stepY; }
KeyPressOn = 1;
}
} else if (key(KEY_DOWN)) {
if (KeyPressOn == 0) {
if (Level[(HeroPosY - stepY)][(HeroPosX - stepX)] > '7') { HeroPosX -= stepX; HeroPosY -= stepY; }
KeyPressOn = 1;
}
}
rotation &= 3;
{ int a,b,c,d; // avoid gcc bug
a = (rotation^1)&1;
b = -((rotation&2)-1);
c = (rotation&1);
d = -((rotation&2)-1);
BuildBackgroundWall (ScreenPosX, ScreenPosX + ScreenSizeX, ScreenPosY, ScreenPosY + ScreenSizeY,
a * b, c * d);
}
}
int main(void) {
HeroPosY = 2; HeroPosX = 2; // initial square
ScreenSizeX = WIDTH; ScreenSizeY = HEIGHT; // size of scratch display
ScreenPosX = -HALF_WIDTH; ScreenPosY = -HALF_HEIGHT; // center
Size_X = ScreenSizeX / 10L; Size_Y = ScreenSizeY / 10L;
for (;;) DrawFrame();
return 0;
}