#include #include #include #include #include #include #include #include #include #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" /*** 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); } void text_draw_char(unsigned int vidOffset, unsigned char c, int stride) { unsigned int fontOffset = c << 3; int i; for (i = 0; i < 8; i ++) { VID[vidOffset] = font[fontOffset++]; vidOffset += stride; } } void text_draw(unsigned int vidOffset, unsigned char *s) { while (*s) { text_draw_char(vidOffset++, *s++, PAGE_STRIDE); } } /*** 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; } 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); } /*** 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); } 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 ++; } } void f_reloadportraits() { blitMemToVid(OFF_PORTRAITS, portraits, PORTRAIT_STRIDE >> 2, NUM_PORTRAITS); } void showtextscreen(char* filename) { FILE *f; f = fopen(filename, "rb"); freadfar(f, MK_FP(0xb800, 0), 4000); gotoxy(1, 24); } void shownag() { vid_cleanup(); showtextscreen("NEUTNAG.BIN"); } void f_showboss() { copyVidmem(0, OFF_TILES, SIZE_FOOTER); setMode(0083h) showtextscreen("BOSSKEY.BIN"); kbd_wait(); setMode(008Dh) copyVidmem(OFF_TILES, 0, SIZE_FOOTER); } void game_init() { FILE *f; TifImageMeta_t meta; allocate_gfx(); mouse_init(); setEGAMode(); atexit(shownag); kbd_init(); timer_init(TIMER_30HZ); text_init(); loadscr("title"); /* f = fopen("TITLE.TIF", "rb"); meta = tifLoadMeta(f); tifLoadEGA(f, meta, 0, 200, 320); fclose(f); */ 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); } void f_keyIsDown() { TOP().i = keyIsDown(TOP().i); } void f_drawSprite() { // ( x y sprite -- ) if (TOP().i >= 0) { drawSprite(&sprites[TOP().i * SPRITE_STRIDE], ST2().i, ST1().i, NULL); } 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); } void f_setticks() { timer_counter = TOP().u; DROP(1); } void f_splitscreen() { setSplitScreen(399 - (TOP().i << 1)); DROP(1); } void f_textc() { // ( col line c color -- ) setWriteMode(0); setPlaneColor(TOP().u); DROP(1); text_draw_char(ST2().u + (ST1().u * PAGE_STRIDE), TOP().i, PAGE_STRIDE); DROP(3); } void f_rawtextc() { // ( offset c color -- ) setWriteMode(0); setPlaneColor(TOP().u); DROP(1); text_draw_char(ST1().u, TOP().i, 40); DROP(2); } 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); } void f_adlib() { adlib_write(TOP().u, ST1().u); DROP(2); } 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; } } } void f_loadscr() { loadscr(TOP().s); DROP(1); } /* 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(); } } 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(); } } 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; } void f_getedittarget() { PUSHI(editTarget); } void f_reloadtiles() { loadTiles(OFF_TILES, tiles); } int DONE = 0; static void f_quit() { DONE = 1; } /* INIT */ void game_f_init(char *exe, char *bootjor) { f_init(exe); CDEF("quit", f_quit); CDEF("seremit", f_seremit); CDEF("key-pressed", f_keyWasPressed); CDEF("key-down", f_keyIsDown); 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); CDEF("ticks", f_ticks); CDEF("ticks!", f_setticks); CDEF("text", f_text); CDEF("textc", f_textc); CDEF("rawtextc", f_rawtextc); 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); CDEF("loadscr", f_loadscr); CDEF("fuck", f_resetvideo); CDEF("boss", f_showboss); CDEF("mouseshow", f_mouseshow); CDEF("mousehide", f_mousehide); CDEF("drawfatsprite", f_drawfatsprite); CDEF("drawfatspritepixel", f_drawfatspritepixel); 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'; } } void do_repl(char *exe) { char buf[128]; f_init(exe); CDEF("quit", f_quit); CDEF("adlib", f_adlib); f_loadfile("repl.jor"); f_taskloop(); while (!DONE) { PUSHS(gets(buf)); f_runstring("REPL send"); f_taskloop(); } } int main(int argc, char *argv[]) { char *bootjor = "gameboot.jor"; if (argc > 1) { bootjor = argv[1]; } randomize(); ser_init(SER_COM2, BAUD_19200, SER_8N1); game_init(); game_f_init(argv[0], bootjor); while (!keyIsDown(K_F12) && !DONE) { kbd_debounce(); f_poll(); f_taskloop(); } return 0; }