From: sparky4 <sparky4@cock.li>
Date: Fri, 21 Apr 2017 13:46:23 +0000 (-0500)
Subject: 16_ca needs huge amounts of work and I should remember what needs to be done soon... 
X-Git-Url: http://4ch.mooo.com/gitweb/?a=commitdiff_plain;h=7b204788231612250d286ca317dd942b78da91b6;p=16.git

16_ca needs huge amounts of work and I should remember what needs to be done soon[going to port rest of code to borland c some time so we can use the core components of id engine here ][going to add 16_us.c eventually but the debug system and CA_ PM_ and MM_ usage is priority now]older zcroll renamed to xcroll][zcroll is now the pre menu game loop system with PROPER data usage with CAMMPM] added 1st scroll back
---

diff --git a/16/modex16/286@12.log b/16/modex16/286@12.log
new file mode 100755
index 00000000..34027049
--- /dev/null
+++ b/16/modex16/286@12.log
@@ -0,0 +1,4 @@
+Old non-sprite: 7.032967
+New non-sprite: 1.043956
+Old Sprite: 6.648352
+New Sprite: 1.648352
diff --git a/16/modex16/286@8.log b/16/modex16/286@8.log
new file mode 100755
index 00000000..a29ceffc
--- /dev/null
+++ b/16/modex16/286@8.log
@@ -0,0 +1,4 @@
+Old non-sprite: 10.439561
+New non-sprite: 1.373626
+Old Sprite: 9.945055
+New Sprite: 2.362637
diff --git a/16/modex16/46113319.pcx b/16/modex16/46113319.pcx
new file mode 100755
index 00000000..ce42ed87
Binary files /dev/null and b/16/modex16/46113319.pcx differ
diff --git a/16/modex16/bitmap.c b/16/modex16/bitmap.c
new file mode 100755
index 00000000..8287e57d
--- /dev/null
+++ b/16/modex16/bitmap.c
@@ -0,0 +1,162 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "bitmap.h"
+#include "modex16.h"
+
+static struct pcxHeader {
+    byte id;
+    byte version;
+    byte encoding;
+    byte bpp;
+    word xmin;
+    word ymin;
+    word xmax;
+    word ymax;
+    word hres;
+    word vres;
+    byte pal16[48];
+    byte res1;
+    word bpplane;
+    word palType;
+    word hScreenSize;
+    word vScreenSize;
+    byte padding[54];
+} head;
+
+
+static void loadPcxStage1(FILE *file, bitmap_t *result) {
+    long bufSize;
+    int index;
+    byte count, val;
+    long int pos;
+
+    /* read the header */
+    fread(&head, sizeof(char), sizeof(struct pcxHeader), file);
+
+    /* get the width and height */
+    result->width = head.xmax - head.xmin + 1;
+    result->height = head.ymax - head.ymin + 1;
+
+    /* make sure this  is 8bpp */
+    if(head.bpp != 8) {
+	printf("I only know how to handle 8bpp pcx files!\n");
+	fclose(file);
+	exit(-2);
+    }
+}
+
+
+static void loadPcxPalette(FILE *file, bitmap_t *result) {
+    byte val;
+    int index;
+
+    /* handle the palette */
+    fseek(file, -769, SEEK_END);
+    val = fgetc(file);
+    result->palette = modexNewPal();
+    if(head.version == 5 && val == 12) {
+	/* use the vga palette */
+	for(index=0; !feof(file) && index < PAL_SIZE; index++) {
+	    val = fgetc(file);
+	    result->palette[index] = val >> 2;
+	}
+    } else {
+	/* use the 16 color palette */
+	for(index=0; index<48; index++) {
+	    result->palette[index]  = head.pal16[index];
+	}
+    }
+}
+
+
+bitmap_t
+bitmapLoadPcx(char *filename) {
+    FILE *file;
+    bitmap_t result;
+    long bufSize;
+    int index;
+    byte count, val;
+
+    /* open the PCX file for reading */
+    file = fopen(filename, "rb");
+    if(!file) {
+	printf("Could not open %s for reading.\n", filename);
+	exit(-2);
+    }
+
+    /* load the first part of the pcx file */
+    loadPcxStage1(file, &result);
+
+    /* allocate the buffer */
+    bufSize = result.width * result.height;
+    result.data = malloc(bufSize);
+    if(!result.data) {
+	printf("Could not allocate memory for bitmap data.");
+	fclose(file);
+	exit(-1);
+    }
+
+    /*  read the buffer in */
+    index = 0;
+    do {
+	/* get the run length and the value */
+	count = fgetc(file);
+	if(0xC0 ==  (count & 0xC0)) { /* this is the run count */
+	    count &= 0x3f;
+	    val = fgetc(file);
+	} else {
+	    val = count;
+	    count = 1;
+	}
+
+	/* write the pixel the specified number of times */
+	for(; count && index < bufSize; count--,index++)  {
+	    result.data[index] = val;
+	}
+    } while(index < bufSize);
+
+    loadPcxPalette(file, &result);
+
+    fclose(file);
+
+    return result;
+}
+
+
+tileset_t
+bitmapLoadPcxTiles(char *filename, word twidth, word theight) {
+    tileset_t ts;
+    FILE *file;
+    bitmap_t result;
+    int i;
+
+    /* open the PCX file for reading */
+    file = fopen(filename, "rb");
+    if(!file) {
+	printf("Could not open %s for reading.\n", filename);
+	exit(-2);
+    }
+
+    /* load the first part of the pcx file */
+    loadPcxStage1(file, &result);
+
+    /* get the number of tiles and set up the result structure */
+    ts.twidth = twidth;
+    ts.theight = theight;
+    ts.ntiles = (result.width/twidth) * (result.height/theight);
+    ts.palette = result.palette;
+
+    /* allocate the pixel storage for the tiles */
+    ts.data = malloc(sizeof(byte*) * ts.ntiles);
+    ts.data[0] = malloc(sizeof(byte) * ts.ntiles * twidth * theight);
+    for(i=1; i < ts.ntiles; i++) {
+	ts.data[i] = ts.data[i-1] + twidth * theight;
+    }
+    
+    /* finish off the file */
+    loadPcxPalette(file, &result);
+
+    fclose(file);
+
+    return ts;
+}
diff --git a/16/modex16/bitmap.h b/16/modex16/bitmap.h
new file mode 100755
index 00000000..4c4af98e
--- /dev/null
+++ b/16/modex16/bitmap.h
@@ -0,0 +1,24 @@
+/*
+ * Functions and types for loading and manipulating bitmaps.
+ */
+#ifndef BITMAP_H
+#define BITMAP_H
+#include "types.h"
+typedef struct {
+    byte *data;
+    word width;
+    word height;
+    byte *palette;
+} bitmap_t;
+
+typedef struct {
+    byte **data;
+    word ntiles;   /* the number of tiles */
+    word twidth;   /* width of the tiles */
+    word theight;  /* height of the tiles */
+    byte *palette; /* palette for the tile set */
+} tileset_t;
+
+bitmap_t bitmapLoadPcx(char *filename);
+tileset_t bitmapLoadPcxTiles(char *filename, word twidth, word theight);
+#endif
diff --git a/16/modex16/chikyuu.pcx b/16/modex16/chikyuu.pcx
new file mode 100755
index 00000000..61eac4cc
Binary files /dev/null and b/16/modex16/chikyuu.pcx differ
diff --git a/16/modex16/computer.pcx b/16/modex16/computer.pcx
new file mode 100755
index 00000000..07da0a5c
Binary files /dev/null and b/16/modex16/computer.pcx differ
diff --git a/16/modex16/dos_kb.c b/16/modex16/dos_kb.c
new file mode 100755
index 00000000..dd924189
--- /dev/null
+++ b/16/modex16/dos_kb.c
@@ -0,0 +1,142 @@
+/* Thanks to Alex Russell for example code */
+/* Thanks to Gary Neal for example code */
+#include "dos_kb.h"
+
+// keyboard buffer
+static byte key[NUM_SCANCODES]; // pressed
+static byte kea[NUM_SCANCODES]; // released
+
+#ifdef __cplusplus		/* Function must be declared C style */
+extern "C" {
+#endif
+static void interrupt (far *oldkb)(void) = NULL; /* BIOS keyboard handler */
+#ifdef __cplusplus
+}
+#endif
+
+/*
+ * Comment out the following #define if you don't want the testing main()
+ * to be included.
+ */
+//#define TESTING
+#define TESTING2
+
+/*****************NEW KEYBOARD 09h ISR***********************/
+void interrupt newkb(void){
+	byte kee;
+	register char qx;
+
+	kee = inp(0x60);	/* Read the keyboard scan code */
+
+	/* Clear keyboard controller on XT machines */
+	qx = inp(0x61);	   /* Get keyboard control register */
+	qx |= 0x82;
+	outp(0x61, qx);	   /* Toggle acknowledge bit high */
+	qx &= 0x7F;
+	outp(0x61, qx);	   /* Toggle acknowledge bit low */
+
+	/* Interpret the scan code and set our flags */
+	#ifdef TESTING2
+	//printf("%d[%d]\n",kee,key[kee]);
+	printf("\0"); // bug
+	#endif
+	if(kee & 0x80)
+		key[kee & 0x7F] = 0; // a key is released
+	else
+		key[kee] = kea[kee] = 1; // a key is pressed
+
+	/* Acknowledge the interrupt to the programmable interrupt controller */
+	outp(0x20, 0x20);      /* Signal non specific end of interrupt */
+}
+
+/* ---------------------- init_keyboard() ---------------- April 17,1993 */
+/* restore the bios keyboard handler */
+/* ---------------------- deinit_keyboard() -------------- April 17,1993 */
+void setkb(int vq){
+	int i;	/* Index variable */
+	if(!vq){ // deinitiation
+		/* Abort if our function pointer has no valid address */
+		if(oldkb == NULL) return;
+		/* Set address in our function pointer in interrupt vector table */
+		_dos_setvect(9, oldkb);
+		/* Reset our function pointer to contain no valid address */
+		oldkb = NULL;
+		#ifdef TESTING
+		/* Print the key heap */
+		printf("\n");
+		for(i=0; i<NUM_SCANCODES; i++){
+			if(i==NUM_SCANCODES/2) printf("================================\n");
+			printf("%03d[%d][%d]",i+1,key[i],kea[i]);
+			if(key[i]==1)printf("====");
+			printf(",\n");
+		}
+		#endif
+	}else if(vq == 1){ // initiation
+		byte far *lock_key;
+
+		/* Abort if our function pointer has a valid address. */
+		if(oldkb != NULL) return;
+
+		/* Clear the keyboard buttons state arrays */
+		for(i = 0; i < NUM_SCANCODES; i++)
+			key[i] = kea[i] = 0;
+
+		/* save old BIOS key board handler */
+		oldkb = _dos_getvect(9);
+
+		// turn off num-lock via BIOS
+		lock_key = MK_FP(0x040, 0x017); // Pointing to the address of the bios shift state keys
+		*lock_key&=(~(16 | 32 | 64)); // toggle off the locks by changing the values of the 4th, 5th, and 6th bits of the address byte of 0040:0017
+		oldkb();	// call BIOS keyhandler to change keyboard lights
+
+		/* setup our own handler */
+		_dos_setvect(9, newkb);
+	}
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
+ * keyp							      *
+ *									 *
+ * Returns the status of the key requested.				*
+ * The status is 1 if the key is pressed or has been pressed since the     *
+ * last call to this function for that particular key.		     *
+\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+int keyp(byte c){
+	register char retVal;
+
+	/* Key value in range of keyboard keys available */
+	c &= 0x7F;
+
+	/* Get the status of the key requested */
+	retVal = key[c] | kea[c];
+
+	/* Reset the was pressed status for the requested key */
+	kea[c] = 0;
+
+	/* Return the requested key's state */
+	return retVal;
+}
+
+
+/*
+ * The library testing routines follows below.
+ */
+
+#ifdef TESTING
+
+/*
+ * Library test (program) entry point.
+ */
+
+void main(void)
+{
+	byte q;
+	setkb(1);
+	while(!keyp(1))
+	{
+		keyp(q);
+	}
+	setkb(0);
+}
+
+#endif
diff --git a/16/modex16/dos_kb.h b/16/modex16/dos_kb.h
new file mode 100755
index 00000000..ea81462a
--- /dev/null
+++ b/16/modex16/dos_kb.h
@@ -0,0 +1,23 @@
+#ifndef _DOSLIB_KB_H_
+#define _DOSLIB_KB_H_
+#include "lib\lib_com.h"
+
+/* Maximum number of scan codes on keyboard controllers */
+#define NUM_SCANCODES   128
+
+#ifdef __cplusplus      /* Functions must be declared C style */
+extern "C" {
+#endif
+void interrupt far newkb(void);
+//extern void interrupt (far *oldkb)(void);
+void setkb(int vq);
+int keyp(byte c);
+
+/* Define macro */
+//#define kepn(c) key[c & 0x7F]
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif/*_DOSLIB_KB_H_*/
diff --git a/16/modex16/ed.pcx b/16/modex16/ed.pcx
new file mode 100755
index 00000000..41e56317
Binary files /dev/null and b/16/modex16/ed.pcx differ
diff --git a/16/modex16/ed2.pcx b/16/modex16/ed2.pcx
new file mode 100755
index 00000000..b35305e3
Binary files /dev/null and b/16/modex16/ed2.pcx differ
diff --git a/16/modex16/edw.pcx b/16/modex16/edw.pcx
new file mode 100755
index 00000000..2427b5da
Binary files /dev/null and b/16/modex16/edw.pcx differ
diff --git a/16/modex16/gfx.pal b/16/modex16/gfx.pal
new file mode 100755
index 00000000..e98ae60e
Binary files /dev/null and b/16/modex16/gfx.pal differ
diff --git a/16/modex16/koishi.pcx b/16/modex16/koishi.pcx
new file mode 100755
index 00000000..76d05160
Binary files /dev/null and b/16/modex16/koishi.pcx differ
diff --git a/16/modex16/koishi^^.pcx b/16/modex16/koishi^^.pcx
new file mode 100755
index 00000000..0dbbc0da
Binary files /dev/null and b/16/modex16/koishi^^.pcx differ
diff --git a/16/modex16/koishi~.pcx b/16/modex16/koishi~.pcx
new file mode 100755
index 00000000..58a03bb4
Binary files /dev/null and b/16/modex16/koishi~.pcx differ
diff --git a/16/modex16/lib/lib_com.cpp b/16/modex16/lib/lib_com.cpp
new file mode 100755
index 00000000..19ad2ddf
--- /dev/null
+++ b/16/modex16/lib/lib_com.cpp
@@ -0,0 +1,21 @@
+//#include "src\lib\lib_com.h"
+#include "lib\lib_com.h"
+
+/* local function */
+void wait(clock_t wait);
+
+/* Function: Wait **********************************************************
+*
+*     Parameters:    wait - time in microseconds
+*
+*     Description:    pauses for a specified number of microseconds.
+*
+*/
+void wait(clock_t wait){
+	clock_t goal;
+
+	if(!wait) return;
+
+	goal = wait + clock();
+	while((goal > clock()) && !kbhit()) ;
+} /* End of wait */
\ No newline at end of file
diff --git a/16/modex16/lib/lib_com.h b/16/modex16/lib/lib_com.h
new file mode 100755
index 00000000..5a203b9d
--- /dev/null
+++ b/16/modex16/lib/lib_com.h
@@ -0,0 +1,106 @@
+#ifndef _LIBCOM_H_
+#define _LIBCOM_H_
+#include <dos.h>
+#include <stdio.h>
+#include <conio.h> // just for wait
+#include <time.h> // just for wait
+#include "types.h"
+
+/* Control codes for all keys on the keyboard */
+//here temperarly
+#define KEY_A		(0x1E)
+#define KEY_B		(0x30)
+#define KEY_C		(0x2E)
+#define KEY_D		(0x20)
+#define KEY_E		(0x12)
+#define KEY_F		(0x21)
+#define KEY_G		(0x22)
+#define KEY_H		(0x23)
+#define KEY_I		(0x17)
+#define KEY_J		(0x24)
+#define KEY_K		(0x25)
+#define KEY_L		(0x26)
+#define KEY_M		(0x32)
+#define KEY_N		(0x31)
+#define KEY_O		(0x18)
+#define KEY_P		(0x19)
+#define KEY_Q		(0x10)
+#define KEY_R		(0x13)
+#define KEY_S		(0x1F)
+#define KEY_T		(0x14)
+#define KEY_U		(0x16)
+#define KEY_V		(0x2F)
+#define KEY_W		(0x11)
+#define KEY_X		(0x2D)
+#define KEY_Y		(0x15)
+#define KEY_Z		(0x2C)
+#define KEY_1		(0x02)
+#define KEY_2		(0x03)
+#define KEY_3		(0x04)
+#define KEY_4		(0x05)
+#define KEY_5		(0x06)
+#define KEY_6		(0x07)
+#define KEY_7		(0x08)
+#define KEY_8		(0x09)
+#define KEY_9		(0x0A)
+#define KEY_0		(0x0B)
+#define KEY_DASH		(0x0C)	/* -_ */
+#define KEY_EQUAL		(0x0D)	/* =+ */
+#define KEY_LBRACKET	(0x1A)	/* [{ */
+#define KEY_RBRACKET	(0x1B)	/* ]} */
+#define KEY_SEMICOLON	(0x27)	/* ;: */
+#define KEY_RQUOTE	(0x28)	/* '" */
+#define KEY_LQUOTE	(0x29)	/* `~ */
+#define KEY_PERIOD	(0x33)	/* .> */
+#define KEY_COMMA		(0x34)	/* ,< */
+#define KEY_SLASH		(0x35)	/* /? */
+#define KEY_BACKSLASH	(0x2B)	/* \| */
+#define KEY_F1		(0x3B)
+#define KEY_F2		(0x3C)
+#define KEY_F3		(0x3D)
+#define KEY_F4		(0x3E)
+#define KEY_F5		(0x3F)
+#define KEY_F6		(0x40)
+#define KEY_F7		(0x41)
+#define KEY_F8		(0x42)
+#define KEY_F9		(0x43)
+#define KEY_F10		(0x44)
+#define KEY_ESC		(0x01)
+#define KEY_BACKSPACE   (0x0E)
+#define KEY_TAB		(0x0F)
+#define KEY_ENTER		(0x1C)
+#define KEY_CONTROL	(0x1D)
+#define KEY_LSHIFT	(0x2A)
+#define KEY_RSHIFT	(0x36)
+#define KEY_PRTSC		(0x37)
+#define KEY_ALT		(0x38)
+#define KEY_SPACE		(0x39)
+#define KEY_CAPSLOCK	(0x3A)
+#define KEY_NUMLOCK	(0x45)
+#define KEY_SCROLLLOCK	(0x46)
+#define KEY_HOME		(0x47)
+#define KEY_UP		(0x48)
+#define KEY_PGUP		(0x49)
+#define KEY_MINUS		(0x4A)
+#define KEY_LEFT		(0x4B)
+#define KEY_CENTER	(0x4C)
+#define KEY_RIGHT		(0x4D)
+#define KEY_PLUS		(0x4E)
+#define KEY_END		(0x4F)
+#define KEY_DOWN		(0x50)
+#define KEY_PGDOWN	(0x51)
+#define KEY_INS		(0x52)
+#define KEY_DEL		(0x53)
+
+#define KEY_LWIN		(0x73)
+#define KEY_RWIN		(0x74)
+#define KEY_MENU		(0x75)
+
+
+//typedef unsigned char byte;
+//typedef unsigned int word;
+//typedef unsigned short syte;
+
+void wait(clock_t wait);
+
+#endif/*_LIBCOM_H_*/
diff --git a/16/modex16/makefile b/16/modex16/makefile
new file mode 100755
index 00000000..b11f89a0
--- /dev/null
+++ b/16/modex16/makefile
@@ -0,0 +1,37 @@
+FLAGS=-0 
+all: test.exe pcxtest.exe test2.exe scroll.exe
+
+scroll.exe: scroll.obj modex16.obj dos_kb.obj bitmap.obj
+	wcl $(FLAGS) scroll.obj modex16.obj dos_kb.obj bitmap.obj
+scroll.obj: scroll.c
+	wcl $(FLAGS) -c scroll.c
+test.exe: test.obj modex16.obj bitmap.obj
+	wcl $(FLAGS) test.obj modex16.obj bitmap.obj
+	
+test2.exe: test2.obj modex16.obj bitmap.obj
+	wcl $(FLAGS) test2.obj modex16.obj bitmap.obj
+	
+pcxtest.exe: pcxtest.obj modex16.obj bitmap.obj
+	wcl $(FLAGS) pcxtest.obj modex16.obj bitmap.obj
+
+test.obj: test.c modex16.h
+	wcl $(FLAGS) -c test.c
+	
+test2.obj: test2.c modex16.h
+	wcl $(FLAGS) -c test2.c
+	
+pcxtest.obj: pcxtest.c modex16.h
+	wcl $(FLAGS) -c pcxtest.c
+
+modex16.obj: modex16.h modex16.c
+	wcl $(FLAGS) -c modex16.c
+
+dos_kb.obj: dos_kb.h dos_kb.c
+	wcl $(FLAGS) -c dos_kb.c
+
+bitmap.obj: bitmap.h bitmap.c
+	wcl $(FLAGS) -c bitmap.c
+	
+clean: 
+	del *.obj
+	del *.exe
diff --git a/16/modex16/mayu.pcx b/16/modex16/mayu.pcx
new file mode 100755
index 00000000..025e7d4a
Binary files /dev/null and b/16/modex16/mayu.pcx differ
diff --git a/16/modex16/modex16.c b/16/modex16/modex16.c
new file mode 100755
index 00000000..f01116b5
--- /dev/null
+++ b/16/modex16/modex16.c
@@ -0,0 +1,605 @@
+#include <dos.h>
+#include <string.h>
+#include <mem.h>
+#include <conio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "modex16.h"
+
+
+byte far* VGA=(byte far*) 0xA0000000; 	/* this points to video memory. */
+
+static void fadePalette(sbyte fade, sbyte start, word iter, byte *palette);
+static byte tmppal[PAL_SIZE];
+
+static void
+vgaSetMode(byte mode)
+{
+  union REGS regs;
+
+  regs.h.ah = SET_MODE;
+  regs.h.al = mode;
+  int86(VIDEO_INT, &regs, &regs);
+}
+
+
+/* -========================= Entry  Points ==========================- */
+void
+modexEnter() {
+    word i;
+    dword far*ptr=(dword far*)VGA;      /* used for faster screen clearing */
+    word CRTParms[] = {
+	0x0d06,		/* vertical total */
+	0x3e07,		/* overflow (bit 8 of vertical counts) */
+	0x4109,		/* cell height (2 to double-scan */
+	0xea10,		/* v sync start */
+	0xac11,		/* v sync end and protect cr0-cr7 */
+	0xdf12,		/* vertical displayed */
+	0x0014,		/* turn off dword mode */
+	0xe715,		/* v blank start */
+	0x0616,		/* v blank end */
+	0xe317		/* turn on byte mode */
+    };
+    int CRTParmCount = sizeof(CRTParms) / sizeof(CRTParms[0]);
+
+    /* TODO save current video mode and palette */
+    vgaSetMode(VGA_256_COLOR_MODE);
+
+    /* disable chain4 mode */
+    outpw(SC_INDEX, 0x0604);
+
+    /* synchronous reset while setting Misc Output */
+    outpw(SC_INDEX, 0x0100);
+
+    /* select 25 MHz dot clock & 60 Hz scanning rate */
+    outp(MISC_OUTPUT, 0xe3);
+
+    /* undo reset (restart sequencer) */
+    outpw(SC_INDEX, 0x0300);
+
+    /* reprogram the CRT controller */
+    outp(CRTC_INDEX, 0x11); /* VSync End reg contains register write prot */
+    outp(CRTC_DATA, 0x7f);  /* get current write protect on varios regs */
+
+    /* send the CRTParms */
+    for(i=0; i<CRTParmCount; i++) {
+	outpw(CRTC_INDEX, CRTParms[i]);
+    }
+
+    /* clear video memory */
+    outpw(SC_INDEX, 0x0f02);
+    for(i=0; i<0x8000; i++) {
+	ptr[i] = 0x0000;
+    }
+}
+
+
+void
+modexLeave() {
+    /* TODO restore original mode and palette */
+    vgaSetMode(TEXT_MODE);
+}
+
+
+page_t
+modexDefaultPage() {
+    page_t page;
+
+    /* default page values */
+    page.data = VGA;
+    page.dx = 0;
+    page.dy = 0;
+    page.width = SCREEN_WIDTH;
+    page.height = SCREEN_HEIGHT;
+
+    return page;
+}
+
+/* returns the next page in contiguous memory
+ * the next page will be the same size as p, by default
+ */
+page_t
+modexNextPage(page_t *p) {
+    page_t result;
+
+    result.data = p->data + (p->width/4)*p->height;  /* compute the offset */
+    result.dx = 0;
+    result.dy = 0;
+    result.width = p->width;
+    result.height = p->height;
+
+    return result;
+}
+
+
+void
+modexShowPage(page_t *page) {
+    word high_address;
+    word low_address;
+    word offset;
+    byte crtcOffset;
+
+    /* calculate offset */
+    offset = (word) page->data;
+    offset += page->dy * (page->width >> 2 );
+    offset += page->dx >> 2;
+
+    /* calculate crtcOffset according to virtual width */
+    crtcOffset = page->width >> 3;
+
+    high_address = HIGH_ADDRESS | (offset & 0xff00);
+    low_address  = LOW_ADDRESS  | (offset << 8);
+
+    /* wait for appropriate timing and then program CRTC */
+    while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
+    outpw(CRTC_INDEX, high_address);
+    outpw(CRTC_INDEX, low_address);
+    outp(CRTC_INDEX, 0x13);
+    outp(CRTC_DATA, crtcOffset);
+
+    /*  wait for one retrace */
+    while (!(inp(INPUT_STATUS_1) & VRETRACE)); 
+
+    /* do PEL panning here */
+    outp(AC_INDEX, 0x33);
+    outp(AC_INDEX, (page->dx & 0x03) << 1);
+}
+
+
+void
+modexPanPage(page_t *page, int dx, int dy) {
+    page->dx = dx;
+    page->dy = dy;
+}
+
+
+void
+modexSelectPlane(byte plane) {
+    outp(SC_INDEX, MAP_MASK);          /* select plane */
+    outp(SC_DATA,  plane);
+}
+
+
+void
+modexClearRegion(page_t *page, int x, int y, int w, int h, byte  color) {
+    word pageOff = (word) page->data;
+    word xoff=x/4;       /* xoffset that begins each row */
+    word scanCount=w/4;  /* number of iterations per row (excluding right clip)*/
+    word poffset = pageOff + y*(page->width/4) + xoff; /* starting offset */
+    word nextRow = page->width/4-scanCount-1;  /* loc of next row */
+    byte lclip[] = {0x0f, 0x0e, 0x0c, 0x08};  /* clips for rectangles not on 4s */
+    byte rclip[] = {0x00, 0x01, 0x03, 0x07};
+    byte left = lclip[x&0x03];
+    byte right = rclip[(x+w)&0x03];
+
+    /* handle the case which requires an extra group */
+    if((x & 0x03) && !((x+w) & 0x03)) {
+      right=0x0f;
+    }
+
+    __asm {
+		MOV AX, SCREEN_SEG      ; go to the VGA memory
+		MOV ES, AX
+		MOV DI, poffset		; go to the first pixel
+		MOV DX, SC_INDEX	; point to the map mask
+		MOV AL, MAP_MASK
+		OUT DX, AL
+		INC DX
+		MOV AL, color		; get ready to write colors
+	SCAN_START:
+		MOV CX, scanCount	; count the line
+		MOV BL, AL		; remember color
+		MOV AL, left		; do the left clip
+		OUT DX, AL		; set the left clip
+		MOV AL, BL		; restore color
+		STOSB			; write the color
+		DEC CX
+		JZ SCAN_DONE		; handle 1 group stuff
+
+		;-- write the main body of the scanline
+		MOV BL, AL	  	; remember color
+		MOV AL, 0x0f		; write to all pixels
+		OUT DX, AL
+		MOV AL, BL		; restore color
+		REP STOSB		; write the color
+	SCAN_DONE:
+		MOV BL, AL		; remeber color
+		MOV AL, right
+		OUT DX, AL		; do the right clip
+		MOV AL, BL		; restore color
+		STOSB			; write pixel
+		ADD DI, nextRow		; go to the next row
+		DEC h
+		JNZ SCAN_START
+    }
+}
+
+
+void
+modexDrawBmp(page_t *page, int x, int y, bitmap_t *bmp) {
+    /* draw the region (the entire freakin bitmap) */
+    modexDrawBmpRegion(page, x, y, 0, 0, bmp->width, bmp->height, bmp);
+}
+
+
+void
+modexDrawBmpRegion(page_t *page, int x, int y,
+                   int rx, int ry, int rw, int rh, bitmap_t *bmp) {
+    word poffset = (word) page->data  + y*(page->width/4) + x/4;
+    byte *data = bmp->data;
+    word bmpOffset = (word) data + ry * bmp->width + rx;
+    word width = rw;
+    word height = rh;
+    byte plane = 1 << ((byte) x & 0x03);
+    word scanCount = width/4 + (width%4 ? 1 :0);
+    word nextPageRow = page->width/4 - scanCount;
+    word nextBmpRow = (word) bmp->width - width;
+    word rowCounter;
+    byte planeCounter = 4;
+
+    __asm {
+		MOV AX, SCREEN_SEG      ; go to the VGA memory
+		MOV ES, AX
+
+		MOV DX, SC_INDEX	; point at the map mask register
+		MOV AL, MAP_MASK	;
+		OUT DX, AL		;
+
+	PLANE_LOOP:
+		MOV DX, SC_DATA		; select the current plane
+		MOV AL, plane		;
+		OUT DX, AL		;
+
+		;-- begin plane painting
+		MOV AX, height		; start the row counter
+		MOV rowCounter, AX	; 
+		MOV DI, poffset		; go to the first pixel
+		MOV SI, bmpOffset	; go to the bmp pixel
+	ROW_LOOP:
+		MOV CX, width		; count the columns
+	SCAN_LOOP:
+		MOVSB			; copy the pixel
+		SUB CX, 3		; we skip the next 3
+		ADD SI, 3		; skip the bmp pixels
+		LOOP SCAN_LOOP		; finish the scan
+
+		MOV AX, nextPageRow
+		ADD DI, AX		; go to the next row on screen
+		MOV AX, nextBmpRow
+		ADD SI, AX		; go to the next row on bmp
+
+		DEC rowCounter
+		JNZ ROW_LOOP		; do all the rows
+		;-- end plane painting
+
+		MOV AL, plane		; advance to the next plane
+		SHL AL, 1		;
+		AND AL, 0x0f		; mask the plane properly
+		MOV plane, AL		; store the plane
+
+		INC bmpOffset		; start bmp at the right spot
+
+		DEC planeCounter
+		JNZ PLANE_LOOP		; do all 4 planes
+    }
+}
+
+
+void
+modexDrawSprite(page_t *page, int x, int y, bitmap_t *bmp) {
+    /* draw the whole sprite */
+    modexDrawSpriteRegion(page, x, y, 0, 0, bmp->width, bmp->height, bmp);
+}
+
+void
+modexDrawSpriteRegion(page_t *page, int x, int y,
+		      int rx, int ry, int rw, int rh, bitmap_t *bmp) {
+    word poffset = (word)page->data + y*(page->width/4) + x/4;
+    byte *data = bmp->data;
+    word bmpOffset = (word) data + ry * bmp->width + rx;
+    word width = rw;
+    word height = rh;
+    byte plane = 1 << ((byte) x & 0x03);
+    word scanCount = width/4 + (width%4 ? 1 :0);
+    word nextPageRow = page->width/4 - scanCount;
+    word nextBmpRow = (word) bmp->width - width;
+    word rowCounter;
+    byte planeCounter = 4;
+
+    __asm {
+		MOV AX, SCREEN_SEG      ; go to the VGA memory
+		MOV ES, AX
+
+		MOV DX, SC_INDEX	; point at the map mask register
+		MOV AL, MAP_MASK	;
+		OUT DX, AL		;
+
+	PLANE_LOOP:
+		MOV DX, SC_DATA		; select the current plane
+		MOV AL, plane		;
+		OUT DX, AL		;
+
+		;-- begin plane painting
+		MOV AX, height		; start the row counter
+		MOV rowCounter, AX	; 
+		MOV DI, poffset		; go to the first pixel
+		MOV SI, bmpOffset	; go to the bmp pixel
+	ROW_LOOP:
+		MOV CX, width		; count the columns
+	SCAN_LOOP:
+		LODSB
+		DEC SI
+		CMP AL, 0
+		JNE DRAW_PIXEL		; draw non-zero pixels
+
+		INC DI			; skip the transparent pixel
+		ADD SI, 1
+		JMP NEXT_PIXEL
+	DRAW_PIXEL:
+		MOVSB			; copy the pixel
+	NEXT_PIXEL:
+		SUB CX, 3		; we skip the next 3
+		ADD SI, 3		; skip the bmp pixels
+		LOOP SCAN_LOOP		; finish the scan
+
+		MOV AX, nextPageRow
+		ADD DI, AX		; go to the next row on screen
+		MOV AX, nextBmpRow
+		ADD SI, AX		; go to the next row on bmp
+
+		DEC rowCounter
+		JNZ ROW_LOOP		; do all the rows
+		;-- end plane painting
+
+		MOV AL, plane		; advance to the next plane
+		SHL AL, 1		;
+		AND AL, 0x0f		; mask the plane properly
+		MOV plane, AL		; store the plane
+
+		INC bmpOffset		; start bmp at the right spot
+
+		DEC planeCounter
+		JNZ PLANE_LOOP		; do all 4 planes
+    }
+}
+
+
+/* copy a region of video memory from one page to another.
+ * It assumes that the left edge of the tile is the same on both
+ * regions and the memory areas do not overlap.
+ */
+void
+modexCopyPageRegion(page_t *dest, page_t *src,
+		    word sx, word sy,
+		    word dx, word dy,
+		    word width, word height)
+{
+    word doffset = (word)dest->data + dy*(dest->width/4) + dx/4;
+    word soffset = (word)src->data + sy*(src->width/4) + sx/4;
+    word scans   = width/4;
+    word nextSrcRow = src->width/4 - scans - 1;
+    word nextDestRow = dest->width/4 - scans - 1;
+    byte lclip[] = {0x0f, 0x0e, 0x0c, 0x08};  /* clips for rectangles not on 4s */
+    byte rclip[] = {0x0f, 0x01, 0x03, 0x07};
+    byte left = lclip[sx&0x03];
+    byte right = rclip[(sx+width)&0x03];
+
+    __asm {
+		MOV AX, SCREEN_SEG	; work in the vga space
+		MOV ES, AX		;
+		MOV DI, doffset		;
+		MOV SI, soffset		;
+
+		MOV DX, GC_INDEX	; turn off cpu bits
+		MOV AX, 0008h		;
+		OUT DX, AX
+
+		MOV AX, SC_INDEX	; point to the mask register
+		MOV DX, AX		;
+		MOV AL, MAP_MASK	;
+		OUT DX, AL		;
+		INC DX			;
+
+	ROW_START:
+		PUSH DS
+		MOV AX, ES
+		MOV DS, AX
+		MOV CX, scans		; the number of latches
+
+		MOV AL, left		; do the left column
+		OUT DX, AL		;
+		MOVSB			;
+		DEC CX			;
+
+		MOV AL, 0fh		; do the inner columns
+		OUT DX, AL
+		REP MOVSB		; copy the pixels
+
+		MOV AL, right		; do the right column
+		OUT DX, AL
+		MOVSB
+		POP DS
+
+		MOV AX, SI		; go the start of the next row
+		ADD AX, nextSrcRow	;
+		MOV SI, AX		;
+		MOV AX, DI		;
+		ADD AX, nextDestRow	;
+		MOV DI, AX		;
+
+		DEC height		; do the rest of the actions
+		JNZ ROW_START		;
+
+		MOV DX, GC_INDEX+1	; go back to CPU data
+		MOV AL, 0ffh		; none from latches
+		OUT DX, AL		;
+    }
+}
+
+
+/* fade and flash */
+void
+modexFadeOn(word fade, byte *palette) {
+    fadePalette(-fade, 64, 64/fade+1, palette);
+}
+
+
+void
+modexFadeOff(word fade, byte *palette) {
+    fadePalette(fade, 0, 64/fade+1, palette);
+}
+
+
+void
+modexFlashOn(word fade, byte *palette) {
+    fadePalette(fade, -64, 64/fade+1, palette);
+}
+
+
+void
+modexFlashOff(word fade, byte *palette) {
+    fadePalette(-fade, 0, 64/fade+1, palette);
+}
+
+
+static void
+fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {
+    word i;
+    byte dim = start;
+
+    /* handle the case where we just update */
+    if(iter == 0) {
+	modexPalUpdate(palette);
+	return;
+    }
+
+    while(iter > 0) {  /* FadeLoop */
+	for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */
+	    tmppal[i] = palette[i] - dim;
+	    if(tmppal[i] > 127) {
+		tmppal[i] = 0;
+	    } else if(tmppal[i] > 63) {
+		tmppal[i] = 63;
+	    }
+	}
+        modexPalUpdate(tmppal);
+	iter--;
+	dim += fade;
+    }
+}
+
+
+/* save and load */
+void
+modexPalSave(byte *palette) {
+    int  i;
+
+    outp(PAL_READ_REG, 0);	/* start at palette entry 0 */
+    for(i=0; i<PAL_SIZE; i++) {
+	palette[i] = inp(PAL_DATA_REG); /* read the palette data */
+    }
+}
+
+
+byte *
+modexNewPal() {
+    byte *ptr;
+    ptr = malloc(PAL_SIZE);
+
+    /* handle errors */
+    if(!ptr) {
+	printf("Could not allocate palette.\n");
+	exit(-1);
+    }
+
+    return ptr;
+}
+
+
+void
+modexLoadPalFile(byte *filename, byte **palette) {
+    FILE *file;
+    byte *ptr;
+
+    /* free the palette if it exists */
+    if(*palette) {
+	free(*palette);
+    }
+
+    /* allocate the new palette */
+    *palette = modexNewPal();
+
+    /* open the file */
+    file = fopen(filename, "rb");
+    if(!file) {
+	printf("Could not open palette file: %s\n", filename);
+	exit(-2);
+    }
+
+    /* read the file */
+    ptr = *palette;
+    while(!feof(file)) {
+	*ptr++ = fgetc(file);
+    }
+
+    fclose(file);
+}
+
+
+void
+modexSavePalFile(char *filename, byte *pal) {
+    unsigned int i;
+    FILE *file;
+
+    /* open the file for writing */
+    file = fopen(filename, "wb");
+    if(!file) {
+	printf("Could not open %s for writing\n", filename);
+	exit(-2);
+    }
+
+    /* write the data to the file */
+    fwrite(pal, 1, PAL_SIZE, file);
+    fclose(file);
+}
+
+
+/* blanking */
+void
+modexPalBlack() {
+    fadePalette(-1, 64, 1, tmppal);
+}
+
+
+void
+modexPalWhite() {
+    fadePalette(-1, -64, 1, tmppal);
+}
+
+
+/* utility */
+void
+modexPalUpdate(byte *p) {
+    int i;
+    modexWaitBorder();
+    outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */
+    for(i=0; i<PAL_SIZE/2; i++) {
+	outp(PAL_DATA_REG, p[i]);
+    }
+    modexWaitBorder();	    /* waits one retrace -- less flicker */
+    for(i=PAL_SIZE/2; i<PAL_SIZE; i++) {
+	outp(PAL_DATA_REG, p[i]);
+    }
+}
+
+
+void
+modexWaitBorder() {
+    while(inp(INPUT_STATUS_1)  & 8)  {
+	/* spin */
+    }
+
+    while(!(inp(INPUT_STATUS_1)  & 8))  {
+	/* spin */
+    }
+}
diff --git a/16/modex16/modex16.h b/16/modex16/modex16.h
new file mode 100755
index 00000000..77573105
--- /dev/null
+++ b/16/modex16/modex16.h
@@ -0,0 +1,86 @@
+/*
+ * Functions for handling modex and doing other basic graphics stuff.
+ */
+#ifndef MODEX16_H
+#define MODEX16_H
+#include <conio.h>
+#include "types.h"
+#include "bitmap.h"
+
+/* -========================== Types & Macros ==========================- */
+#define PAGE_OFFSET(x,y) (((y)<<6)+((y)<<4)+((x)>>2))
+#define PLANE(x) (1<< (x&3))
+#define SELECT_ALL_PLANES() outpw(0x03c4, 0xff02)
+
+typedef struct {
+    byte far* data;	/* the data for the page */
+    word dx;		/* col we are viewing on the virtual screen */
+    word dy;		/* row we are viewing on the virtual screen */
+    word width;		/* virtual width of the page */
+    word height;	/* virtual height of the page */
+} page_t;
+
+/* -============================ Functions =============================- */
+/* mode switching, page, and plane functions */
+void modexEnter();
+void modexLeave();
+page_t modexDefaultPage();
+page_t modexNextPage(page_t *p);
+void modexShowPage(page_t *page);
+void modexPanPage(page_t *page, int dx, int dy);
+void modexSelectPlane(byte plane);
+void modexClearRegion(page_t *page, int x, int y, int w, int h, byte color);
+void modexDrawBmp(page_t *page, int x, int y, bitmap_t *bmp);
+void modexDrawBmpRegion(page_t *page, int x, int y, int rx, int ry, int rw, int rh, bitmap_t *bmp);
+void modexDrawSprite(page_t *page, int x, int y, bitmap_t *bmp);
+void modexDrawSpriteRegion(page_t *page, int x, int y, int rx, int ry, int rw, int rh, bitmap_t *bmp);
+
+/* Palette fade and flash effects */
+void modexFadeOn(word fade, byte *palette);
+void modexFadeOff(word fade, byte *palette);
+void modexFlashOn(word fade, byte *palette);
+void modexFlashOff(word fade, byte *palette);
+
+/* palette loading and saving */
+void modexPalSave(byte *palette);
+byte *modexNewPal();
+void modexLoadPalFile(char *filename, byte **palette);
+void modexSavePalFile(char *filename, byte *palette);
+
+/* fixed palette functions */
+void modexPalBlack();
+void modexPalWhite();
+
+/* utility functions */
+void modexPalUpdate(byte *p);
+void modexWaitBorder();
+
+/* -======================= Constants & Vars ==========================- */
+extern byte far*  VGA;  /* The VGA Memory */
+#define SCREEN_SEG		0xa000
+#define VIDEO_INT		0x10
+#define SET_MODE		0x00
+#define VGA_256_COLOR_MODE 	0x13
+#define TEXT_MODE		0x03
+#define SCREEN_WIDTH		320
+#define SCREEN_HEIGHT		240
+#define PAGE_SIZE		(word)(SCREEN_WIDTH/4 * SCREEN_HEIGHT)
+
+#define AC_INDEX		0x03c0
+#define SC_INDEX		0x03c4
+#define SC_DATA			0x03c5
+#define CRTC_INDEX		0x03d4
+#define CRTC_DATA		0x03d5
+#define GC_INDEX		0x03ce
+#define MISC_OUTPUT		0x03c2
+#define HIGH_ADDRESS 		0x0C
+#define LOW_ADDRESS		0x0D
+#define VRETRACE		0x08
+#define INPUT_STATUS_1		0x03da
+#define DISPLAY_ENABLE		0x01
+#define MAP_MASK		0x02
+#define PAL_READ_REG            0x03C7   /* Color register, read address */
+#define PAL_WRITE_REG           0x03C8   /* Color register, write address */
+#define PAL_DATA_REG            0x03C9   /* Color register, data port */
+#define PAL_SIZE                (256 * 3)
+#endif
diff --git a/16/modex16/palettec.c b/16/modex16/palettec.c
new file mode 100755
index 00000000..340a9303
--- /dev/null
+++ b/16/modex16/palettec.c
@@ -0,0 +1,16 @@
+#include "modex16.h"
+
+void
+main() {
+    byte *pal;
+
+    modexEnter();
+
+    pal = modexNewPal();
+    modexPalSave(pal);
+
+    modexSavePalFile("gfx.pal", pal);
+
+    modexLeave();
+
+}
diff --git a/16/modex16/pcxtest.c b/16/modex16/pcxtest.c
new file mode 100755
index 00000000..7373e885
--- /dev/null
+++ b/16/modex16/pcxtest.c
@@ -0,0 +1,79 @@
+#include <stdio.h>
+#include "modex16.h"
+#include "bitmap.h"
+
+word far* clock= (word far*) 0x046C; /* 18.2hz clock */
+
+void
+oldDrawBmp(byte far* page, int x, int y, bitmap_t *bmp, byte sprite) {
+    byte plane;
+    word px, py;
+    word offset;
+
+    /* TODO Make this fast.  It's SLOOOOOOW */
+    for(plane=0; plane < 4; plane++) {
+	modexSelectPlane(PLANE(plane+x));
+	for(px = plane; px < bmp->width; px+=4) {
+	    offset=px;
+	    for(py=0; py<bmp->height; py++) {
+		if(!sprite || bmp->data[offset])
+		  page[PAGE_OFFSET(x+px, y+py)] = bmp->data[offset];
+		offset+=bmp->width;
+	    }
+	}
+    }
+}
+
+void main() {
+    bitmap_t bmp;
+    int i;
+    page_t page;
+    word start;
+    float t1, t2;
+
+    page=modexDefaultPage();
+
+    bmp = bitmapLoadPcx("46113319.pcx");
+    modexEnter();
+
+    /* fix up the palette and everything */
+    modexPalUpdate(bmp.palette);
+
+    /* clear and draw one sprite and one bitmap */
+    modexClearRegion(&page, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 1);
+
+    /* non sprite comparison */
+    start = *clock;
+    for(i=0; i<100 ;i++) {
+      oldDrawBmp(VGA, 20, 20, &bmp, 0);
+    }
+
+    start = *clock;
+    for(i=0; i<100 ;i++) {
+      modexDrawBmp(&page, 20, 20, &bmp);
+    }
+    t1 = (*clock-start) /18.2;
+
+    start = *clock;
+    for(i=0; i<100; i++) {
+    	modexCopyPageRegion(&page, &page, 20, 20, 128, 20, 64, 64);
+    }
+    t2 = (*clock-start)/18.2;
+
+
+    start = *clock;
+    for(i=0; i<100 ;i++) {
+      oldDrawBmp(VGA, 20, 20, &bmp, 1);
+    }
+
+
+    start = *clock;
+    for(i=0; i<100 ;i++) {
+      modexDrawSprite(&page, 20, 20, &bmp);
+    }
+    modexLeave();
+
+    printf("CPU to VGA: %f\n", t1);
+    printf("VGA to VGA: %f\n", t2);
+    return;
+}
diff --git a/16/modex16/pcxtest.exe b/16/modex16/pcxtest.exe
new file mode 100755
index 00000000..de765ece
Binary files /dev/null and b/16/modex16/pcxtest.exe differ
diff --git a/16/modex16/q.pcx b/16/modex16/q.pcx
new file mode 100755
index 00000000..a51d634c
Binary files /dev/null and b/16/modex16/q.pcx differ
diff --git a/16/modex16/rarity.pcx b/16/modex16/rarity.pcx
new file mode 100755
index 00000000..8e7e32fc
Binary files /dev/null and b/16/modex16/rarity.pcx differ
diff --git a/16/modex16/scroll.c b/16/modex16/scroll.c
new file mode 100755
index 00000000..8a960eee
--- /dev/null
+++ b/16/modex16/scroll.c
@@ -0,0 +1,363 @@
+#include "modex16.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "dos_kb.h"
+
+//word far *clock= (word far*) 0x046C; /* 18.2hz clock */
+
+typedef struct {
+	bitmap_t *data;
+	word tileHeight;
+	word tileWidth;
+	unsigned int rows;
+	unsigned int cols;
+	unsigned int tilex,tiley; // tile position on the map
+} tiles_t;
+
+
+typedef struct {
+	byte	*data;
+	tiles_t *tiles;
+	int width;
+	int height;
+} map_t;
+
+
+typedef struct {
+	map_t *map;
+	page_t *page;
+	int tx; //???? appears to be the tile position on the viewable screen map
+	int ty; //???? appears to be the tile position on the viewable screen map
+	word dxThresh; //????
+	word dyThresh; //????
+} map_view_t;
+
+struct {
+	int tx; //player position on the viewable map
+	int ty; //player position on the viewable map
+} player;
+
+
+map_t allocMap(int w, int h);
+void initMap(map_t *map);
+void mapScrollRight(map_view_t *mv, byte offset);
+void mapScrollLeft(map_view_t *mv, byte offest);
+void mapScrollUp(map_view_t *mv, byte offset);
+void mapScrollDown(map_view_t *mv, byte offset);
+void mapGoTo(map_view_t *mv, int tx, int ty);
+void mapDrawTile(tiles_t *t, word i, page_t *page, word x, word y);
+void mapDrawRow(map_view_t *mv, int tx, int ty, word y);
+void mapDrawCol(map_view_t *mv, int tx, int ty, word x);
+
+#define TILEWH 16
+#define QUADWH (TILEWH/4)
+//#define SWAP(a, b) tmp=a; a=b; b=tmp;
+void main() {
+//	int show1=1;
+	int tx, ty;
+	int x, y;
+	//int ch=0x0;
+//	byte ch;
+	int q=0;
+	page_t screen;//,screen2;
+	map_t map;
+	map_view_t mv;//, mv2;
+	map_view_t *draw;//, *show, *tmp;
+	byte *ptr;
+
+	//default player position on the viewable map
+	player.tx = 10;
+	player.ty = 8;
+
+	setkb(1);
+	/* create the map */
+	map = allocMap(160,120); //20x15 is the resolution of the screen you can make maps smaller than 20x15 but the null space needs to be drawn properly
+	initMap(&map);
+	mv.map = &map;
+//	mv2.map = &map;
+
+	/* draw the tiles */
+	ptr = map.data;
+	modexEnter();
+	screen = modexDefaultPage();
+	screen.width += (TILEWH*2);
+	mv.page = &screen;
+	mapGoTo(&mv, 16, 16);
+//	screen2=modexNextPage(mv.page);
+//	mv2.page = &screen2;
+//	mapGoTo(&mv2, 16, 16);
+//	modexShowPage(mv.page);
+
+	/* set up paging */
+//	show = &mv;
+//	draw = &mv2;
+	draw = &mv;
+
+	//TODO: set player position data here according to the viewable map screen thingy
+
+	while(!keyp(1)) {
+	//TODO: top left corner & bottem right corner of map veiw be set as map edge trigger since maps are actually square
+	//to stop scrolling and have the player position data move to the edge of the screen with respect to the direction
+	//when player.tx or player.ty == 0 or player.tx == 20 or player.ty == 15 then stop because that is edge of map and you do not want to walk of the map
+	if(keyp(77)){
+//		for(q=0; q<TILEWH; q++) {
+		mapScrollRight(draw, 1);
+//		modexShowPage(draw->page);
+//		mapScrollRight(draw, 1);
+//		SWAP(draw, show);
+//		}
+	}
+
+	if(keyp(75)){
+//		for(q=0; q<TILEWH; q++) {
+ 		mapScrollLeft(draw, 1);
+//		modexShowPage(draw->page);
+// 		mapScrollLeft(show, 1);
+//		SWAP(draw, show);
+//		}
+	}
+
+	if(keyp(80)){
+//		for(q=0; q<TILEWH; q++) {
+		mapScrollDown(draw, 1);
+//		modexShowPage(draw->page);
+//		mapScrollDown(show, 1);
+//		SWAP(draw, show);
+//		}
+	}
+
+	if(keyp(72)){
+//		for(q=0; q<TILEWH; q++) {
+		mapScrollUp(draw, 1);
+//		modexShowPage(draw->page);
+//		mapScrollUp(show, 1);
+//		SWAP(draw, show);
+//		}
+	}
+
+	//keyp(ch);
+	modexShowPage(draw->page);
+
+	}
+
+	modexLeave();
+	setkb(0);
+}
+
+
+map_t
+allocMap(int w, int h) {
+	map_t result;
+
+	result.width =w;
+	result.height=h;
+	result.data = malloc(sizeof(byte) * w * h);
+
+	return result;
+}
+
+
+void
+initMap(map_t *map) {
+	/* just a place holder to fill out an alternating pattern */
+	int x, y;
+	int i;
+	int tile = 1;
+	map->tiles = malloc(sizeof(tiles_t));
+
+	/* create the tile set */
+	map->tiles->data = malloc(sizeof(bitmap_t));
+	map->tiles->data->width = (TILEWH*2);
+	map->tiles->data->height= TILEWH;
+	map->tiles->data->data = malloc((TILEWH*2)*TILEWH);
+	map->tiles->tileHeight = TILEWH;
+	map->tiles->tileWidth =TILEWH;
+	map->tiles->rows = 1;
+	map->tiles->cols = 2;
+
+	i=0;
+	for(y=0; y<TILEWH; y++) {
+	for(x=0; x<(TILEWH*2); x++) {
+		if(x<TILEWH)
+		  map->tiles->data->data[i] = 0x24;
+		else
+		  map->tiles->data->data[i] = 0x34;
+		i++;
+	}
+	}
+
+	i=0;
+	for(y=0; y<map->height; y++) {
+		for(x=0; x<map->width; x++) {
+			map->data[i] = tile;
+			tile = tile ? 0 : 1;
+			i++;
+		}
+		tile = tile ? 0 : 1;
+	}
+}
+
+
+void
+mapScrollRight(map_view_t *mv, byte offset) {
+	word x, y;  /* coordinate for drawing */
+
+	/* increment the pixel position and update the page */
+	mv->page->dx += offset;
+
+	/* check to see if this changes the tile */
+	if(mv->page->dx >= mv->dxThresh ) {
+	/* go forward one tile */
+	mv->tx++;
+	/* Snap the origin forward */
+	mv->page->data += 4;
+	mv->page->dx = mv->map->tiles->tileWidth;
+
+
+	/* draw the next column */
+	x= SCREEN_WIDTH + mv->map->tiles->tileWidth;
+		mapDrawCol(mv, mv->tx + 20 , mv->ty-1, x);
+	}
+}
+
+
+void
+mapScrollLeft(map_view_t *mv, byte offset) {
+	word x, y;  /* coordinate for drawing */
+
+	/* increment the pixel position and update the page */
+	mv->page->dx -= offset;
+
+	/* check to see if this changes the tile */
+	if(mv->page->dx == 0) {
+	/* go backward one tile */
+	mv->tx--;
+		
+	/* Snap the origin backward */
+	mv->page->data -= 4;
+	mv->page->dx = mv->map->tiles->tileWidth;
+
+	/* draw the next column */
+		mapDrawCol(mv, mv->tx-1, mv->ty-1, 0);
+	}
+}
+
+
+void
+mapScrollUp(map_view_t *mv, byte offset) {
+	word x, y;  /* coordinate for drawing */
+
+	/* increment the pixel position and update the page */
+	mv->page->dy -= offset;
+
+	/* check to see if this changes the tile */
+	if(mv->page->dy == 0 ) {
+	/* go down one tile */
+	mv->ty--;
+	/* Snap the origin downward */
+	mv->page->data -= mv->page->width*4;
+	mv->page->dy = mv->map->tiles->tileHeight;
+
+
+	/* draw the next row */
+	y= 0;
+		mapDrawRow(mv, mv->tx-1 , mv->ty-1, y);
+	}
+}
+
+
+void
+mapScrollDown(map_view_t *mv, byte offset) {
+	word x, y;  /* coordinate for drawing */
+
+	/* increment the pixel position and update the page */
+	mv->page->dy += offset;
+
+	/* check to see if this changes the tile */
+	if(mv->page->dy >= mv->dyThresh ) {
+	/* go down one tile */
+	mv->ty++;
+	/* Snap the origin downward */
+	mv->page->data += mv->page->width*4;
+	mv->page->dy = mv->map->tiles->tileHeight;
+
+
+	/* draw the next row */
+	y= SCREEN_HEIGHT + mv->map->tiles->tileHeight;
+		mapDrawRow(mv, mv->tx-1 , mv->ty+15, y);
+	}
+
+}
+
+
+void
+mapGoTo(map_view_t *mv, int tx, int ty) {
+	int px, py;
+	unsigned int i;
+
+	/* set up the coordinates */
+	mv->tx = tx;
+	mv->ty = ty;
+	mv->page->dx = mv->map->tiles->tileWidth;
+	mv->page->dy = mv->map->tiles->tileHeight;
+
+	/* set up the thresholds */
+	mv->dxThresh = mv->map->tiles->tileWidth * 2;
+	mv->dyThresh = mv->map->tiles->tileHeight * 2;
+
+	/* draw the tiles */
+	modexClearRegion(mv->page, 0, 0, mv->page->width, mv->page->height, 0);
+	py=0;
+	i=mv->ty * mv->map->width + mv->tx;
+	for(ty=mv->ty-1; py < SCREEN_HEIGHT+mv->dyThresh && ty < mv->map->height; ty++, py+=mv->map->tiles->tileHeight) {
+		mapDrawRow(mv, tx-1, ty, py);
+	i+=mv->map->width - tx;
+	}
+}
+
+
+void
+mapDrawTile(tiles_t *t, word i, page_t *page, word x, word y) {
+	word rx;
+	word ry;
+	rx = (i % t->cols) * t->tileWidth;
+	ry = (i / t->cols) * t->tileHeight;
+	modexDrawBmpRegion(page, x, y, rx, ry, t->tileWidth, t->tileHeight, t->data);
+}
+
+
+void 
+mapDrawRow(map_view_t *mv, int tx, int ty, word y) {
+	word x;
+	int i;
+
+	/* the position within the map array */
+	i=ty * mv->map->width + tx;
+	for(x=0; x<SCREEN_WIDTH+mv->dxThresh && tx < mv->map->width; x+=mv->map->tiles->tileWidth, tx++) {
+	if(i>=0) {
+		/* we are in the map, so copy! */
+		mapDrawTile(mv->map->tiles, mv->map->data[i], mv->page, x, y);
+	}
+	i++; /* next! */
+	}
+}
+
+
+void 
+mapDrawCol(map_view_t *mv, int tx, int ty, word x) {
+	int y;
+	int i;
+
+	/* location in the map array */
+	i=ty * mv->map->width + tx;
+
+	/* We'll copy all of the columns in the screen, 
+	   i + 1 row above and one below */
+	for(y=0; y<SCREEN_HEIGHT+mv->dyThresh && ty < mv->map->height; y+=mv->map->tiles->tileHeight, ty++) {
+	if(i>=0) {
+		/* we are in the map, so copy away! */
+		mapDrawTile(mv->map->tiles, mv->map->data[i], mv->page, x, y);
+	}
+	i += mv->map->width;
+	}
+}
diff --git a/16/modex16/scroll.exe b/16/modex16/scroll.exe
new file mode 100755
index 00000000..23762520
Binary files /dev/null and b/16/modex16/scroll.exe differ
diff --git a/16/modex16/test.c b/16/modex16/test.c
new file mode 100755
index 00000000..c5b9d7dc
--- /dev/null
+++ b/16/modex16/test.c
@@ -0,0 +1,75 @@
+#include "modex16.h"
+#include <stdio.h>
+
+word far* clock= (word far*) 0x046C; /* 18.2hz clock */
+
+void main() {
+    int i, j;
+    word start, end;
+    page_t page, page2;
+    byte *pal, *pal2=NULL;
+
+    /* load our palette */
+    modexLoadPalFile("gfx.pal", &pal2);
+
+    /* save the palette */
+    pal  = modexNewPal();
+    modexPalSave(pal);
+    modexFadeOff(1, pal);
+    modexPalBlack();
+
+    modexEnter();
+    modexPalBlack();
+
+    /* set up the page, but with 16 pixels on all borders in offscreen mem */
+    page=modexDefaultPage();
+    page2 = modexNextPage(&page);
+    page.width += 32;
+    page.height += 32;
+
+
+    /* fill the page with one color, but with a black border */
+    modexShowPage(&page2);
+    modexClearRegion(&page, 16, 16, SCREEN_WIDTH, SCREEN_HEIGHT, 128);
+    modexClearRegion(&page, 32, 32, SCREEN_WIDTH-32, SCREEN_HEIGHT-32, 42);
+    modexClearRegion(&page, 48, 48, SCREEN_WIDTH-64, SCREEN_HEIGHT-64, 128);
+    modexShowPage(&page);
+
+    /* fade in */
+    modexFadeOn(1, pal2);
+
+
+    start = *clock;
+    for(i=0; i<5; i++) {
+	/* go right */
+	for(j=0; j<32; j++) {
+	    page.dx++;
+	    modexShowPage(&page);
+	}
+	/* go left */
+	for(j=0; j<32; j++) {
+	    page.dx--;
+	    modexShowPage(&page);
+	}
+	/* go up */
+	for(j=0; j<32; j++) {
+	    page.dy++;
+	    modexShowPage(&page);
+	}
+
+	/* go down */
+	for(j=0; j<32; j++) {
+	    page.dy--;
+	    modexShowPage(&page);
+	}
+    }
+
+    end = *clock;
+
+    /* fade back to text mode */
+    modexFadeOff(1, pal2);
+    modexPalBlack();
+    modexLeave();
+    modexPalBlack();
+    modexFadeOn(1, pal);
+}
diff --git a/16/modex16/test.exe b/16/modex16/test.exe
new file mode 100755
index 00000000..99404b1a
Binary files /dev/null and b/16/modex16/test.exe differ
diff --git a/16/modex16/test.txt b/16/modex16/test.txt
new file mode 100755
index 00000000..05adc9ec
--- /dev/null
+++ b/16/modex16/test.txt
@@ -0,0 +1,258 @@
+64 x 64 Pixels
+
+0 0 0 
+20 0 0 
+0 20 0 
+20 20 0 
+0 0 20 
+20 0 20 
+0 20 20 
+30 30 30 
+30 37 30 
+29 32 3c 
+3f 3f 33 
+3f 3f 26 
+3f 3f 19 
+3f 3f c 
+3f 33 3f 
+3f 33 33 
+3f 33 26 
+3f 33 19 
+3f 33 c 
+3f 33 0 
+3f 26 3f 
+3f 26 33 
+3f 26 26 
+3f 26 19 
+3f 26 c 
+3f 26 0 
+3f 19 3f 
+3f 19 33 
+3f 19 26 
+3f 19 19 
+3f 19 c 
+3f 19 0 
+3f c 3f 
+3f c 33 
+3f c 26 
+3f c 19 
+3f c c 
+3f c 0 
+3f 0 33 
+3f 0 26 
+3f 0 19 
+3f 0 c 
+33 3f 3f 
+33 3f 33 
+33 3f 26 
+33 3f 19 
+33 3f c 
+33 3f 0 
+33 33 3f 
+33 33 33 
+33 33 26 
+33 33 19 
+33 33 c 
+33 33 0 
+33 26 3f 
+33 26 33 
+33 26 26 
+33 26 19 
+33 26 c 
+33 26 0 
+33 19 3f 
+33 19 33 
+33 19 26 
+33 19 19 
+33 19 c 
+33 19 0 
+33 c 3f 
+33 c 33 
+33 c 26 
+33 c 19 
+33 c c 
+33 c 0 
+33 0 3f 
+33 0 33 
+33 0 26 
+33 0 19 
+33 0 c 
+33 0 0 
+26 3f 3f 
+26 3f 33 
+26 3f 26 
+26 3f 19 
+26 3f c 
+26 3f 0 
+26 33 3f 
+26 33 33 
+26 33 26 
+26 33 19 
+26 33 c 
+26 33 0 
+26 26 3f 
+26 26 33 
+26 26 26 
+26 26 19 
+26 26 c 
+26 26 0 
+26 19 3f 
+26 19 33 
+26 19 26 
+26 19 19 
+26 19 c 
+26 19 0 
+26 c 3f 
+26 c 33 
+26 c 26 
+26 c 19 
+26 c c 
+26 c 0 
+26 0 3f 
+26 0 33 
+26 0 26 
+26 0 19 
+26 0 c 
+26 0 0 
+19 3f 3f 
+19 3f 33 
+19 3f 26 
+19 3f 19 
+19 3f c 
+19 3f 0 
+19 33 3f 
+19 33 33 
+19 33 26 
+19 33 19 
+19 33 c 
+19 33 0 
+19 26 3f 
+19 26 33 
+19 26 26 
+19 26 19 
+19 26 c 
+19 26 0 
+19 19 3f 
+19 19 33 
+19 19 26 
+19 19 19 
+19 19 c 
+19 19 0 
+19 c 3f 
+19 c 33 
+19 c 26 
+19 c 19 
+19 c c 
+19 c 0 
+19 0 3f 
+19 0 33 
+19 0 26 
+19 0 19 
+19 0 c 
+19 0 0 
+c 3f 3f 
+c 3f 33 
+c 3f 26 
+c 3f 19 
+c 3f c 
+c 3f 0 
+c 33 3f 
+c 33 33 
+c 33 26 
+c 33 19 
+c 33 c 
+c 33 0 
+c 26 3f 
+c 26 33 
+c 26 26 
+c 26 19 
+c 26 c 
+c 26 0 
+c 19 3f 
+c 19 33 
+c 19 26 
+c 19 19 
+c 19 c 
+c 19 0 
+c c 3f 
+c c 33 
+c c 26 
+c c 19 
+c c c 
+c c 0 
+c 0 3f 
+c 0 33 
+c 0 26 
+c 0 19 
+c 0 c 
+c 0 0 
+0 3f 33 
+0 3f 26 
+0 3f 19 
+0 3f c 
+0 33 3f 
+0 33 33 
+0 33 26 
+0 33 19 
+0 33 c 
+0 33 0 
+0 26 3f 
+0 26 33 
+0 26 26 
+0 26 19 
+0 26 c 
+0 26 0 
+0 19 3f 
+0 19 33 
+0 19 26 
+0 19 19 
+0 19 c 
+0 19 0 
+0 c 3f 
+0 c 33 
+0 c 26 
+0 c 19 
+0 c c 
+0 c 0 
+0 0 33 
+0 0 26 
+0 0 19 
+0 0 c 
+20 3f 3f 
+10 20 20 
+20 3f 0 
+10 10 0 
+3f 3f 20 
+3f 20 0 
+3f 20 20 
+20 10 0 
+20 0 3f 
+20 0 10 
+10 20 3f 
+0 10 20 
+0 0 0 
+0 0 0 
+0 0 0 
+0 0 0 
+0 0 0 
+0 0 0 
+0 0 0 
+0 0 0 
+0 0 0 
+0 0 0 
+0 0 0 
+0 0 0 
+0 0 0 
+0 0 0 
+0 0 0 
+0 0 0 
+3f 3e 3c 
+28 28 29 
+20 20 20 
+3f 0 0 
+0 3f 0 
+3f 3f 0 
+0 0 3f 
+3f 0 3f 
+0 3f 3f 
+3f 3f 3f 
\ No newline at end of file
diff --git a/16/modex16/test2.c b/16/modex16/test2.c
new file mode 100755
index 00000000..9118279f
--- /dev/null
+++ b/16/modex16/test2.c
@@ -0,0 +1,19 @@
+#include "modex16.h"
+
+word far* clock= (word far*) 0x046C; /* 18.2hz clock */
+
+void main() {
+    int i;
+    word start;
+    page_t page;
+
+    page=modexDefaultPage();
+
+    modexEnter();
+    start = *clock;
+    for(i=0; i<500; i++) {
+	modexShowPage(&page);
+    }
+    modexLeave();
+
+}
diff --git a/16/modex16/test2.exe b/16/modex16/test2.exe
new file mode 100755
index 00000000..2b870eff
Binary files /dev/null and b/16/modex16/test2.exe differ
diff --git a/16/modex16/types.h b/16/modex16/types.h
new file mode 100755
index 00000000..039653f2
--- /dev/null
+++ b/16/modex16/types.h
@@ -0,0 +1,11 @@
+/*
+ * Just some handy typedefs that make it easier to think about the low
+ * level code
+ */
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned long  dword;
+typedef signed char sbyte;
+typedef signed short sword;
+typedef signed long sdword;
diff --git a/16/modex16/w.pcx b/16/modex16/w.pcx
new file mode 100755
index 00000000..ad808796
Binary files /dev/null and b/16/modex16/w.pcx differ
diff --git a/src/0croll.c b/src/0croll.c
index 3a91e173..4ea630f8 100755
--- a/src/0croll.c
+++ b/src/0croll.c
@@ -1,4 +1,4 @@
-//from https://github.com/sparky4/16/commit/a19d7592507e5f7aa91f4a6b6611e021bd1a3e8d
+//from https://github.com/sparky4/16/commit/7872dbf5d0240f01177588bd7966c3e042ced554
 #include "16/src/lib/omodex16.h"
 #include "16/src/lib/bitmap.h"
 #include <stdio.h>