2020-02-02 23:33:07 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2020-03-14 00:12:01 +00:00
|
|
|
#include <conio.h>
|
2020-02-02 23:33:07 +00:00
|
|
|
#include <dos.h>
|
2020-04-08 03:20:46 +00:00
|
|
|
#include <sys/stat.h>
|
2020-02-02 23:33:07 +00:00
|
|
|
#include <alloc.h>
|
|
|
|
#include <ctype.h>
|
2020-03-07 23:55:18 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <time.h>
|
2020-02-02 23:33:07 +00:00
|
|
|
|
|
|
|
#include "video.h"
|
|
|
|
#include "kbd.h"
|
|
|
|
#include "mouse.h"
|
|
|
|
#include "tiff.h"
|
|
|
|
#include "tiles.h"
|
|
|
|
#include "serial.h"
|
|
|
|
#include "timer.h"
|
|
|
|
#include "jorth.h"
|
|
|
|
#include "egamap.h"
|
|
|
|
#include "adlib.h"
|
2020-04-19 15:37:08 +00:00
|
|
|
#include "fakelib.h"
|
2020-02-02 23:33:07 +00:00
|
|
|
|
|
|
|
/*** T E X T ***/
|
|
|
|
char far *font = NULL;
|
|
|
|
|
|
|
|
void text_init() {
|
|
|
|
unsigned int fontSeg, fontOff;
|
|
|
|
asm {
|
|
|
|
push es
|
|
|
|
push bp
|
|
|
|
mov ah, 11h
|
|
|
|
mov al, 30h
|
|
|
|
mov bh, 3
|
|
|
|
int 10h
|
|
|
|
mov ax, bp
|
|
|
|
pop bp
|
|
|
|
mov fontSeg, es
|
|
|
|
mov fontOff, ax
|
|
|
|
pop es
|
|
|
|
}
|
|
|
|
font = MK_FP(fontSeg, fontOff);
|
|
|
|
}
|
|
|
|
|
2020-04-08 03:20:46 +00:00
|
|
|
void text_draw_char(unsigned int vidOffset, unsigned char c, int stride) {
|
2020-02-02 23:33:07 +00:00
|
|
|
unsigned int fontOffset = c << 3;
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 8; i ++) {
|
|
|
|
VID[vidOffset] = font[fontOffset++];
|
2020-04-08 03:20:46 +00:00
|
|
|
vidOffset += stride;
|
2020-02-02 23:33:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void text_draw(unsigned int vidOffset, unsigned char *s) {
|
|
|
|
while (*s) {
|
2020-04-08 03:20:46 +00:00
|
|
|
text_draw_char(vidOffset++, *s++, PAGE_STRIDE);
|
2020-02-02 23:33:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*** I / O ***/
|
|
|
|
size_t fwritefar(FILE *fp, void far *buf, size_t length) {
|
|
|
|
char nearbuf[32];
|
|
|
|
size_t written = 0;
|
|
|
|
size_t towrite;
|
|
|
|
|
|
|
|
for (; towrite = min(32, length), length > 0; length -= towrite) {
|
|
|
|
movedata(FP_SEG(buf), FP_OFF(buf) + written, _SS, nearbuf, towrite);
|
|
|
|
if (!fwrite(nearbuf, towrite, 1, fp)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
written += towrite;
|
|
|
|
}
|
|
|
|
return written;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t freadfar(FILE *fp, void far *buf, size_t length) {
|
|
|
|
char nearbuf[32];
|
|
|
|
size_t totalread = 0;
|
|
|
|
size_t toread;
|
|
|
|
|
|
|
|
for (; toread = min(32, length), length > 0; length -= toread) {
|
|
|
|
size_t bytesread = fread(nearbuf, 1, toread, fp);
|
|
|
|
movedata(_SS, nearbuf, FP_SEG(buf), FP_OFF(buf) + totalread, bytesread);
|
|
|
|
totalread += bytesread;
|
|
|
|
if (bytesread != toread) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return totalread;
|
|
|
|
}
|
|
|
|
|
2020-04-08 03:20:46 +00:00
|
|
|
void freadvram(FILE *fp, unsigned int offset, size_t length) {
|
|
|
|
char nearbuf[32];
|
|
|
|
int plane;
|
|
|
|
setWriteMode(0);
|
|
|
|
for (plane = 0; plane < 4; plane ++) {
|
|
|
|
volatile char far *vmem = &VID[offset];
|
|
|
|
size_t planelen = length;
|
|
|
|
size_t toread;
|
|
|
|
setPlane(plane);
|
|
|
|
for (; toread = min(32, planelen), planelen > 0; planelen -= toread) {
|
|
|
|
size_t bytesread = fread(nearbuf, 1, toread, fp);
|
|
|
|
size_t i;
|
|
|
|
for (i = 0; i < bytesread; i +=2) {
|
|
|
|
// don't ask me why they're byteswapped :P
|
|
|
|
*vmem++ = nearbuf[i+1];
|
|
|
|
*vmem++ = nearbuf[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void loadscr(char *basefn) {
|
|
|
|
char fn[16];
|
|
|
|
struct stat exists;
|
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
sprintf(fn, "%s.gfx", basefn);
|
|
|
|
if (stat(fn, &exists) != 0) {
|
|
|
|
TifImageMeta_t meta;
|
|
|
|
unsigned int far *buf = farmalloc(32000);
|
|
|
|
|
|
|
|
sprintf(fn, "%s.tif", basefn);
|
|
|
|
f = fopen(fn, "rb");
|
|
|
|
meta = tifLoadMeta(f);
|
|
|
|
tifLoad(f, meta, buf, 200, 200, 4);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
sprintf(fn, "%s.gfx", basefn);
|
|
|
|
f = fopen(fn, "wb");
|
|
|
|
fwritefar(f, buf, 32000);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
farfree(buf);
|
|
|
|
}
|
|
|
|
f = fopen(fn, "rb");
|
|
|
|
freadvram(f, 0, 8000);
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
2020-02-02 23:33:07 +00:00
|
|
|
/*** S C R A T C H ***/
|
|
|
|
#define PORTRAIT_GFX
|
|
|
|
|
|
|
|
#define NUM_SPRITES 64
|
|
|
|
#define TILE_STRIDE 64
|
|
|
|
#define SPRITE_STRIDE 80
|
|
|
|
#define PORTRAIT_STRIDE 256
|
|
|
|
unsigned int far *tiles;
|
|
|
|
unsigned int far *sprites;
|
|
|
|
unsigned int far *portraits;
|
|
|
|
unsigned char map[10000];
|
|
|
|
|
|
|
|
|
|
|
|
void deallocate_gfx() {
|
|
|
|
if (tiles) farfree(tiles);
|
|
|
|
if (sprites) farfree(sprites);
|
|
|
|
if (portraits) farfree(portraits);
|
|
|
|
}
|
|
|
|
|
|
|
|
void allocate_gfx() {
|
|
|
|
unsigned long memleft = farcoreleft();
|
|
|
|
tiles = farmalloc(NUM_TILES * TILE_STRIDE * 2);
|
|
|
|
sprites = farmalloc(NUM_SPRITES * SPRITE_STRIDE * 2);
|
|
|
|
portraits = farmalloc(NUM_PORTRAITS * PORTRAIT_STRIDE * 2);
|
|
|
|
atexit(deallocate_gfx);
|
|
|
|
|
|
|
|
if (!tiles || !sprites || !portraits) {
|
|
|
|
printf("%lu bytes free - need %lu\n", memleft,
|
|
|
|
(unsigned long)
|
|
|
|
((NUM_TILES * TILE_STRIDE * 2) +
|
|
|
|
(NUM_SPRITES * SPRITE_STRIDE * 2) +
|
|
|
|
(NUM_PORTRAITS * PORTRAIT_STRIDE * 2)));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void fillMap() {
|
|
|
|
unsigned int x, y, z;
|
|
|
|
z = 0;
|
|
|
|
|
|
|
|
for (y = 0; y < 100; y ++) {
|
|
|
|
for (x = 0; x < 100; x ++) {
|
|
|
|
map[x + (y * 100)] = ((x + y + z) >> 2) % 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void readTifTiles(char *filename) {
|
|
|
|
FILE *f;
|
|
|
|
TifImageMeta_t meta;
|
|
|
|
|
|
|
|
f = fopen(filename, "rb");
|
|
|
|
meta = tifLoadMeta(f);
|
|
|
|
tifLoad(f, meta, tiles, NUM_TILES * 16, 16, 4);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
loadTiles(OFF_TILES, tiles);
|
|
|
|
}
|
|
|
|
|
|
|
|
void readTiles(char *filename) {
|
|
|
|
FILE *f = fopen(filename, "rb");
|
|
|
|
freadfar(f, tiles, NUM_TILES * TILE_STRIDE * 2);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
loadTiles(OFF_TILES, tiles);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_loadtiles() {
|
|
|
|
if (tolower(TOP().s[strlen(TOP().s) - 1]) == 'f') {
|
|
|
|
readTifTiles(TOP().s);
|
|
|
|
} else {
|
|
|
|
readTiles(TOP().s);
|
|
|
|
}
|
|
|
|
DROP(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_load_footer() {
|
|
|
|
FILE *f = fopen("FOOTER.TIF", "rb");
|
|
|
|
TifImageMeta_t meta = tifLoadMeta(f);
|
|
|
|
tifLoadEGA(f, meta, 0, 48, 336);
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
2020-04-04 03:06:18 +00:00
|
|
|
void copyVidmem(unsigned int from, unsigned int to, unsigned int count) {
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
setAllPlanes();
|
|
|
|
setWriteMode(1);
|
|
|
|
|
|
|
|
for (i = 0; i < count; i ++) {
|
|
|
|
VID[to] = VID[from];
|
|
|
|
to ++; from ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-02 23:33:07 +00:00
|
|
|
void f_reloadportraits() {
|
|
|
|
blitMemToVid(OFF_PORTRAITS, portraits, PORTRAIT_STRIDE >> 2, NUM_PORTRAITS);
|
|
|
|
}
|
|
|
|
|
2020-04-02 23:11:01 +00:00
|
|
|
void showtextscreen(char* filename) {
|
2020-03-14 00:12:01 +00:00
|
|
|
FILE *f;
|
2020-04-02 23:11:01 +00:00
|
|
|
f = fopen(filename, "rb");
|
2020-03-14 00:12:01 +00:00
|
|
|
freadfar(f, MK_FP(0xb800, 0), 4000);
|
|
|
|
gotoxy(1, 24);
|
2020-09-06 15:11:36 +00:00
|
|
|
fclose(f);
|
2020-03-14 00:12:01 +00:00
|
|
|
}
|
2020-04-02 23:11:01 +00:00
|
|
|
void shownag() {
|
2020-04-04 03:06:18 +00:00
|
|
|
vid_cleanup();
|
2020-04-02 23:11:01 +00:00
|
|
|
showtextscreen("NEUTNAG.BIN");
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_showboss() {
|
2020-04-04 03:06:18 +00:00
|
|
|
copyVidmem(0, OFF_TILES, SIZE_FOOTER);
|
|
|
|
setMode(0083h)
|
2020-04-02 23:11:01 +00:00
|
|
|
showtextscreen("BOSSKEY.BIN");
|
|
|
|
kbd_wait();
|
2020-04-04 03:06:18 +00:00
|
|
|
setMode(008Dh)
|
|
|
|
copyVidmem(OFF_TILES, 0, SIZE_FOOTER);
|
2020-04-02 23:11:01 +00:00
|
|
|
}
|
2020-03-14 00:12:01 +00:00
|
|
|
|
2020-02-02 23:33:07 +00:00
|
|
|
void game_init() {
|
|
|
|
FILE *f;
|
|
|
|
TifImageMeta_t meta;
|
|
|
|
|
|
|
|
allocate_gfx();
|
|
|
|
|
|
|
|
mouse_init();
|
|
|
|
|
|
|
|
setEGAMode();
|
2020-03-14 00:12:01 +00:00
|
|
|
atexit(shownag);
|
2020-02-02 23:33:07 +00:00
|
|
|
|
|
|
|
kbd_init();
|
|
|
|
timer_init(TIMER_30HZ);
|
|
|
|
text_init();
|
2020-04-18 20:53:11 +00:00
|
|
|
adlib_init();
|
2020-04-19 15:37:08 +00:00
|
|
|
fakelib_init();
|
|
|
|
timer_setcallback(fakelib_tick);
|
2020-02-02 23:33:07 +00:00
|
|
|
|
2020-04-08 03:20:46 +00:00
|
|
|
loadscr("title");
|
|
|
|
/* f = fopen("TITLE.TIF", "rb");
|
2020-03-14 00:12:01 +00:00
|
|
|
meta = tifLoadMeta(f);
|
|
|
|
tifLoadEGA(f, meta, 0, 200, 320);
|
|
|
|
fclose(f);
|
2020-04-08 03:20:46 +00:00
|
|
|
*/
|
2020-02-02 23:33:07 +00:00
|
|
|
|
|
|
|
f = fopen("sprite.gfx", "rb");
|
|
|
|
freadfar(f, sprites, NUM_SPRITES * SPRITE_STRIDE * 2);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
#ifdef PORTRAIT_GFX
|
|
|
|
f = fopen("portrait.gfx", "rb");
|
|
|
|
freadfar(f, portraits, NUM_PORTRAITS * PORTRAIT_STRIDE * 2);
|
|
|
|
fclose(f);
|
|
|
|
f_reloadportraits();
|
|
|
|
#else
|
|
|
|
f = fopen("PORTRAIT.TIF", "rb");
|
|
|
|
meta = tifLoadMeta(f);
|
|
|
|
tifLoad(f, meta, portraits, NUM_PORTRAITS * 32, 32, 4);
|
|
|
|
tifLoadEGA(f, meta, OFF_PORTRAITS, NUM_PORTRAITS * 32, 32);
|
|
|
|
fclose(f);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
readTiles("tiles.gfx");
|
|
|
|
|
|
|
|
loadMap(map, 100, 100);
|
|
|
|
scroll(0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_seremit() {
|
|
|
|
ser_write_byte(TOP().i);
|
|
|
|
if (TOP().i == '\n') {
|
|
|
|
ser_write_byte('\r');
|
|
|
|
}
|
|
|
|
DROP(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_keyWasPressed() {
|
|
|
|
int k = TOP().i;
|
|
|
|
TOP().i = keyWasPressed(k);
|
|
|
|
consumeKey(k);
|
|
|
|
}
|
|
|
|
|
2020-09-06 15:11:36 +00:00
|
|
|
void f_keyWasReleased() {
|
|
|
|
int k = TOP().i;
|
|
|
|
TOP().i = keyWasReleased(k);
|
|
|
|
}
|
|
|
|
|
2020-02-02 23:33:07 +00:00
|
|
|
void f_keyIsDown() {
|
|
|
|
TOP().i = keyIsDown(TOP().i);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_drawSprite() { // ( x y sprite -- )
|
2020-02-02 23:29:49 +00:00
|
|
|
if (TOP().i >= 0) {
|
|
|
|
drawSprite(&sprites[TOP().i * SPRITE_STRIDE], ST2().i, ST1().i, NULL);
|
|
|
|
}
|
2020-02-02 23:33:07 +00:00
|
|
|
DROP(3);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_scroll() { // ( x y -- )
|
|
|
|
scroll(ST1().i, TOP().i);
|
|
|
|
DROP(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_scrollpos() { // ( -- x y )
|
|
|
|
PUSHI(screen.scrollX);
|
|
|
|
PUSHI(screen.scrollY);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_ticks() {
|
|
|
|
PUSHU(timer_counter);
|
|
|
|
}
|
2020-04-04 03:06:18 +00:00
|
|
|
void f_setticks() {
|
|
|
|
timer_counter = TOP().u;
|
|
|
|
DROP(1);
|
|
|
|
}
|
2020-02-02 23:33:07 +00:00
|
|
|
|
|
|
|
void f_splitscreen() {
|
|
|
|
setSplitScreen(399 - (TOP().i << 1));
|
|
|
|
DROP(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_textc() { // ( col line c color -- )
|
|
|
|
setWriteMode(0);
|
|
|
|
setPlaneColor(TOP().u);
|
|
|
|
DROP(1);
|
2020-04-08 03:20:46 +00:00
|
|
|
text_draw_char(ST2().u + (ST1().u * PAGE_STRIDE), TOP().i, PAGE_STRIDE);
|
2020-02-02 23:33:07 +00:00
|
|
|
DROP(3);
|
|
|
|
}
|
|
|
|
|
2020-04-08 03:20:46 +00:00
|
|
|
void f_rawtextc() { // ( offset c color -- )
|
2020-04-08 16:07:40 +00:00
|
|
|
unsigned int color = TOP().u;
|
|
|
|
unsigned int inverse = (~color) & 0x0f;
|
2020-04-08 03:20:46 +00:00
|
|
|
setWriteMode(0);
|
2020-04-08 16:07:40 +00:00
|
|
|
if (inverse) {
|
|
|
|
setPlaneColor(inverse);
|
|
|
|
text_draw_char(ST2().u, ' ', 40);
|
|
|
|
}
|
|
|
|
setPlaneColor(color);
|
|
|
|
text_draw_char(ST2().u, ST1().i, 40);
|
|
|
|
DROP(3);
|
2020-04-08 03:20:46 +00:00
|
|
|
}
|
|
|
|
|
2020-02-02 23:33:07 +00:00
|
|
|
void f_text() { // ( col line s color -- )
|
|
|
|
setWriteMode(0);
|
|
|
|
setPlaneColor(TOP().u);
|
|
|
|
DROP(1);
|
|
|
|
text_draw(ST2().u + (ST1().u * PAGE_STRIDE), TOP().s);
|
|
|
|
DROP(3);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_map() {
|
|
|
|
PUSHP(map);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_mapsize() { // ( -- w h )
|
|
|
|
PUSHI(screen.w);
|
|
|
|
PUSHI(screen.h);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_mapsize_set() { // ( w h -- )
|
|
|
|
loadMap(map, ST1().i, TOP().i);
|
|
|
|
DROP(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_mousepos() { // ( -- x y )
|
|
|
|
PUSHI(MOUSE.x);
|
|
|
|
PUSHI(MOUSE.y);
|
|
|
|
}
|
|
|
|
void f_mousebuttons() {
|
|
|
|
PUSHI(MOUSE.buttons);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_drawportrait() {
|
|
|
|
setAllPlanes();
|
|
|
|
setWriteMode(1);
|
|
|
|
blit32x32(OFF_PORTRAITS + (TOP().u << 7), (PAGE_STRIDE << 3) + 1);
|
|
|
|
DROP(1);
|
|
|
|
}
|
|
|
|
|
2020-04-19 15:37:08 +00:00
|
|
|
int use_adlib;
|
2020-02-02 23:33:07 +00:00
|
|
|
void f_adlib() {
|
2020-04-19 15:37:08 +00:00
|
|
|
if (use_adlib) {
|
|
|
|
adlib_write(TOP().u, ST1().u);
|
|
|
|
} else {
|
|
|
|
fakelib_write(TOP().u, ST1().u);
|
|
|
|
}
|
2020-02-02 23:33:07 +00:00
|
|
|
DROP(2);
|
|
|
|
}
|
|
|
|
|
2020-04-19 15:37:08 +00:00
|
|
|
void f_adlib_present() {
|
|
|
|
PUSHI(adlib_present);
|
|
|
|
}
|
|
|
|
|
2020-02-02 23:33:07 +00:00
|
|
|
cell f_atexit;
|
|
|
|
void f_cleanup() {
|
|
|
|
f_execcp(f_atexit);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_glitch() {
|
|
|
|
int count = TOP().u;
|
|
|
|
int i, x, y;
|
|
|
|
DROP(1);
|
|
|
|
for (i = 0; i < count; i ++) {
|
|
|
|
x = screen.scrollX + (rand() % 352) - 16;
|
|
|
|
y = screen.scrollY + (rand() % 232) - 16;
|
|
|
|
switch(rand()%2) {
|
|
|
|
case 0:
|
|
|
|
drawSprite(sprites + (rand() % (NUM_SPRITES * SPRITE_STRIDE)), x, y, NULL);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
drawSprite(mem + (rand() % MEM_SIZE), x, y, NULL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-08 03:20:46 +00:00
|
|
|
void f_loadscr() {
|
|
|
|
loadscr(TOP().s);
|
|
|
|
DROP(1);
|
|
|
|
}
|
|
|
|
|
2020-04-18 20:53:11 +00:00
|
|
|
void f_system() {
|
|
|
|
kbd_cleanup();
|
|
|
|
system(TOP().s);
|
|
|
|
DROP(1);
|
|
|
|
kbd_init();
|
|
|
|
}
|
|
|
|
|
2020-04-20 22:33:13 +00:00
|
|
|
void clearPages() {
|
|
|
|
unsigned int offset;
|
|
|
|
|
|
|
|
setAllPlanes();
|
|
|
|
setWriteMode(0);
|
|
|
|
for (offset = 0; offset < OFF_PAGE2 + SIZE_PAGE; offset ++) {
|
|
|
|
VID[offset] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-02 23:33:07 +00:00
|
|
|
/* JILES */
|
|
|
|
#define SCREEN_STRIDE 40
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
ET_SPRITE = 0,
|
|
|
|
ET_TILE = 1,
|
|
|
|
ET_PORTRAIT = 2
|
|
|
|
} EditTarget_t;
|
|
|
|
EditTarget_t editTarget = ET_SPRITE;
|
|
|
|
|
|
|
|
unsigned int far *getTarget(int index) {
|
|
|
|
if (editTarget == ET_SPRITE) {
|
|
|
|
return &sprites[index * SPRITE_STRIDE];
|
|
|
|
} else if (editTarget == ET_TILE) {
|
|
|
|
return &tiles[index * TILE_STRIDE];
|
|
|
|
} else {
|
|
|
|
return &portraits[index * PORTRAIT_STRIDE];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ET_STRIDE (editTarget == ET_SPRITE ? SPRITE_STRIDE : \
|
|
|
|
(editTarget == ET_TILE ? TILE_STRIDE : PORTRAIT_STRIDE))
|
|
|
|
|
|
|
|
int getsprpixel(int x, int y, unsigned int far *spr) {
|
|
|
|
int shift = (15 - (x % 16));
|
|
|
|
int plane_stride = 16;
|
|
|
|
int b, g, r, i, v;
|
|
|
|
if (editTarget == ET_PORTRAIT) {
|
|
|
|
y = y << 1;
|
|
|
|
if (x > 15) y ++;
|
|
|
|
plane_stride = 64;
|
|
|
|
}
|
|
|
|
spr += y;
|
|
|
|
b = (*spr & (1 << shift)) >> shift; spr += plane_stride;
|
|
|
|
g = (*spr & (1 << shift)) >> shift; spr += plane_stride;
|
|
|
|
r = (*spr & (1 << shift)) >> shift; spr += plane_stride;
|
|
|
|
i = (*spr & (1 << shift)) >> shift; spr += plane_stride;
|
|
|
|
v = editTarget != ET_SPRITE || (*spr & (1 << shift)) ? 0 : 1;
|
|
|
|
return b | (g << 1) | (r << 2) | (i << 3) | (v << 4);
|
|
|
|
}
|
|
|
|
int resetEnabledCache = 0;
|
|
|
|
|
|
|
|
#define setResetEnabledCached(m) \
|
|
|
|
if (resetEnabledCache != m) { \
|
|
|
|
resetEnabledCache = m; \
|
|
|
|
setResetEnabled(m); \
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawFatBox(int x, int y, int color) {
|
|
|
|
int faty;
|
|
|
|
int fill1 = color <= 0x0f ? 0xff : 0x55;
|
|
|
|
int fill2 = fill1 == 0xff ? 0xff : 0xaa;
|
|
|
|
unsigned int dst = SCREEN_STRIDE * y;
|
|
|
|
|
|
|
|
if (color > 0x0f) {
|
|
|
|
setResetEnabledCached(0);
|
|
|
|
} else {
|
|
|
|
setResetEnabledCached(0x0f);
|
|
|
|
setResetMask(color);
|
|
|
|
}
|
|
|
|
for ( faty = 0; faty < 8; faty ++) {
|
|
|
|
VID[dst + x + (SCREEN_STRIDE * faty)] = (faty % 2) ? fill1 : fill2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawDoubleFatBox(int x, int y, int colorl, int colorr) {
|
|
|
|
int faty, plane;
|
|
|
|
unsigned int dst = (SCREEN_STRIDE * y) + x;
|
|
|
|
|
|
|
|
setResetEnabledCached(0);
|
|
|
|
|
|
|
|
for ( plane = 0; plane < 4; plane ++ ) {
|
|
|
|
int fill = colorr & ( 1 << plane ) ? 0x0f : 0x00;
|
|
|
|
fill |= colorl & ( 1 << plane ) ? 0xf0 : 0x00;
|
|
|
|
|
|
|
|
setPlane( plane );
|
|
|
|
for ( faty = 0; faty < 4; faty ++ ) {
|
|
|
|
VID[dst + (SCREEN_STRIDE * faty)] = fill;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_drawfatsprite() {
|
|
|
|
int isprite = TOP().i;
|
|
|
|
unsigned int far *spr = getTarget(isprite);
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
DROP(1);
|
|
|
|
if (editTarget != ET_PORTRAIT) {
|
|
|
|
setAllPlanes();
|
|
|
|
for ( y = 0; y < 16; y ++ ) {
|
|
|
|
for ( x = 0; x < 16; x ++ ) {
|
|
|
|
int color = getsprpixel(x, y, spr);
|
|
|
|
drawFatBox(x, y << 3, color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for ( y = 0; y < 32; y ++ ) {
|
|
|
|
for ( x = 0; x < 32; x += 2 ) {
|
|
|
|
int colorl = getsprpixel( x, y, spr);
|
|
|
|
int colorr = getsprpixel(x + 1, y, spr);
|
|
|
|
drawDoubleFatBox(x >> 1, y << 2, colorl, colorr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
setAllPlanes();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-28 20:58:47 +00:00
|
|
|
void f_drawfatspritepixel() {
|
|
|
|
int x = ST2().i;
|
|
|
|
int y = ST1().i;
|
|
|
|
unsigned int far *spr = getTarget(TOP().i);
|
|
|
|
DROP(3);
|
|
|
|
|
|
|
|
if (editTarget != ET_PORTRAIT) {
|
|
|
|
int color = getsprpixel(x, y, spr);
|
|
|
|
|
|
|
|
setAllPlanes();
|
|
|
|
drawFatBox(x, y << 3, color);
|
|
|
|
} else {
|
|
|
|
int colorl, colorr;
|
|
|
|
|
|
|
|
x = x & 0xfffe;
|
|
|
|
colorl = getsprpixel( x, y, spr);
|
|
|
|
colorr = getsprpixel(x + 1, y, spr);
|
|
|
|
|
|
|
|
drawDoubleFatBox(x >> 1, y << 2, colorl, colorr);
|
|
|
|
setAllPlanes();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-02 23:33:07 +00:00
|
|
|
void f_drawfatbox() {
|
|
|
|
drawFatBox(ST1().i, TOP().i, ST2().i);
|
|
|
|
DROP(3);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_savegfx() {
|
|
|
|
FILE *fp = fopen(TOP().s, "wb");
|
|
|
|
if (editTarget == ET_SPRITE) {
|
|
|
|
fwritefar(fp, sprites, NUM_SPRITES * SPRITE_STRIDE * 2);
|
|
|
|
} else if (editTarget == ET_TILE) {
|
|
|
|
fwritefar(fp, tiles, NUM_TILES * TILE_STRIDE * 2);
|
|
|
|
} else {
|
|
|
|
fwritefar(fp, portraits, NUM_PORTRAITS * PORTRAIT_STRIDE * 2);
|
|
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
DROP(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_mousehide() {
|
|
|
|
mouse_hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_mouseshow() {
|
|
|
|
mouse_show();
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_resetvideo() {
|
|
|
|
setLogicalWidth(SCREEN_STRIDE >> 1);
|
|
|
|
setResetEnabledCached(0);
|
|
|
|
setWriteMode(0);
|
|
|
|
setAllPlanes();
|
|
|
|
setDisplayOffset(0);
|
|
|
|
setHorizontalPan(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_putpixel() {
|
|
|
|
int isprite = TOP().i;
|
|
|
|
unsigned int far *spr = getTarget(isprite);
|
|
|
|
int x = ST2().i;
|
|
|
|
int y = ST1().i;
|
|
|
|
int color, shift, b, g, r, i, v;
|
|
|
|
int plane_stride = 16;
|
|
|
|
|
|
|
|
DROP(3);
|
|
|
|
color = TOP().i;
|
|
|
|
DROP(1);
|
|
|
|
|
|
|
|
shift = (15 - (x % 16));
|
|
|
|
if (editTarget == ET_PORTRAIT) {
|
|
|
|
y = y << 1;
|
|
|
|
if (x > 15) y ++;
|
|
|
|
plane_stride = 64;
|
|
|
|
}
|
|
|
|
|
|
|
|
b = (color & 0x01);
|
|
|
|
g = (color & 0x02) >> 1;
|
|
|
|
r = (color & 0x04) >> 2;
|
|
|
|
i = (color & 0x08) >> 3;
|
|
|
|
v = ((color & 0x10) >> 4) ^ 1;
|
|
|
|
spr = &spr[y];
|
|
|
|
|
|
|
|
*spr = (*spr & ~(1 << shift)) | (b << shift); spr += plane_stride;
|
|
|
|
*spr = (*spr & ~(1 << shift)) | (g << shift); spr += plane_stride;
|
|
|
|
*spr = (*spr & ~(1 << shift)) | (r << shift); spr += plane_stride;
|
|
|
|
*spr = (*spr & ~(1 << shift)) | (i << shift); spr += plane_stride;
|
|
|
|
if (editTarget == ET_SPRITE) {
|
|
|
|
*spr = (*spr & ~(1 << shift)) | (v << shift);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_getpixel() {
|
|
|
|
int isprite = TOP().i;
|
|
|
|
unsigned int far *spr = getTarget(isprite);
|
|
|
|
int x = ST2().i;
|
|
|
|
int y = ST1().i;
|
|
|
|
DROP(2);
|
|
|
|
|
|
|
|
TOP().i = getsprpixel(x, y, spr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_spritecount() {
|
|
|
|
if (editTarget == ET_SPRITE) {
|
|
|
|
PUSHI(NUM_SPRITES);
|
|
|
|
} else if (editTarget == ET_TILE) {
|
|
|
|
PUSHI(NUM_TILES);
|
|
|
|
} else if (editTarget == ET_PORTRAIT) {
|
|
|
|
PUSHI(NUM_PORTRAITS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_tile2buf() {
|
|
|
|
unsigned int *buf = (unsigned int *)TOP().p;
|
|
|
|
unsigned int itile = ST1().u;
|
|
|
|
DROP(2);
|
|
|
|
writeTile(buf, &tiles[itile * TILE_STRIDE]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_spr2buf() {
|
|
|
|
unsigned int *buf = (unsigned int *)TOP().p;
|
|
|
|
unsigned int isprite = ST1().u;
|
|
|
|
DROP(2);
|
|
|
|
overlaySprite(buf, &sprites[isprite * SPRITE_STRIDE], 0, 0, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_remap_spr2buf() {
|
|
|
|
unsigned int *buf = (unsigned int *)TOP().p;
|
|
|
|
unsigned int isprite = ST1().u;
|
|
|
|
char *remap = (char*)ST2().p;
|
|
|
|
DROP(3);
|
|
|
|
overlaySprite(buf, &sprites[isprite * SPRITE_STRIDE], 0, 0, remap);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_pastetile() {
|
|
|
|
unsigned int far *src = getTarget(ST1().i);
|
|
|
|
unsigned int far *dst = getTarget(TOP().i);
|
|
|
|
unsigned int stride = ET_STRIDE;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
DROP(2);
|
|
|
|
for (i = 0; i < stride; i ++) {
|
|
|
|
dst[i] = src[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_fliptile() {
|
|
|
|
unsigned int far *dst = getTarget(TOP().i);
|
|
|
|
unsigned int stride = ET_STRIDE;
|
|
|
|
unsigned int i;
|
|
|
|
unsigned int bit;
|
|
|
|
|
|
|
|
DROP(1);
|
|
|
|
for (i = 0; i < stride; i ++) {
|
|
|
|
unsigned int src = dst[i];
|
|
|
|
unsigned int result = 0;
|
|
|
|
for (bit = 0; bit < 16; bit ++) {
|
|
|
|
if (src & (1 << bit)) {
|
|
|
|
result |= (1 << (15 - bit));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (editTarget == ET_PORTRAIT && ((i % 2) == 1)) {
|
|
|
|
bit = dst[i - 1];
|
|
|
|
dst[i - 1] = result;
|
|
|
|
dst[i] = bit;
|
|
|
|
} else {
|
|
|
|
dst[i] = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_vfliptile() {
|
|
|
|
unsigned int far *dst;
|
|
|
|
unsigned int far *gfx = editTarget == ET_SPRITE ? sprites : tiles;
|
|
|
|
unsigned int stride = editTarget == ET_SPRITE ? SPRITE_STRIDE : TILE_STRIDE;
|
|
|
|
unsigned int y;
|
|
|
|
unsigned int plane;
|
|
|
|
|
|
|
|
if (editTarget == ET_PORTRAIT) return; // TODO
|
|
|
|
dst = &gfx[TOP().i * stride];
|
|
|
|
DROP(1);
|
|
|
|
for (plane = 0; plane < (editTarget == ET_SPRITE ? 5 : 4); plane ++) {
|
|
|
|
for (y = 0; y < 8; y ++) {
|
|
|
|
unsigned int tmp = dst[y];
|
|
|
|
dst[y] = dst[15 - y];
|
|
|
|
dst[15 - y] = tmp;
|
|
|
|
}
|
|
|
|
dst += 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_nudgesprite() {
|
|
|
|
unsigned int far *dst = &sprites[TOP().i * SPRITE_STRIDE];
|
|
|
|
int direction = ST1().i < 0 ? -1 : 1;
|
|
|
|
int ystart = direction < 0 ? 0 : 15;
|
|
|
|
int ylim = direction < 0 ? 15 : 0;
|
|
|
|
int plane, y;
|
|
|
|
unsigned int itransparent = direction < 0 ? 64 : 79;
|
|
|
|
DROP(2);
|
|
|
|
if (dst[itransparent] != 0 || editTarget != ET_SPRITE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (plane = 0; plane < 5; plane ++) {
|
|
|
|
for (y = ystart; y != ylim; y -= direction) {
|
|
|
|
dst[y] = dst[y - direction];
|
|
|
|
}
|
|
|
|
dst[ylim] = 0;
|
|
|
|
dst += 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_paintbuf() {
|
|
|
|
unsigned int *buf = (unsigned int *)TOP().p;
|
|
|
|
int y = ST1().i;
|
|
|
|
int x = ST2().i;
|
|
|
|
DROP(3);
|
|
|
|
paintBuffer(buf, x + (y * SCREEN_STRIDE));
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_setedittarget() {
|
|
|
|
editTarget = TOP().i;
|
2020-09-06 18:54:08 +00:00
|
|
|
DROP(1);
|
2020-02-02 23:33:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void f_getedittarget() {
|
|
|
|
PUSHI(editTarget);
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_reloadtiles() {
|
|
|
|
loadTiles(OFF_TILES, tiles);
|
|
|
|
}
|
|
|
|
|
2020-04-08 03:20:46 +00:00
|
|
|
int DONE = 0;
|
|
|
|
static void f_quit() {
|
|
|
|
DONE = 1;
|
|
|
|
}
|
|
|
|
|
2020-02-02 23:33:07 +00:00
|
|
|
/* INIT */
|
|
|
|
void game_f_init(char *exe, char *bootjor) {
|
|
|
|
f_init(exe);
|
2020-04-08 03:20:46 +00:00
|
|
|
CDEF("quit", f_quit);
|
2020-02-02 23:33:07 +00:00
|
|
|
CDEF("seremit", f_seremit);
|
|
|
|
CDEF("key-pressed", f_keyWasPressed);
|
|
|
|
CDEF("key-down", f_keyIsDown);
|
2020-09-06 15:11:36 +00:00
|
|
|
CDEF("key-released", f_keyWasReleased);
|
2020-02-02 23:33:07 +00:00
|
|
|
CDEF("key-start", kbd_init);
|
|
|
|
CDEF("key-end", kbd_cleanup);
|
|
|
|
CDEF("draw-sprite", f_drawSprite);
|
|
|
|
CDEF("draw-portrait", f_drawportrait);
|
|
|
|
CDEF("scroll", f_scroll);
|
|
|
|
CDEF("scrollpos", f_scrollpos);
|
|
|
|
CDEF("draw-screen", drawScreen);
|
|
|
|
CDEF("split-screen", f_splitscreen);
|
2020-04-20 22:33:13 +00:00
|
|
|
CDEF("clear-pages", clearPages);
|
2020-02-02 23:33:07 +00:00
|
|
|
CDEF("ticks", f_ticks);
|
2020-04-04 03:06:18 +00:00
|
|
|
CDEF("ticks!", f_setticks);
|
2020-02-02 23:33:07 +00:00
|
|
|
CDEF("text", f_text);
|
|
|
|
CDEF("textc", f_textc);
|
2020-04-08 03:20:46 +00:00
|
|
|
CDEF("rawtextc", f_rawtextc);
|
2020-02-02 23:33:07 +00:00
|
|
|
CDEF("map", f_map);
|
|
|
|
CDEF("mapsize", f_mapsize);
|
|
|
|
CDEF("mapsize!", f_mapsize_set);
|
|
|
|
CDEF("mousepos", f_mousepos);
|
|
|
|
CDEF("mousebuttons", f_mousebuttons);
|
|
|
|
CDEF("loadtiles", f_loadtiles);
|
|
|
|
CDEF("glitch", f_glitch);
|
|
|
|
CDEF("unfuck", tile_init);
|
|
|
|
CDEF("load-footer", f_load_footer);
|
2020-04-08 03:20:46 +00:00
|
|
|
CDEF("loadscr", f_loadscr);
|
2020-02-02 23:33:07 +00:00
|
|
|
CDEF("fuck", f_resetvideo);
|
2020-04-02 23:11:01 +00:00
|
|
|
CDEF("boss", f_showboss);
|
2020-04-18 20:53:11 +00:00
|
|
|
CDEF("system", f_system);
|
|
|
|
CDEF("adlib!", f_adlib);
|
2020-04-19 15:37:08 +00:00
|
|
|
CDEF("adlib?", f_adlib_present);
|
|
|
|
PCONST("use-adlib", &use_adlib);
|
|
|
|
use_adlib = adlib_present;
|
2020-02-02 23:33:07 +00:00
|
|
|
|
|
|
|
CDEF("mouseshow", f_mouseshow);
|
|
|
|
CDEF("mousehide", f_mousehide);
|
|
|
|
CDEF("drawfatsprite", f_drawfatsprite);
|
2020-03-28 20:58:47 +00:00
|
|
|
CDEF("drawfatspritepixel", f_drawfatspritepixel);
|
2020-02-02 23:33:07 +00:00
|
|
|
CDEF("drawfatbox", f_drawfatbox);
|
|
|
|
CDEF("putpixel", f_putpixel);
|
|
|
|
CDEF("getpixel", f_getpixel);
|
|
|
|
CDEF("spritecount", f_spritecount);
|
|
|
|
CDEF("savegfx", f_savegfx);
|
|
|
|
CDEF("tile>buf", f_tile2buf);
|
|
|
|
CDEF("spr>buf", f_spr2buf);
|
|
|
|
CDEF("remap-spr>buf", f_remap_spr2buf);
|
|
|
|
CDEF("paintbuf", f_paintbuf);
|
|
|
|
CDEF("edittarget", f_getedittarget);
|
|
|
|
CDEF("edittarget!", f_setedittarget);
|
|
|
|
CDEF("reloadtiles", f_reloadtiles);
|
|
|
|
CDEF("reloadportraits", f_reloadportraits);
|
|
|
|
CDEF("paste-tile", f_pastetile);
|
|
|
|
CDEF("flip-tile", f_fliptile);
|
|
|
|
CDEF("vflip-tile", f_vfliptile);
|
|
|
|
CDEF("nudge-sprite", f_nudgesprite);
|
|
|
|
|
|
|
|
f_loadjor(bootjor);
|
|
|
|
|
|
|
|
f_atexit = f_lookupcp("atexit");
|
|
|
|
atexit(f_cleanup);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void f_poll() {
|
|
|
|
static char line[128] = { 0 };
|
|
|
|
|
|
|
|
while (ser_getline(line)) {
|
|
|
|
PUSHS(line);
|
|
|
|
f_runstring("REPL send");
|
|
|
|
f_taskloop();
|
|
|
|
line[0] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
char *bootjor = "gameboot.jor";
|
2020-03-14 00:12:01 +00:00
|
|
|
|
2020-02-02 23:33:07 +00:00
|
|
|
if (argc > 1) {
|
|
|
|
bootjor = argv[1];
|
|
|
|
}
|
2020-03-07 23:55:18 +00:00
|
|
|
randomize();
|
2020-02-02 23:33:07 +00:00
|
|
|
ser_init(SER_COM2, BAUD_19200, SER_8N1);
|
|
|
|
game_init();
|
|
|
|
game_f_init(argv[0], bootjor);
|
|
|
|
|
2020-04-08 03:20:46 +00:00
|
|
|
while (!keyIsDown(K_F12) && !DONE) {
|
2020-02-02 23:33:07 +00:00
|
|
|
kbd_debounce();
|
|
|
|
f_poll();
|
|
|
|
f_taskloop();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|